Add date-range filters to map

This commit is contained in:
Paul Bienkowski 2022-07-22 13:29:51 +02:00
parent 7716da8844
commit e0cb36565a
4 changed files with 157 additions and 22 deletions

View file

@ -1,5 +1,7 @@
from gzip import decompress
from sqlite3 import connect
import dateutil.parser
from sanic.exceptions import Forbidden
from sanic.response import raw
@ -46,6 +48,10 @@ async def tiles(req, zoom: int, x: int, y: str):
raise Forbidden()
user_id = req.ctx.user.id
parse_date = lambda s: dateutil.parser.parse(s)
start = req.ctx.get_single_arg("start", default=None, convert=parse_date)
end = req.ctx.get_single_arg("end", default=None, convert=parse_date)
tile = await req.ctx.db.scalar(
text(
f"select data from getmvt(:zoom, :x, :y, :user_id, :min_time, :max_time) as b(data, key);"
@ -54,8 +60,8 @@ async def tiles(req, zoom: int, x: int, y: str):
x=int(x),
y=int(y),
user_id=user_id,
min_time=None,
max_time=None,
min_time=start,
max_time=end,
)
)

View file

@ -32,6 +32,12 @@ const ROAD_ATTRIBUTE_OPTIONS = [
"zone",
];
const DATE_FILTER_MODES = [
{ value: "none", key: "none", text: "All time" },
{ value: "range", key: "range", text: "Start and end range" },
{ value: "threshold", key: "threshold", text: "Before/after comparison" },
];
type User = Object;
function LayerSidebar({
@ -48,7 +54,13 @@ function LayerSidebar({
baseMap: { style },
obsRoads: { show: showRoads, showUntagged, attribute, maxCount },
obsEvents: { show: showEvents },
filters: { currentUser: filtersCurrentUser },
filters: {
currentUser: filtersCurrentUser,
dateMode,
startDate,
endDate,
thresholdAfter,
},
} = mapConfig;
return (
@ -209,24 +221,113 @@ function LayerSidebar({
</>
)}
<Divider />
<List.Item>
<Header as="h4" style={{ marginBottom: 8 }}>
Filter
</Header>
{login && (
<Checkbox
toggle
size="small"
id="filters.currentUser"
checked={filtersCurrentUser}
onChange={() =>
setMapConfigFlag("filters.currentUser", !filtersCurrentUser)
}
label="Show only my own data"
/>
)}
{!login && <div>No filters available without login.</div>}
<Header as="h4">Filters</Header>
</List.Item>
{login && (
<>
<List.Item>
<Header as="h5">User data</Header>
</List.Item>
<List.Item>
<Checkbox
toggle
size="small"
id="filters.currentUser"
checked={filtersCurrentUser}
onChange={() =>
setMapConfigFlag("filters.currentUser", !filtersCurrentUser)
}
label="Show only my own data"
/>
</List.Item>
<List.Item>
<Header as="h5">Date range</Header>
</List.Item>
<List.Item>
<Select
id="filters.dateMode"
options={DATE_FILTER_MODES}
value={dateMode ?? "none"}
onChange={(_e, { value }) =>
setMapConfigFlag("filters.dateMode", value)
}
/>
</List.Item>
{dateMode == "range" && (
<List.Item>
<Input
type="date"
size="small"
id="filters.startDate"
onChange={(_e, { value }) =>
setMapConfigFlag("filters.startDate", value)
}
value={startDate ?? null}
label="Start"
/>
</List.Item>
)}
{dateMode == "range" && (
<List.Item>
<Input
type="date"
size="small"
id="filters.endDate"
onChange={(_e, { value }) =>
setMapConfigFlag("filters.endDate", value)
}
value={endDate ?? null}
label="End"
/>
</List.Item>
)}
{dateMode == "threshold" && (
<List.Item>
<Input
type="date"
size="small"
id="filters.startDate"
value={startDate ?? null}
onChange={(_e, { value }) =>
setMapConfigFlag("filters.startDate", value)
}
label="Threshold"
/>
</List.Item>
)}
{dateMode == "threshold" && (
<List.Item>
<span>
Before{" "}
<Checkbox
toggle
size="small"
checked={thresholdAfter ?? false}
onChange={() =>
setMapConfigFlag(
"filters.thresholdAfter",
!thresholdAfter
)
}
id="filters.thresholdAfter"
/>{" "}
After
</span>
</List.Item>
)}
</>
)}
{!login && <List.Item>No filters available without login.</List.Item>}
</List>
</div>
);

View file

@ -160,9 +160,29 @@ function MapPage({ login }) {
}
const tiles = obsMapSource?.tiles?.map(
(tileUrl: string) =>
tileUrl +
(login && mapConfig.filters.currentUser ? `?user=${login.username}` : "")
(tileUrl: string) => {
const query = new URLSearchParams()
if (login) {
if (mapConfig.filters.currentUser) {
query.append('user', login.username)
}
if (mapConfig.filters.dateMode === "range") {
if (mapConfig.filters.startDate) {
query.append('start', mapConfig.filters.startDate)
}
if (mapConfig.filters.endDate) {
query.append('end', mapConfig.filters.endDate)
}
} else if (mapConfig.filters.dateMode === "threshold") {
if (mapConfig.filters.startDate) {
query.append(mapConfig.filters.thresholdAfter ? 'start' : 'end', mapConfig.filters.startDate)
}
}
}
const queryString = String(query)
return tileUrl + (queryString ? '?' : '') + queryString
}
);
return (

View file

@ -29,6 +29,10 @@ export type MapConfig = {
};
filters: {
currentUser: boolean;
dateMode: "none" | "range" | "threshold";
startDate?: null | string;
endDate?: null | string;
thresholdAfter?: null | boolean;
};
};
@ -47,6 +51,10 @@ export const initialState: MapConfig = {
},
filters: {
currentUser: false,
dateMode: "none",
startDate: null,
endDate: null,
thresholdAfter: true,
},
};