Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions src/components/filter/temporal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { useEffect, useState } from "react";
import useStacMap from "../../hooks/stac-map";
import { HStack, Slider } from "@chakra-ui/react";
import Section from "../section";
import { LuFilter } from "react-icons/lu";

export default function TemporalFilter({
start,
end,
}: {
start: Date;
end: Date;
}) {
const { setTemporalFilter } = useStacMap();
const [filterStart, setFilterStart] = useState<Date>();
const [filterEnd, setFilterEnd] = useState<Date>();
const [value, setValue] = useState([start.getTime(), end.getTime()]);

useEffect(() => {
setValue([
(filterStart && filterStart.getTime()) || start.getTime(),
(filterEnd && filterEnd.getTime()) || end.getTime(),
]);
}, [filterStart, filterEnd, start, end]);

useEffect(() => {
if (filterStart && filterEnd) {
setTemporalFilter({ start: filterStart, end: filterEnd });
} else {
setTemporalFilter(undefined);
}
}, [filterStart, filterEnd, setTemporalFilter]);

return (
<Section title="Temporal filter" TitleIcon={LuFilter}>
<Slider.Root
value={value}
onValueChange={(e) => {
setFilterStart(new Date(e.value[0]));
setFilterEnd(new Date(e.value[1]));
}}
min={start.getTime()}
max={end.getTime()}
gap={2}
>
<Slider.Control>
<Slider.Track>
<Slider.Range />
</Slider.Track>
<Slider.Thumbs />
</Slider.Control>
<HStack justify={"space-between"}>
<Slider.Label>
{(filterStart && filterStart.toLocaleString()) ||
start.toLocaleString()}
</Slider.Label>
<Slider.Label>
{(filterEnd && filterEnd.toLocaleString()) || end.toLocaleString()}
</Slider.Label>
</HStack>
</Slider.Root>
</Section>
);
}
24 changes: 22 additions & 2 deletions src/components/panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
Stack,
type UseFileUploadReturn,
} from "@chakra-ui/react";
import { useEffect, useState } from "react";
import { useEffect, useMemo, useState } from "react";
import type { StacLink } from "stac-ts";
import useStacMap from "../hooks/stac-map";
import type { SetHref } from "../types/app";
Expand All @@ -17,6 +17,8 @@ import Item from "./item";
import ItemCollection from "./item-collection";
import { NavigationBreadcrumbs } from "./navigation-breadcrumbs";
import { ItemSearchResults } from "./search/item";
import { getItemDatetimes } from "../stac";
import TemporalFilter from "./filter/temporal";

export default function Panel({
href,
Expand All @@ -27,7 +29,7 @@ export default function Panel({
setHref: SetHref;
fileUpload: UseFileUploadReturn;
}) {
const { value, picked, setPicked, setItems } = useStacMap();
const { value, picked, setPicked, items, setItems } = useStacMap();
const [search, setSearch] = useState<StacSearch>();
const [searchLink, setSearchLink] = useState<StacLink>();
const [autoLoad, setAutoLoad] = useState(false);
Expand All @@ -37,6 +39,21 @@ export default function Panel({
setPicked(undefined);
}, [search, setPicked, setItems]);

const { start: itemsStart, end: itemsEnd } = useMemo(() => {
if (items) {
let start = null;
let end = null;
for (const item of items) {
const { start: itemStart, end: itemEnd } = getItemDatetimes(item);
if (itemStart && (!start || itemStart < start)) start = itemStart;
if (itemEnd && (!end || itemEnd > end)) end = itemEnd;
}
return { start, end };
} else {
return { start: null, end: null };
}
}, [items]);

let content;
if (!href) {
content = (
Expand Down Expand Up @@ -89,6 +106,9 @@ export default function Panel({
setAutoLoad={setAutoLoad}
></ItemSearchResults>
)}
{itemsStart && itemsEnd && (
<TemporalFilter start={itemsStart} end={itemsEnd} />
)}
</Stack>
</Box>
);
Expand Down
30 changes: 9 additions & 21 deletions src/provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { StacMapContext } from "./context";
import useStacGeoparquet from "./hooks/stac-geoparquet";
import { useStacValue } from "./hooks/stac-value";
import type { TemporalFilter } from "./types/datetime";
import { getItemDatetimes } from "./stac";

export function StacMapProvider({
href,
Expand Down Expand Up @@ -37,10 +38,6 @@ export function StacMapProvider({
item: stacGeoparquetItem,
} = useStacGeoparquet(parquetPath, temporalFilter);

const items = useMemo(() => {
return unlinkedItems || linkedItems;
}, [unlinkedItems, linkedItems]);

useEffect(() => {
if (value?.title || value?.id) {
document.title = "stac-map | " + (value.title || value.id);
Expand All @@ -56,6 +53,10 @@ export function StacMapProvider({
setPicked(stacGeoparquetItem);
}, [stacGeoparquetItem]);

const items = useMemo(() => {
return unlinkedItems || linkedItems;
}, [unlinkedItems, linkedItems]);

const filteredItems = useMemo(() => {
if (items && temporalFilter) {
return items.filter((item) =>
Expand Down Expand Up @@ -92,21 +93,8 @@ function isItemWithinTemporalFilter(
item: StacItem,
temporalFilter: TemporalFilter,
) {
const start = item.properties?.start_datetime
? new Date(item.properties.start_datetime)
: item.properties?.datetime
? new Date(item.properties.datetime)
: null;
if (!start) {
return false;
}
const end = item.properties?.end_datetime
? new Date(item.properties.end_datetime)
: item.properties?.datetime
? new Date(item.properties.datetime)
: null;
if (!end) {
return false;
}
return start >= temporalFilter.start && end <= temporalFilter.end;
const { start, end } = getItemDatetimes(item);
return (
start && end && start >= temporalFilter.start && end <= temporalFilter.end
);
}
15 changes: 15 additions & 0 deletions src/stac.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { StacItem } from "stac-ts";

export function getItemDatetimes(item: StacItem) {
const start = item.properties?.start_datetime
? new Date(item.properties.start_datetime)
: item.properties?.datetime
? new Date(item.properties.datetime)
: null;
const end = item.properties?.end_datetime
? new Date(item.properties.end_datetime)
: item.properties?.datetime
? new Date(item.properties.datetime)
: null;
return { start, end };
}