Skip to content

Commit ad50b4d

Browse files
committed
store map state in the hash [not so good AI]
AI couldn't create useMapHash correctly. I had to do quite a lot of manual editing. Basically, throttling wasn't working.
1 parent c658379 commit ad50b4d

File tree

4 files changed

+93
-1
lines changed

4 files changed

+93
-1
lines changed

package-lock.json

Lines changed: 25 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"dependencies": {
1313
"@vis.gl/react-maplibre": "^1.0.0-alpha.4",
1414
"autoprefixer": "^10.4.20",
15+
"lodash.throttle": "^4.1.1",
1516
"maplibre-gl": "^4.7.1",
1617
"postcss": "^8.4.49",
1718
"react": "^18.3.1",
@@ -20,6 +21,7 @@
2021
},
2122
"devDependencies": {
2223
"@eslint/js": "^9.13.0",
24+
"@types/lodash.throttle": "^4.1.9",
2325
"@types/react": "^18.3.12",
2426
"@types/react-dom": "^18.3.1",
2527
"@vitejs/plugin-react": "^4.3.3",

src/contexts/AppContext.tsx

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
1-
import { createContext, ReactNode, useCallback, useContext } from "react";
1+
import {
2+
createContext,
3+
ReactNode,
4+
useCallback,
5+
useContext,
6+
useEffect,
7+
} from "react";
28
import { DEFAULT_SOURCE_ID, MAP_SOURCES } from "../constants/mapSources";
39
import { useLocalStorage } from "../hooks/useLocalStorage";
410
import { AppState, BoxCount, MapSource, MapState } from "../types";
11+
import { useMapHash } from "../hooks/useMapHash";
512

613
function getInitialPanels() {
714
// Get available source IDs excluding the default one
@@ -182,6 +189,14 @@ export function AppProvider({ children }: { children: ReactNode }) {
182189
initialState
183190
);
184191

192+
const hashState = useMapHash(state.mapState);
193+
194+
useEffect(() => {
195+
if (hashState) {
196+
dispatch({ type: "UPDATE_MAP_STATE", payload: hashState });
197+
}
198+
}, []);
199+
185200
const dispatch = useCallback(
186201
(action: Action) => {
187202
setState((currentState) => appReducer(currentState, action));

src/hooks/useMapHash.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { useEffect, useRef, useState, useCallback } from "react";
2+
import throttle from "lodash.throttle";
3+
import { MapState } from "../types";
4+
5+
function parseHash(): MapState | null {
6+
const hash = window.location.hash.slice(1);
7+
const [zoom, lat, lng, bearing = "0", pitch = "0"] = hash.split("/");
8+
9+
if (!zoom || !lat || !lng) return null;
10+
11+
return {
12+
center: [parseFloat(lng), parseFloat(lat)],
13+
zoom: parseFloat(zoom),
14+
bearing: parseFloat(bearing),
15+
pitch: parseFloat(pitch),
16+
};
17+
}
18+
19+
function formatHash(mapState: MapState): string {
20+
const { zoom, center, bearing, pitch } = mapState;
21+
return `#${zoom.toFixed(2)}/${center[1].toFixed(4)}/${center[0].toFixed(
22+
4
23+
)}/${bearing.toFixed(0)}/${pitch.toFixed(0)}`;
24+
}
25+
26+
export function useMapHash(mapState: MapState): MapState | null {
27+
// Store initial hash state
28+
const [initialState] = useState(parseHash);
29+
30+
function onHashChange(newState: MapState) {
31+
console.log("throttledUpdateHash");
32+
const newHash = formatHash(newState);
33+
if (window.location.hash !== newHash) {
34+
window.location.hash = newHash;
35+
}
36+
}
37+
38+
// Create throttled callback
39+
const throttledUpdateHash = useCallback(
40+
throttle(onHashChange, 500),
41+
[] // Empty deps array as this function doesn't depend on any props/state
42+
);
43+
44+
// Update hash when mapState changes
45+
useEffect(() => {
46+
throttledUpdateHash(mapState);
47+
}, [mapState, throttledUpdateHash]);
48+
49+
return initialState;
50+
}

0 commit comments

Comments
 (0)