fixed wrong env var, added base maps
This commit is contained in:
@@ -1,7 +1,272 @@
|
||||
"use client";
|
||||
import { usePannelStore } from "_store/pannelStore";
|
||||
import { useEffect } from "react";
|
||||
import { TileLayer, useMap } from "react-leaflet";
|
||||
import { Control, Icon, LatLngExpression } from "leaflet";
|
||||
import { useEffect, useState } from "react";
|
||||
import {
|
||||
LayerGroup,
|
||||
LayersControl,
|
||||
TileLayer,
|
||||
useMap,
|
||||
WMSTileLayer,
|
||||
GeoJSON,
|
||||
Circle,
|
||||
useMapEvent,
|
||||
FeatureGroup,
|
||||
Marker,
|
||||
Tooltip,
|
||||
} from "react-leaflet";
|
||||
// @ts-ignore
|
||||
import type { FeatureCollection, Geometry } from "geojson";
|
||||
import L from "leaflet";
|
||||
import LEITSTELLENBERECHE from "./_geojson/Leitstellen_VAR.json";
|
||||
import { createCustomMarker } from "_components/map/_components/createCustomMarker";
|
||||
import { Station } from "@repo/db";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { getStationsAPI } from "_querys/stations";
|
||||
|
||||
const RadioAreaLayer = () => {
|
||||
const getColor = (randint: number) => {
|
||||
switch (randint) {
|
||||
case 1:
|
||||
return "#2b6eff";
|
||||
case 2:
|
||||
return "#233ee5";
|
||||
case 3:
|
||||
return "#7BA5FF";
|
||||
case 4:
|
||||
return "#5087FF";
|
||||
default:
|
||||
return "#7f7f7f";
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<GeoJSON
|
||||
data={LEITSTELLENBERECHE as FeatureCollection<Geometry>}
|
||||
style={(feature) => {
|
||||
if (!feature || !feature.properties) return {}; // Early return if feature or its properties are undefined
|
||||
return {
|
||||
color: getColor(feature.properties.randint),
|
||||
weight: 1.5,
|
||||
className: "no-pointer",
|
||||
};
|
||||
}}
|
||||
onEachFeature={(feature, layer) => {
|
||||
if (feature && feature.properties && feature.properties.name) {
|
||||
layer.bindTooltip(
|
||||
new L.Tooltip({
|
||||
content: feature.properties.name,
|
||||
direction: "top",
|
||||
sticky: true,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const StationsLayer = ({ attribution }: { attribution: Control.Attribution }) => {
|
||||
const { data: stations } = useQuery({
|
||||
queryKey: ["stations"],
|
||||
queryFn: () => getStationsAPI(),
|
||||
});
|
||||
|
||||
const [selectedStations, setSelectedStations] = useState<Station["id"][]>([]);
|
||||
const [stationsWithIcon, setStationsWithIcon] = useState<(Station & { icon?: string })[]>([]); // Zustand für die Stationen mit Icon
|
||||
const attributionText = "";
|
||||
|
||||
const resetSelection = () => {
|
||||
setSelectedStations([]);
|
||||
};
|
||||
|
||||
useMapEvent("click", () => {
|
||||
resetSelection();
|
||||
});
|
||||
|
||||
const handleMarkerClick = (stationId: number) => {
|
||||
if (selectedStations.includes(stationId)) {
|
||||
setSelectedStations((prevStations) => prevStations.filter((s) => s !== stationId));
|
||||
} else {
|
||||
setSelectedStations((prevStations) => [...prevStations, stationId]);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
// Erstelle die Icons für alle Stationen
|
||||
|
||||
const fetchIcons = async () => {
|
||||
if (!stations) return;
|
||||
const urls = await Promise.all(
|
||||
stations.map(async (station) => {
|
||||
return createCustomMarker(station.operator);
|
||||
}),
|
||||
);
|
||||
setStationsWithIcon(stations.map((station, index) => ({ ...station, icon: urls[index] })));
|
||||
};
|
||||
|
||||
fetchIcons();
|
||||
}, [stations]);
|
||||
|
||||
return (
|
||||
<FeatureGroup>
|
||||
{stationsWithIcon.map((station) => {
|
||||
const coordinates: LatLngExpression = [station.latitude, station.longitude];
|
||||
const typeLabel = station.bosUse.charAt(0).toUpperCase();
|
||||
|
||||
return (
|
||||
<Marker
|
||||
key={`marker-${station.id}`}
|
||||
position={coordinates}
|
||||
icon={
|
||||
new Icon({
|
||||
iconUrl: station.icon,
|
||||
iconSize: [30, 30],
|
||||
iconAnchor: [15, 15],
|
||||
tooltipAnchor: [0, 20],
|
||||
className: station.hideRangeRings ? "no-pointer" : "pointer",
|
||||
})
|
||||
}
|
||||
eventHandlers={{
|
||||
click: () => {
|
||||
if (!station.hideRangeRings) handleMarkerClick(station.id);
|
||||
},
|
||||
add: () => attribution.addAttribution(attributionText),
|
||||
remove: () => attribution.removeAttribution(attributionText),
|
||||
}}
|
||||
>
|
||||
<Tooltip direction="top" sticky>
|
||||
<div style={{ textAlign: "center" }}>
|
||||
<strong>{station.bosCallsign}</strong>
|
||||
<small style={{ fontWeight: "bold", fontSize: "0.7em" }}>{` (${typeLabel})`}</small>
|
||||
<br />
|
||||
<small>
|
||||
{[
|
||||
station.hasWinch ? "W" : null,
|
||||
station.is24h ? "24h" : null,
|
||||
station.hasNvg ? "N" : null,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(", ")}
|
||||
</small>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</Marker>
|
||||
);
|
||||
})}
|
||||
|
||||
{selectedStations.map((stationId) => {
|
||||
const station = stations?.find((s) => s.id === stationId);
|
||||
|
||||
if (!station) return null;
|
||||
|
||||
const center: LatLngExpression = [station.latitude, station.longitude];
|
||||
return (
|
||||
<div key={`marker-${stationId}`}>
|
||||
<Circle
|
||||
center={center}
|
||||
radius={(station.aircraftSpeed * 1000) / 6}
|
||||
color="#0e0ecf"
|
||||
fillOpacity={0}
|
||||
weight={2}
|
||||
/>
|
||||
<Circle
|
||||
center={center}
|
||||
radius={(station.aircraftSpeed * 1000) / 3}
|
||||
color="navy"
|
||||
fillOpacity={0}
|
||||
weight={2}
|
||||
/>
|
||||
{(station.bosUse === "SECONDARY" || station.bosUse === "DUAL_USE") && (
|
||||
<Circle
|
||||
center={center}
|
||||
radius={station.aircraftSpeed * 1000}
|
||||
color="maroon"
|
||||
fillOpacity={0}
|
||||
weight={1}
|
||||
dashArray="40,30"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</FeatureGroup>
|
||||
);
|
||||
};
|
||||
|
||||
const EsriSatellite = ({ attribution }: { attribution: Control.Attribution }) => {
|
||||
const accessToken = process.env.NEXT_PUBLIC_ESRI_ACCESS_TOKEN || "";
|
||||
|
||||
const attributionText = "Sources: Esri, TomTom, Garmin, FAO, NOAA, USGS";
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Satellite Imagery Layer; API KEY PROVIDED BY VAR0002 */}
|
||||
<TileLayer
|
||||
eventHandlers={{
|
||||
add: () => attribution.addAttribution(attributionText),
|
||||
remove: () => attribution.removeAttribution(attributionText),
|
||||
}}
|
||||
url={`https://services.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}?token=${accessToken}`}
|
||||
tileSize={256}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const StrassentexteEsri = () => {
|
||||
return (
|
||||
<WMSTileLayer
|
||||
url="https://tiledbasemaps.arcgis.com/arcgis/rest/services/Reference/World_Transportation/MapServer/tile/{z}/{y}/{x}"
|
||||
format="image/png"
|
||||
transparent
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const OpenAIP = ({ attribution }: { attribution: Control.Attribution }) => {
|
||||
const accessToken = process.env.NEXT_PUBLIC_OPENAIP_ACCESS;
|
||||
const attributionText = '© <a href="https://www.openaip.net" target="_blank">OpenAIP</a>';
|
||||
|
||||
return (
|
||||
<TileLayer
|
||||
eventHandlers={{
|
||||
add: () => attribution.addAttribution(attributionText),
|
||||
remove: () => attribution.removeAttribution(attributionText),
|
||||
}}
|
||||
url={`https://api.tiles.openaip.net/api/data/openaip/{z}/{x}/{y}.png?apiKey=${accessToken}`}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const NiederschlagOverlay = ({ attribution }: { attribution: Control.Attribution }) => {
|
||||
let tileLayer: L.TileLayer | null = null;
|
||||
|
||||
useEffect(() => {
|
||||
if (tileLayer) {
|
||||
tileLayer.bringToFront();
|
||||
}
|
||||
}, [tileLayer]);
|
||||
|
||||
return (
|
||||
<WMSTileLayer
|
||||
ref={(layer) => {
|
||||
if (layer) {
|
||||
tileLayer = layer;
|
||||
}
|
||||
}}
|
||||
eventHandlers={{
|
||||
add: () => attribution.addAttribution("Quelle: Deutscher Wetterdienst"),
|
||||
remove: () => attribution.removeAttribution("Quelle: Deutscher Wetterdienst"),
|
||||
}}
|
||||
url="https://maps.dwd.de/geoserver/wms?"
|
||||
format="image/png"
|
||||
layers="dwd:Niederschlagsradar"
|
||||
transparent
|
||||
opacity={0.7}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const BaseMaps = () => {
|
||||
const map = useMap();
|
||||
@@ -14,16 +279,39 @@ export const BaseMaps = () => {
|
||||
}, [isPannelOpen]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<TileLayer
|
||||
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||
/>
|
||||
<TileLayer
|
||||
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||
className="invert-100 grayscale"
|
||||
/>
|
||||
</>
|
||||
<LayersControl position="topleft">
|
||||
<LayersControl.Overlay name={"Funknetzbereiche"}>
|
||||
<RadioAreaLayer />
|
||||
</LayersControl.Overlay>
|
||||
<LayersControl.Overlay name={"Niederschlag"}>
|
||||
<NiederschlagOverlay attribution={map.attributionControl} />
|
||||
</LayersControl.Overlay>
|
||||
|
||||
<LayersControl.Overlay name={"LRZs"}>
|
||||
<StationsLayer attribution={map.attributionControl} />
|
||||
</LayersControl.Overlay>
|
||||
<LayersControl.Overlay name={"OpenAIP"}>
|
||||
<OpenAIP attribution={map.attributionControl} />
|
||||
</LayersControl.Overlay>
|
||||
<LayersControl.BaseLayer name="OpenStreetMap" checked>
|
||||
<TileLayer
|
||||
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||
/>
|
||||
</LayersControl.BaseLayer>
|
||||
<LayersControl.BaseLayer name="OpenStreetMap Dark">
|
||||
<TileLayer
|
||||
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||
className="invert-100 grayscale"
|
||||
/>
|
||||
</LayersControl.BaseLayer>
|
||||
<LayersControl.BaseLayer name="ESRI Satellite">
|
||||
<LayerGroup>
|
||||
<EsriSatellite attribution={map.attributionControl} />
|
||||
<StrassentexteEsri />
|
||||
</LayerGroup>
|
||||
</LayersControl.BaseLayer>
|
||||
</LayersControl>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user