Add date-range filters to map
This commit is contained in:
parent
7716da8844
commit
e0cb36565a
|
@ -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,
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -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,11 +221,18 @@ function LayerSidebar({
|
|||
</>
|
||||
)}
|
||||
<Divider />
|
||||
|
||||
<List.Item>
|
||||
<Header as="h4" style={{ marginBottom: 8 }}>
|
||||
Filter
|
||||
</Header>
|
||||
<Header as="h4">Filters</Header>
|
||||
</List.Item>
|
||||
|
||||
{login && (
|
||||
<>
|
||||
<List.Item>
|
||||
<Header as="h5">User data</Header>
|
||||
</List.Item>
|
||||
|
||||
<List.Item>
|
||||
<Checkbox
|
||||
toggle
|
||||
size="small"
|
||||
|
@ -224,9 +243,91 @@ function LayerSidebar({
|
|||
}
|
||||
label="Show only my own data"
|
||||
/>
|
||||
)}
|
||||
{!login && <div>No filters available without login.</div>}
|
||||
</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>
|
||||
);
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue