@mytec: iter7 ready for test
This commit is contained in:
74
frontend/src/hooks/useElevation.ts
Normal file
74
frontend/src/hooks/useElevation.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useMap } from 'react-leaflet';
|
||||
import L from 'leaflet';
|
||||
|
||||
interface ElevationState {
|
||||
elevation: number | null;
|
||||
position: { lat: number; lon: number } | null;
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
export function useElevation() {
|
||||
const map = useMap();
|
||||
const [state, setState] = useState<ElevationState>({
|
||||
elevation: null,
|
||||
position: null,
|
||||
loading: false,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
let timeoutId: number;
|
||||
let abortController: AbortController | null = null;
|
||||
|
||||
const handleMouseMove = (e: L.LeafletMouseEvent) => {
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
position: { lat: e.latlng.lat, lon: e.latlng.lng },
|
||||
}));
|
||||
|
||||
// Debounce API calls (300ms)
|
||||
clearTimeout(timeoutId);
|
||||
if (abortController) abortController.abort();
|
||||
|
||||
timeoutId = window.setTimeout(async () => {
|
||||
setState((prev) => ({ ...prev, loading: true }));
|
||||
abortController = new AbortController();
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
`https://api.open-elevation.com/api/v1/lookup?locations=${e.latlng.lat},${e.latlng.lng}`,
|
||||
{ signal: abortController.signal }
|
||||
);
|
||||
const data = await response.json();
|
||||
const elev = data?.results?.[0]?.elevation ?? null;
|
||||
setState((prev) => ({ ...prev, elevation: elev, loading: false }));
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof DOMException && error.name === 'AbortError') {
|
||||
// Intentional abort, ignore
|
||||
return;
|
||||
}
|
||||
console.error('Elevation fetch failed:', error);
|
||||
setState((prev) => ({ ...prev, elevation: null, loading: false }));
|
||||
}
|
||||
}, 300);
|
||||
};
|
||||
|
||||
const handleMouseOut = () => {
|
||||
clearTimeout(timeoutId);
|
||||
if (abortController) abortController.abort();
|
||||
setState({ elevation: null, position: null, loading: false });
|
||||
};
|
||||
|
||||
map.on('mousemove', handleMouseMove);
|
||||
map.on('mouseout', handleMouseOut);
|
||||
|
||||
return () => {
|
||||
map.off('mousemove', handleMouseMove);
|
||||
map.off('mouseout', handleMouseOut);
|
||||
clearTimeout(timeoutId);
|
||||
if (abortController) abortController.abort();
|
||||
};
|
||||
}, [map]);
|
||||
|
||||
return state;
|
||||
}
|
||||
Reference in New Issue
Block a user