117 lines
3.3 KiB
TypeScript
117 lines
3.3 KiB
TypeScript
import { MapContainer, GeoJSON, TileLayer } from "react-leaflet";
|
|
import Parser from "./parser/parser";
|
|
import { createRef, useEffect, useState } from "react";
|
|
import hash from "object-hash";
|
|
import Leaflet from "leaflet";
|
|
import L from "leaflet";
|
|
|
|
const parser = await Parser.instance();
|
|
|
|
const terminals = [10394, 10395, 10475, 10480, 10482, 10485, 10653];
|
|
|
|
function App() {
|
|
const [selectedTerminal, setSelectedTerminal] = useState(terminals[0]);
|
|
const [procedure, setProcedure] = useState<string>();
|
|
|
|
const mapRef = createRef<Leaflet.Map>();
|
|
const layerRef = createRef<Leaflet.GeoJSON>();
|
|
|
|
useEffect(() => {
|
|
(async () => {
|
|
setProcedure(await parser.parse(selectedTerminal));
|
|
})();
|
|
}, [selectedTerminal]);
|
|
|
|
useEffect(() => {
|
|
if (layerRef.current && mapRef.current) {
|
|
mapRef.current.flyToBounds(layerRef.current.getBounds(), {
|
|
animate: false,
|
|
padding: [50, 50],
|
|
});
|
|
}
|
|
});
|
|
|
|
return (
|
|
<div style={{ display: "flex", height: "100vh", width: "100vw" }}>
|
|
<MapContainer
|
|
center={[51.505, -0.09]}
|
|
zoom={13}
|
|
zoomSnap={0}
|
|
zoomDelta={0.1}
|
|
wheelPxPerZoomLevel={1000}
|
|
style={{ height: "100%", width: "100%" }}
|
|
ref={mapRef}
|
|
>
|
|
<TileLayer
|
|
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
|
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
|
/>
|
|
<GeoJSON
|
|
key={hash(procedure ?? "") + "lines"}
|
|
data={procedure}
|
|
style={{
|
|
color: "#00ffff",
|
|
stroke: true,
|
|
weight: 5,
|
|
opacity: 1,
|
|
}}
|
|
filter={(feature) => feature.geometry.type !== "Point"}
|
|
ref={layerRef}
|
|
/>
|
|
<GeoJSON
|
|
key={hash(procedure ?? "") + "points"}
|
|
data={procedure}
|
|
style={(feature) => ({
|
|
color: feature.properties["marker-color"],
|
|
stroke: false,
|
|
fill: true,
|
|
fillOpacity: 1,
|
|
})}
|
|
pointToLayer={(_, latlng) => {
|
|
return L.circleMarker(latlng, { radius: 5 });
|
|
}}
|
|
onEachFeature={({ geometry, properties }, layer) => {
|
|
if (geometry.type === "Point") {
|
|
layer.bindPopup(
|
|
`${properties.name}<br>
|
|
${properties.altitude} ft<br>
|
|
${properties.speed} kts<br>
|
|
CNSTR:
|
|
${properties.altitudeConstraint ?? ""}
|
|
${properties.speedConstraint ?? ""}<br>`
|
|
);
|
|
}
|
|
}}
|
|
filter={(feature) => feature.geometry.type === "Point"}
|
|
/>
|
|
</MapContainer>
|
|
<div
|
|
style={{
|
|
padding: "5px",
|
|
display: "flex",
|
|
flexDirection: "column",
|
|
gap: "10px",
|
|
}}
|
|
>
|
|
{terminals.map((terminal) => (
|
|
<div
|
|
key={terminal}
|
|
style={{
|
|
display: "flex",
|
|
gap: "10px",
|
|
background: selectedTerminal === terminal ? "#eeeeee" : undefined,
|
|
}}
|
|
>
|
|
<pre>ID {terminal}</pre>
|
|
<button onClick={() => setSelectedTerminal(terminal)}>
|
|
Select
|
|
</button>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default App;
|