66 lines
1.8 KiB
TypeScript
66 lines
1.8 KiB
TypeScript
import { useEffect, useRef, useState } from 'react';
|
|
import { Airport, AirportCategory } from '@lib/airport.types.ts';
|
|
import { useMapEvents } from 'react-leaflet';
|
|
import debounce from 'lodash.debounce';
|
|
import { getAirports } from '@lib/airport.ts';
|
|
import AirportMarker from '@components/AirportMarker.tsx';
|
|
import { LayerInfo } from '@/App.tsx';
|
|
import { LatLng } from 'leaflet';
|
|
|
|
export default function AirportLayer({
|
|
setAirport,
|
|
showNoMetar,
|
|
selectedLayer
|
|
}: {
|
|
setAirport: (airport: Airport) => void;
|
|
showNoMetar: boolean;
|
|
selectedLayer: LayerInfo;
|
|
}) {
|
|
const [airports, setAirports] = useState<Airport[]>([]);
|
|
const lastBoundsRef = useRef<{ ne: LatLng; sw: LatLng } | null>(null);
|
|
|
|
const debouncedLoad = useRef(
|
|
debounce(async (map: any) => {
|
|
const bounds = map.getBounds();
|
|
const ne = bounds.getNorthEast();
|
|
const sw = bounds.getSouthWest();
|
|
lastBoundsRef.current = { ne, sw };
|
|
|
|
try {
|
|
const resp = await getAirports({
|
|
bounds: { northEast: ne, southWest: sw },
|
|
metars: true,
|
|
categories: [AirportCategory.HELIPORT, AirportCategory.SMALL, AirportCategory.MEDIUM, AirportCategory.LARGE]
|
|
});
|
|
setAirports(resp.data);
|
|
} catch (err) {
|
|
console.error('fetch error', err);
|
|
setAirports([]);
|
|
}
|
|
}, 300)
|
|
).current;
|
|
|
|
const map = useMapEvents({
|
|
move: () => debouncedLoad(map)
|
|
});
|
|
|
|
useEffect(() => {
|
|
if (map) debouncedLoad(map);
|
|
return () => {
|
|
debouncedLoad.cancel();
|
|
};
|
|
}, [map, debouncedLoad]);
|
|
|
|
return (
|
|
<>
|
|
{airports.map((airport, index) => (
|
|
<div key={index}>
|
|
{(showNoMetar || airport.latest_metar != undefined) && (
|
|
<AirportMarker airport={airport} index={index} setAirport={setAirport} selectedLayer={selectedLayer} />
|
|
)}
|
|
</div>
|
|
))}
|
|
</>
|
|
);
|
|
}
|