Skip to content

Commit 4f673bd

Browse files
authored
fix: search over antimeridian (#79)
* fix: move picked clearing up to the provider * refactor: getStartAndEndDatetime * fix: normalize bbox * fix: typing
1 parent 09094c3 commit 4f673bd

File tree

2 files changed

+47
-19
lines changed

2 files changed

+47
-19
lines changed

src/components/search/item.tsx

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import {
1515
Select,
1616
Stack,
1717
Switch,
18-
Text,
1918
} from "@chakra-ui/react";
2019
import { useEffect, useState } from "react";
2120
import { LuPause, LuPlay, LuSearch, LuX } from "react-icons/lu";
@@ -34,7 +33,7 @@ export default function ItemSearch({
3433
collection: StacCollection;
3534
links: StacLink[];
3635
}) {
37-
const { setItems, setPicked } = useStacMap();
36+
const { setItems } = useStacMap();
3837
const [search, setSearch] = useState<StacSearch>();
3938
const [link, setLink] = useState<StacLink | undefined>(links[0]);
4039
const [datetime, setDatetime] = useState<string>();
@@ -44,9 +43,8 @@ export default function ItemSearch({
4443
useEffect(() => {
4544
if (!search) {
4645
setItems(undefined);
47-
setPicked(undefined);
4846
}
49-
}, [search, setItems, setPicked]);
47+
}, [search, setItems]);
5048

5149
const methods = createListCollection({
5250
items: links.map((link) => {
@@ -82,8 +80,6 @@ export default function ItemSearch({
8280
<Switch.Control></Switch.Control>
8381
</Switch.Root>
8482

85-
<Text></Text>
86-
8783
<Datetime
8884
interval={collection.extent?.temporal?.interval[0]}
8985
setDatetime={setDatetime}
@@ -132,7 +128,14 @@ export default function ItemSearch({
132128
datetime,
133129
bbox:
134130
useViewportBounds && map
135-
? map.getBounds().toArray().flat()
131+
? normalizeBbox(
132+
map.getBounds().toArray().flat() as [
133+
number,
134+
number,
135+
number,
136+
number,
137+
],
138+
)
136139
: undefined,
137140
})
138141
}
@@ -356,3 +359,26 @@ function DatetimeInput({
356359
</Field.Root>
357360
);
358361
}
362+
363+
function normalizeBbox(bbox: [number, number, number, number]) {
364+
if (bbox[2] - bbox[0] >= 360) {
365+
return [-180, bbox[1], 180, bbox[3]];
366+
} else if (bbox[0] < -180) {
367+
return normalizeBbox([bbox[0] + 360, bbox[1], bbox[2] + 360, bbox[3]]);
368+
} else if (bbox[0] > 180) {
369+
return normalizeBbox([bbox[0] - 360, bbox[1], bbox[2] - 360, bbox[3]]);
370+
} else if (bbox[2] > 180) {
371+
// Antimeridian-crossing
372+
toaster.create({
373+
type: "info",
374+
title: "Viewport crosses the antimeridian",
375+
description:
376+
"The viewport crosses the antimeridian, and many STAC API servers do not support bounding boxes that cross +/- 180° longitude. We're narrowing the viewport to only search to only one side.",
377+
});
378+
if ((bbox[0] + bbox[2]) / 2 > 180) {
379+
return [-180, bbox[1], bbox[2] - 360, bbox[3]];
380+
} else {
381+
return [bbox[0], bbox[1], 180, bbox[3]];
382+
}
383+
}
384+
}

src/provider.tsx

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -63,20 +63,19 @@ export function StacMapProvider({ children }: { children: ReactNode }) {
6363
setTemporalFilter(undefined);
6464
}, [value, setStacGeoparquetItemId]);
6565

66+
useEffect(() => {
67+
setPicked(undefined);
68+
}, [items]);
69+
6670
useEffect(() => {
6771
if (items) {
6872
let start: Date | null = null;
6973
let end: Date | null = null;
7074
items.forEach((item) => {
71-
const itemStartStr =
72-
item.properties.start_datetime || item.properties.datetime;
73-
const itemStart = itemStartStr ? new Date(itemStartStr) : null;
75+
const { start: itemStart, end: itemEnd } = getStartAndEndDatetime(item);
7476
if (!start || (itemStart && itemStart < start)) {
7577
start = itemStart;
7678
}
77-
const itemEndStr =
78-
item.properties.end_datetime || item.properties.datetime;
79-
const itemEnd = itemEndStr ? new Date(itemEndStr) : null;
8079
if (!end || (itemEnd && itemEnd > end)) {
8180
end = itemEnd;
8281
}
@@ -92,12 +91,7 @@ export function StacMapProvider({ children }: { children: ReactNode }) {
9291
if (temporalFilter) {
9392
setFilteredItems(
9493
items.filter((item) => {
95-
const startStr =
96-
item.properties.start_datetime || item.properties.datetime;
97-
const start = startStr ? new Date(startStr) : null;
98-
const endStr =
99-
item.properties.end_datetime || item.properties.datetime;
100-
const end = endStr ? new Date(endStr) : null;
94+
const { start, end } = getStartAndEndDatetime(item);
10195
return (
10296
(!start || start >= temporalFilter.start) &&
10397
(!end || end <= temporalFilter.end)
@@ -165,3 +159,11 @@ function getInitialHref() {
165159
}
166160
return href;
167161
}
162+
163+
function getStartAndEndDatetime(item: StacItem) {
164+
const startStr = item.properties.start_datetime || item.properties.datetime;
165+
const start = startStr ? new Date(startStr) : null;
166+
const endStr = item.properties.end_datetime || item.properties.datetime;
167+
const end = endStr ? new Date(endStr) : null;
168+
return { start, end };
169+
}

0 commit comments

Comments
 (0)