Skip to content

Commit 64f1870

Browse files
committed
feat: hovering
1 parent 19248ac commit 64f1870

File tree

7 files changed

+105
-31
lines changed

7 files changed

+105
-31
lines changed

src/components/footer.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { HStack, Text } from "@chakra-ui/react";
2+
import { useDuckDb } from "duckdb-wasm-kit";
3+
export default function Footer() {
4+
const { loading, error } = useDuckDb();
5+
return (
6+
<HStack
7+
style={{
8+
position: "absolute",
9+
bottom: 0,
10+
left: 0,
11+
}}
12+
px={4}
13+
py={2}
14+
>
15+
{loading && <Text>Loading DuckDB...</Text>}
16+
{error && <Text color={"red"}>DuckDB error: {error.toString()}</Text>}
17+
</HStack>
18+
);
19+
}

src/components/header.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export default function Header() {
3838
}, [fileUpload.acceptedFiles, db, dispatch]);
3939

4040
return (
41-
<HStack spaceX={2}>
41+
<HStack spaceX={2} pointerEvents={"auto"}>
4242
<Input
4343
variant={"subtle"}
4444
placeholder={

src/components/map.tsx

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,21 @@ import {
88
useControl,
99
type MapRef,
1010
} from "react-map-gl/maplibre";
11-
import { useStacGeoparquet } from "./stac-geoparquet/hooks";
11+
import {
12+
useStacGeoparquet,
13+
useStacGeoparquetDispatch,
14+
} from "./stac-geoparquet/hooks";
1215
import { useColorModeValue } from "./ui/color-mode";
1316

1417
function DeckGLOverlay(props: DeckProps) {
15-
const control = useControl<MapboxOverlay>(() => new MapboxOverlay(props));
18+
const control = useControl<MapboxOverlay>(() => new MapboxOverlay({}));
1619
control.setProps(props);
1720
return <></>;
1821
}
1922

2023
export default function Map() {
2124
const state = useStacGeoparquet();
25+
const dispatch = useStacGeoparquetDispatch();
2226
const [layers, setLayers] = useState<GeoArrowPolygonLayer[]>([]);
2327
const mapRef = useRef<MapRef>(null);
2428
const mapStyle = useColorModeValue(
@@ -36,6 +40,15 @@ export default function Map() {
3640
getFillColor: () => {
3741
return [207, 63, 2, 100];
3842
},
43+
pickable: true,
44+
autoHighlight: true,
45+
highlightColor: [252, 192, 38],
46+
onHover: (info) => {
47+
if (state.table) {
48+
const id = state.table.getChild("id")?.get(info.index);
49+
dispatch({ type: "set-id", id });
50+
}
51+
},
3952
});
4053
setLayers([layer]);
4154
} else {
@@ -46,7 +59,7 @@ export default function Map() {
4659
useEffect(() => {
4760
if (state.metadata) {
4861
if (mapRef.current) {
49-
mapRef.current.fitBounds(state.metadata.bounds, { padding: 20 });
62+
mapRef.current.fitBounds(state.metadata.bounds, { padding: 100 });
5063
}
5164
}
5265
}, [state.metadata]);

src/components/overlay.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import { Container } from "@chakra-ui/react";
2+
import Footer from "./footer";
23
import Header from "./header";
34
import Sidebar from "./sidebar";
45

56
export default function Overlay() {
67
return (
7-
<Container fluid py={2}>
8+
<Container fluid py={2} h={"100vh"} pointerEvents={"none"}>
89
<Header></Header>
910
<Sidebar></Sidebar>
11+
<Footer></Footer>
1012
</Container>
1113
);
1214
}

src/components/sidebar.tsx

Lines changed: 50 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,58 @@
1-
import { Alert, SimpleGrid, Stack } from "@chakra-ui/react";
2-
import { useDuckDb } from "duckdb-wasm-kit";
1+
import { DataList, SimpleGrid, Tabs, Text } from "@chakra-ui/react";
2+
import { LuFolder, LuFolderMinus } from "react-icons/lu";
3+
import type { StacGeoparquetMetadata } from "./stac-geoparquet/context";
34
import { useStacGeoparquet } from "./stac-geoparquet/hooks";
45

6+
function Info({
7+
metadata,
8+
id,
9+
}: {
10+
metadata?: StacGeoparquetMetadata;
11+
id?: string;
12+
}) {
13+
if (metadata) {
14+
return (
15+
<DataList.Root orientation={"horizontal"} size={"sm"}>
16+
<DataList.Item>
17+
<DataList.ItemLabel>Count</DataList.ItemLabel>
18+
<DataList.ItemValue>{metadata.count}</DataList.ItemValue>
19+
</DataList.Item>
20+
<DataList.Item>
21+
<DataList.ItemLabel>Active item</DataList.ItemLabel>
22+
<DataList.ItemValue>{id || "none"}</DataList.ItemValue>
23+
</DataList.Item>
24+
</DataList.Root>
25+
);
26+
} else {
27+
return <Text>No file loaded...</Text>;
28+
}
29+
}
30+
531
export default function Sidebar() {
6-
const { loading, error } = useDuckDb();
7-
const { metadata } = useStacGeoparquet();
32+
const { metadata, id } = useStacGeoparquet();
833

934
return (
10-
<SimpleGrid columns={4} my={2}>
11-
<Stack bg={"bg.muted"} px={4} py={2} fontSize={"sm"} rounded={"sm"}>
12-
{(metadata && `${metadata.count} items`) || "No file loaded..."}
13-
</Stack>
14-
<Stack fontSize={"small"} mx={4} my={2}>
15-
{loading && (
16-
<Alert.Root status={"info"}>
17-
<Alert.Indicator></Alert.Indicator>
18-
<Alert.Content>Loading DuckDB...</Alert.Content>
19-
</Alert.Root>
20-
)}
21-
{error && (
22-
<Alert.Root status={"error"}>
23-
<Alert.Indicator></Alert.Indicator>
24-
<Alert.Content>DuckDB error: {error.toString()}</Alert.Content>
25-
</Alert.Root>
26-
)}
27-
</Stack>
35+
<SimpleGrid columns={3} my={2} pointerEvents={"auto"}>
36+
<Tabs.Root
37+
bg={"bg.muted"}
38+
px={4}
39+
pt={2}
40+
pb={4}
41+
fontSize={"sm"}
42+
rounded={"sm"}
43+
defaultValue={"info"}
44+
>
45+
<Tabs.List>
46+
<Tabs.Trigger value="info">
47+
{(metadata && <LuFolder></LuFolder>) || (
48+
<LuFolderMinus></LuFolderMinus>
49+
)}
50+
</Tabs.Trigger>
51+
</Tabs.List>
52+
<Tabs.Content value="info">
53+
<Info metadata={metadata} id={id}></Info>
54+
</Tabs.Content>
55+
</Tabs.Root>
2856
</SimpleGrid>
2957
);
3058
}

src/components/stac-geoparquet/context.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,24 @@ export type StacGeoparquetState = {
66
path?: string;
77
metadata?: StacGeoparquetMetadata;
88
table?: Table;
9+
id?: string;
910
};
1011

1112
type StacGeoparquetContextType = {
1213
state: StacGeoparquetState;
1314
dispatch: Dispatch<StacGeoparquetAction>;
1415
};
1516

16-
type StacGeoparquetMetadata = {
17+
export type StacGeoparquetMetadata = {
1718
count: number;
1819
bounds: LngLatBounds;
1920
};
2021

2122
export type StacGeoparquetAction =
2223
| { type: "set-path"; path: string }
2324
| { type: "set-metadata"; metadata: StacGeoparquetMetadata }
24-
| { type: "set-table"; table: Table };
25+
| { type: "set-table"; table: Table }
26+
| { type: "set-id"; id?: string };
2527

2628
export const StacGeoparquetContext =
2729
createContext<StacGeoparquetContextType | null>(null);

src/components/stac-geoparquet/provider.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
import { AsyncDuckDBConnection } from "@duckdb/duckdb-wasm";
22
import { io } from "@geoarrow/geoarrow-js";
3-
import { Binary, Data, makeData, makeVector, Table } from "apache-arrow";
3+
import {
4+
Binary,
5+
Data,
6+
makeData,
7+
makeVector,
8+
Table,
9+
vectorFromArray,
10+
} from "apache-arrow";
411
import { useDuckDb } from "duckdb-wasm-kit";
512
import { LngLatBounds } from "maplibre-gl";
613
import { useEffect, useReducer, useState, type ReactNode } from "react";
@@ -75,7 +82,7 @@ export default function StacGeoparquetProvider({
7582
if (connection) {
7683
(async () => {
7784
const result = await connection.query(
78-
`SELECT st_aswkb(geometry) as geometry FROM read_parquet('${state.path}', union_by_name=true);`
85+
`SELECT st_aswkb(geometry) as geometry, id FROM read_parquet('${state.path}', union_by_name=true);`
7986
);
8087
const geometry: Uint8Array[] = result.getChildAt(0)?.toArray();
8188
const wkb = new Uint8Array(geometry?.flatMap((array) => [...array]));
@@ -93,6 +100,7 @@ export default function StacGeoparquetProvider({
93100
const table = new Table({
94101
// @ts-expect-error: 2769
95102
geometry: makeVector(polygons),
103+
id: vectorFromArray(result.getChild("id")?.toArray()),
96104
});
97105
table.schema.fields[0].metadata.set(
98106
"ARROW:extension:name",
@@ -122,5 +130,7 @@ function reducer(state: StacGeoparquetState, action: StacGeoparquetAction) {
122130
return { ...state, metadata: action.metadata };
123131
case "set-table":
124132
return { ...state, table: action.table };
133+
case "set-id":
134+
return { ...state, id: action.id };
125135
}
126136
}

0 commit comments

Comments
 (0)