Skip to content

Commit 46cd096

Browse files
authored
1 parent 502e576 commit 46cd096

File tree

4 files changed

+110
-23
lines changed

4 files changed

+110
-23
lines changed

src/components/filter/temporal.tsx

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { useEffect, useState } from "react";
2+
import useStacMap from "../../hooks/stac-map";
3+
import { HStack, Slider } from "@chakra-ui/react";
4+
import Section from "../section";
5+
import { LuFilter } from "react-icons/lu";
6+
7+
export default function TemporalFilter({
8+
start,
9+
end,
10+
}: {
11+
start: Date;
12+
end: Date;
13+
}) {
14+
const { setTemporalFilter } = useStacMap();
15+
const [filterStart, setFilterStart] = useState<Date>();
16+
const [filterEnd, setFilterEnd] = useState<Date>();
17+
const [value, setValue] = useState([start.getTime(), end.getTime()]);
18+
19+
useEffect(() => {
20+
setValue([
21+
(filterStart && filterStart.getTime()) || start.getTime(),
22+
(filterEnd && filterEnd.getTime()) || end.getTime(),
23+
]);
24+
}, [filterStart, filterEnd, start, end]);
25+
26+
useEffect(() => {
27+
if (filterStart && filterEnd) {
28+
setTemporalFilter({ start: filterStart, end: filterEnd });
29+
} else {
30+
setTemporalFilter(undefined);
31+
}
32+
}, [filterStart, filterEnd, setTemporalFilter]);
33+
34+
return (
35+
<Section title="Temporal filter" TitleIcon={LuFilter}>
36+
<Slider.Root
37+
value={value}
38+
onValueChange={(e) => {
39+
setFilterStart(new Date(e.value[0]));
40+
setFilterEnd(new Date(e.value[1]));
41+
}}
42+
min={start.getTime()}
43+
max={end.getTime()}
44+
gap={2}
45+
>
46+
<Slider.Control>
47+
<Slider.Track>
48+
<Slider.Range />
49+
</Slider.Track>
50+
<Slider.Thumbs />
51+
</Slider.Control>
52+
<HStack justify={"space-between"}>
53+
<Slider.Label>
54+
{(filterStart && filterStart.toLocaleString()) ||
55+
start.toLocaleString()}
56+
</Slider.Label>
57+
<Slider.Label>
58+
{(filterEnd && filterEnd.toLocaleString()) || end.toLocaleString()}
59+
</Slider.Label>
60+
</HStack>
61+
</Slider.Root>
62+
</Section>
63+
);
64+
}

src/components/panel.tsx

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
Stack,
66
type UseFileUploadReturn,
77
} from "@chakra-ui/react";
8-
import { useEffect, useState } from "react";
8+
import { useEffect, useMemo, useState } from "react";
99
import type { StacLink } from "stac-ts";
1010
import useStacMap from "../hooks/stac-map";
1111
import type { SetHref } from "../types/app";
@@ -17,6 +17,8 @@ import Item from "./item";
1717
import ItemCollection from "./item-collection";
1818
import { NavigationBreadcrumbs } from "./navigation-breadcrumbs";
1919
import { ItemSearchResults } from "./search/item";
20+
import { getItemDatetimes } from "../stac";
21+
import TemporalFilter from "./filter/temporal";
2022

2123
export default function Panel({
2224
href,
@@ -27,7 +29,7 @@ export default function Panel({
2729
setHref: SetHref;
2830
fileUpload: UseFileUploadReturn;
2931
}) {
30-
const { value, picked, setPicked, setItems } = useStacMap();
32+
const { value, picked, setPicked, items, setItems } = useStacMap();
3133
const [search, setSearch] = useState<StacSearch>();
3234
const [searchLink, setSearchLink] = useState<StacLink>();
3335
const [autoLoad, setAutoLoad] = useState(false);
@@ -37,6 +39,21 @@ export default function Panel({
3739
setPicked(undefined);
3840
}, [search, setPicked, setItems]);
3941

42+
const { start: itemsStart, end: itemsEnd } = useMemo(() => {
43+
if (items) {
44+
let start = null;
45+
let end = null;
46+
for (const item of items) {
47+
const { start: itemStart, end: itemEnd } = getItemDatetimes(item);
48+
if (itemStart && (!start || itemStart < start)) start = itemStart;
49+
if (itemEnd && (!end || itemEnd > end)) end = itemEnd;
50+
}
51+
return { start, end };
52+
} else {
53+
return { start: null, end: null };
54+
}
55+
}, [items]);
56+
4057
let content;
4158
if (!href) {
4259
content = (
@@ -89,6 +106,9 @@ export default function Panel({
89106
setAutoLoad={setAutoLoad}
90107
></ItemSearchResults>
91108
)}
109+
{itemsStart && itemsEnd && (
110+
<TemporalFilter start={itemsStart} end={itemsEnd} />
111+
)}
92112
</Stack>
93113
</Box>
94114
);

src/provider.tsx

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { StacMapContext } from "./context";
55
import useStacGeoparquet from "./hooks/stac-geoparquet";
66
import { useStacValue } from "./hooks/stac-value";
77
import type { TemporalFilter } from "./types/datetime";
8+
import { getItemDatetimes } from "./stac";
89

910
export function StacMapProvider({
1011
href,
@@ -37,10 +38,6 @@ export function StacMapProvider({
3738
item: stacGeoparquetItem,
3839
} = useStacGeoparquet(parquetPath, temporalFilter);
3940

40-
const items = useMemo(() => {
41-
return unlinkedItems || linkedItems;
42-
}, [unlinkedItems, linkedItems]);
43-
4441
useEffect(() => {
4542
if (value?.title || value?.id) {
4643
document.title = "stac-map | " + (value.title || value.id);
@@ -56,6 +53,10 @@ export function StacMapProvider({
5653
setPicked(stacGeoparquetItem);
5754
}, [stacGeoparquetItem]);
5855

56+
const items = useMemo(() => {
57+
return unlinkedItems || linkedItems;
58+
}, [unlinkedItems, linkedItems]);
59+
5960
const filteredItems = useMemo(() => {
6061
if (items && temporalFilter) {
6162
return items.filter((item) =>
@@ -92,21 +93,8 @@ function isItemWithinTemporalFilter(
9293
item: StacItem,
9394
temporalFilter: TemporalFilter,
9495
) {
95-
const start = item.properties?.start_datetime
96-
? new Date(item.properties.start_datetime)
97-
: item.properties?.datetime
98-
? new Date(item.properties.datetime)
99-
: null;
100-
if (!start) {
101-
return false;
102-
}
103-
const end = item.properties?.end_datetime
104-
? new Date(item.properties.end_datetime)
105-
: item.properties?.datetime
106-
? new Date(item.properties.datetime)
107-
: null;
108-
if (!end) {
109-
return false;
110-
}
111-
return start >= temporalFilter.start && end <= temporalFilter.end;
96+
const { start, end } = getItemDatetimes(item);
97+
return (
98+
start && end && start >= temporalFilter.start && end <= temporalFilter.end
99+
);
112100
}

src/stac.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import type { StacItem } from "stac-ts";
2+
3+
export function getItemDatetimes(item: StacItem) {
4+
const start = item.properties?.start_datetime
5+
? new Date(item.properties.start_datetime)
6+
: item.properties?.datetime
7+
? new Date(item.properties.datetime)
8+
: null;
9+
const end = item.properties?.end_datetime
10+
? new Date(item.properties.end_datetime)
11+
: item.properties?.datetime
12+
? new Date(item.properties.datetime)
13+
: null;
14+
return { start, end };
15+
}

0 commit comments

Comments
 (0)