// components/MapComponent.js import React, { useEffect, useRef, useState } from "react"; import L, { marker } from "leaflet"; import "leaflet/dist/leaflet.css"; import "leaflet-contextmenu/dist/leaflet.contextmenu.css"; import "leaflet-contextmenu"; import * as config from "../config/config.js"; import dynamic from "next/dynamic"; import "leaflet.smooth_marker_bouncing"; import OverlappingMarkerSpiderfier from "overlapping-marker-spiderfier-leaflet"; import DataSheet from "../components/DataSheet"; import { useRecoilState, useRecoilValue } from "recoil"; import { gisStationsStaticDistrictState } from "../store/gisStationState"; import { gisSystemStaticState } from "../store/gisSystemState"; import { mapLayersState } from "../store/mapLayersState"; const MapComponent = ({ locations, onLocationUpdate }) => { const mapRef = useRef(null); // Referenz auf das DIV-Element der Karte const [map, setMap] = useState(null); // Zustand der Karteninstanz const [oms, setOms] = useState(null); // State für OMS-Instanz const [online, setOnline] = useState(navigator.onLine); // Zustand der Internetverbindung const [GisStationsStaticDistrict, setGisStationsStaticDistrict] = useRecoilState(gisStationsStaticDistrictState); const [GisStationsStatusDistrict, setGisStationsStatusDistrict] = useState( [] ); // Zustand für Statusdaten const [GisStationsMeasurements, setGisStationsMeasurements] = useState([]); // Zustand für Messdaten const [GisSystemStatic, setGisSystemStatic] = useRecoilState(gisSystemStaticState); // Zustand für Systemdaten const [DataIcons, setDataIcons] = useState([]); // Zustand für Icon-Daten // Konstanten für die URLs const mapGisStationsStaticDistrictUrl = config.mapGisStationsStaticDistrictUrl; const mapGisStationsStatusDistrictUrl = config.mapGisStationsStatusDistrictUrl; const mapGisStationsMeasurementsUrl = config.mapGisStationsMeasurementsUrl; const mapGisSystemStaticUrl = config.mapGisSystemStaticUrl; const mapDataIconUrl = config.mapDataIconUrl; // Funktion zum Aktualisieren der Position in der Datenbank const updateLocationInDatabase = async (id, newLatitude, newLongitude) => { const response = await fetch("/api/updateLocation", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ id, latitude: newLatitude, longitude: newLongitude, }), }); if (response.ok) { //schreib die neue Kooridnaten in die Console //akuellisiere die Position in der Datenbank mit den neuen Koordinaten mit updateLocation mit SQL Anweisung UPDATE } else { console.error("Fehler beim Aktualisieren der Position"); } }; // API-Daten laden für GisStationsStaticDistrict //http://10.10.0.13/talas5/ClientData/WebServiceMap.asmx/GisStationsStaticDistrict?idMap=10&idUser=485 useEffect(() => { const fetchData = async () => { try { const response = await fetch(mapGisStationsStaticDistrictUrl); const jsonResponse = await response.json(); // Prüfen, ob die Antwort das erwartete Format hat und Daten enthält if (jsonResponse && jsonResponse.Points) { setGisStationsStaticDistrict(jsonResponse.Points); // Direkter Zugriff auf 'Points' } else { console.error( 'Erwartete Daten im "Points"-Array nicht gefunden', jsonResponse ); setGisStationsStaticDistrict([]); } } catch (error) { console.error("Fehler beim Laden der Daten 1: ", error); setGisStationsStaticDistrict([]); } }; fetchData(); }, []); // Dependency-Array ist leer, um den Effekt nur beim Mount auszuführen //GisStationsStaticDistrict Daten laden useEffect(() => { const fetchData = async () => { try { const response = await fetch(mapGisStationsStaticDistrictUrl); const jsonResponse = await response.json(); // Prüfen, ob die Antwort das erwartete Format hat und Daten enthält if (jsonResponse && jsonResponse.Points) { setGisStationsStaticDistrict(jsonResponse.Points); // Direkter Zugriff auf 'Points' } else { console.error( 'Erwartete Daten im "Points"-Array nicht gefunden', jsonResponse ); setGisStationsStaticDistrict([]); } } catch (error) { console.error("Fehler beim Laden der Daten 1: ", error); setGisStationsStaticDistrict([]); } }; fetchData(); }, []); // Dependency-Array ist leer, um den Effekt nur beim Mount auszuführen //------------------------------------------ //GisStationsStatusDistrict Daten laden useEffect(() => { const fetchData = async () => { try { const response = await fetch(mapGisStationsStatusDistrictUrl); const jsonResponse = await response.json(); // Prüfen, ob die Antwort das erwartete Format hat und Daten enthält if (jsonResponse && jsonResponse.Statis) { setGisStationsStatusDistrict(jsonResponse.Statis); // Direkter Zugriff auf 'Statis' } else { console.error( 'Erwartete Daten im "Statis"-Array nicht gefunden', jsonResponse ); setGisStationsStatusDistrict([]); } } catch (error) { console.error("Fehler beim Laden der Daten 2: ", error); setGisStationsStatusDistrict([]); } }; fetchData(); }, []); // Dependency-Array ist leer, um den Effekt nur beim Mount auszuführen //------------------------------------------ //GisStationsMeasurements Daten laden useEffect(() => { const fetchData = async () => { try { const response = await fetch(mapGisStationsMeasurementsUrl); const jsonResponse = await response.json(); // Prüfen, ob die Antwort das erwartete Format hat und Daten enthält if (jsonResponse && jsonResponse.Statis) { setGisStationsMeasurements(jsonResponse.Statis); // Direkter Zugriff auf 'Statis' } else { console.error( 'Erwartete Daten im "Statis"-Array nicht gefunden', jsonResponse ); setGisStationsMeasurements([]); } } catch (error) { console.error("Fehler beim Laden der Daten 3: ", error); setGisStationsMeasurements([]); } }; fetchData(); }, []); // Dependency-Array ist leer, um den Effekt nur beim Mount auszuführen //------------------------------------------ //GisSystemStatic Daten laden useEffect(() => { const fetchData = async () => { try { const response = await fetch(mapGisSystemStaticUrl); const jsonResponse = await response.json(); // Prüfen, ob die Antwort das erwartete Format hat und Daten enthält if (jsonResponse && jsonResponse.Systems) { setGisSystemStatic(jsonResponse.Systems); // Direkter Zugriff auf 'Systems' console.log("GisSystemStatic:", jsonResponse.Systems); } else { console.error( 'Erwartete Daten im "Systems"-Array nicht gefunden', jsonResponse ); setGisSystemStatic([]); } } catch (error) { console.error("Fehler beim Laden der Daten 4: ", error); setGisSystemStatic([]); } }; fetchData(); }, []); // Dependency-Array ist leer, um den Effekt nur beim Mount auszuführen //------------------------------------------ const offlineTileLayer = "../TileMap/mapTiles/{z}/{x}/{y}.png"; const onlineTileLayer = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"; // Create map layers const TALAS = new L.layerGroup(); const ECI = new L.layerGroup(); const ULAF = new L.layerGroup(); const GSMModem = new L.layerGroup(); const CiscoRouter = new L.layerGroup(); const WAGO = new L.layerGroup(); const Siemens = new L.layerGroup(); const OTDR = new L.layerGroup(); const WDM = new L.layerGroup(); const GMA = new L.layerGroup(); const Sonstige = new L.layerGroup(); const TALASICL = new L.layerGroup(); useEffect(() => { if (typeof window !== "undefined") { console.log("Window height from config:", config.windowHeight); } }, []); // Funktionen zur Überwachung der Internetverbindung const checkInternet = () => { fetch("https://tile.openstreetmap.org/1/1/1.png", { method: "HEAD" }) .then((response) => setOnline(response.ok)) .catch(() => setOnline(false)); }; let initMap = []; // Initialisierung der karte und hinzuügen der Layers useEffect(() => { if (mapRef.current && !map) { initMap = L.map(mapRef.current, { center: [53.111111, 8.4625], zoom: 8, layers: [ TALAS, ECI, ULAF, GSMModem, CiscoRouter, WAGO, Siemens, OTDR, WDM, GMA, Sonstige, TALASICL, ], zoomControl: false, contextmenu: true, contextmenuItems: [ { text: "Station hinzufügen", callback: showAddStationPopup }, { text: "Station öffnen (Tab)", icon: "img/screen_new.png", callback: newLink, }, { text: "Station öffnen", icon: "img/screen_same.png", callback: sameLink, }, { text: "Koordinaten", icon: "img/screen_same.png", callback: lata, }, "-", // Divider { text: "Reinzoomen", callback: zoomIn }, { text: "Rauszoomen", callback: zoomOut }, { text: "Hier zentrieren", callback: centerHere }, ], }); L.tileLayer(online ? onlineTileLayer : offlineTileLayer, { attribution: '© OpenStreetMap contributors', }).addTo(initMap); const oms = new window.OverlappingMarkerSpiderfier(initMap, { nearbyDistance: 20, }); setMap(initMap); setOms(oms); // Nach der Initialisierung der Map und Setzen im State kannst du Funktionen aufrufen, die `map` benötigen. initMap.whenReady(() => { console.log("Karte ist jetzt bereit und initialisiert."); // Rufe hier Funktionen auf, die eine initialisierte Karte benötigen. }); } }, [mapRef, map]); // Prüfe die Abhängigkeiten sorgfältig //------------------------------------------ function parsePoint(pointString) { const match = pointString.match( /POINT\s*\((\d+(\.\d+)?)\s+(\d+(\.\d+)?)\)/ ); if (match) { return { longitude: parseFloat(match[1]), latitude: parseFloat(match[3]), // Achtung: Index 3 für die zweite Koordinate, wegen der Gruppe (\.\d+)? }; } else { // Handle the error or return a default/fallback value console.error("Invalid POINT format:", pointString); return null; // Oder eine sinnvolle Standardantwort } } //---------------------------------- //-----Kontextmenu---------------- const newLink = (e) => { try { if (!e.relatedTarget || !e.relatedTarget.options) { throw new Error("relatedTarget or options not defined"); } alert("Neues Fenster: " + e.relatedTarget.options.test); window .open(`../devices/${e.relatedTarget.options.test}`, "_blank") .focus(); } catch (error) { console.error("Failed in newLink function:", error); } }; const sameLink = (e) => { alert(e.relatedTarget.options.test); window .open("../devices/" + e.relatedTarget.options.test, "_parent") .focus(); }; const lata = (e) => { alert("Breitengrad: " + e.latlng.lat); }; const zoomIn = (e) => { initMap.flyTo(e.latlng, 12); }; const zoomOut = (e) => { fly(); }; const centerHere = (e) => { initMap.panTo(e.latlng); }; const showCoordinates = (e) => { alert("Breitengrad: " + e.latlng.lat + "\nLängengrad: " + e.latlng.lng); }; const showData = (e) => {}; const showTalas = (e) => { map.addLayer(TALAS); loadData(); }; const hideTalas = (e) => { map.removeLayer(TALAS); loadData(); }; const showGSM = (e) => { map.addLayer(GMA); loadData(); }; const hideGSM = (e) => { map.removeLayer(GMA); loadData(); }; //-----Kontextmenu----ende------------ // Ensure this function is only called when map is initialized and available const showAddStationPopup = (e) => { if (!newMap) { return; } const popupContent = L.DomUtil.create("div"); popupContent.innerHTML = `
`; L.popup().setLatLng(e.latlng).setContent(popupContent).openOn(newMap); // Attach event listener here L.DomEvent.on(popupContent, "submit", handleSubmit); }; // Funktion zum Hinzufügen eines neuen Standorts async function handleSubmit(event) { event.preventDefault(); const form = event.target; const data = { name: form.name.value, type: form.type.value, latitude: form.lat.value, longitude: form.lng.value, }; try { const response = await fetch("/api/addLocation", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(data), }); const result = await response.json(); if (response.ok) { alert("Standort erfolgreich hinzugefügt!"); form.reset(); // Formular zurücksetzen // Hier könntest du weitere Aktionen durchführen, wie das Schließen des Popups oder das Aktualisieren der Marker auf der Karte } else { throw new Error( result.error || "Ein unbekannter Fehler ist aufgetreten." ); } } catch (error) { console.error("Fehler beim Hinzufügen des Standorts:", error); alert(error.message); } } function fly(stationValue) { var x = 51.41321407879154; var y = 7.739617925303934; var zoom = 7; initMap.flyTo([x, y], zoom); } function getIconPath(status, iconNumber, marker) { let path = status ? `TileMap/img/icons/${status}-marker-icon-${iconNumber}.png` : `TileMap/img/icons/marker-icon-${iconNumber}.png`; // Wenn der Pfad das Wort "critical" oder "major" enthält, dann den Marker bouncing options setzen if ( path.includes("critical") || path.includes("major") || path.includes("minor") || path.includes("system") ) { // Setze Bouncing-Optionen marker.setBouncingOptions({ bounceHeight: 15, // Höhe des Bounces contractHeight: 12, // Höhe des Einzugs beim Landen bounceSpeed: 52, // Geschwindigkeit des Bounces contractSpeed: 52, // Geschwindigkeit des Einzugs shadowAngle: null, // Standard-Schattenwinkel }); // Check if the icon path includes 'critical' if (path.includes("critical")) { // marker.bounce(3); } } return path; } //useEffect zusammen von MySQL Daten bank und von APIs useEffect(() => { const fetchData = async () => { try { const responses = await Promise.all([ fetch(mapGisStationsStaticDistrictUrl), fetch(mapGisStationsStatusDistrictUrl), // Andere relevante API-Anfragen ]); const data = await Promise.all(responses.map((res) => res.json())); if (data[0] && data[0].Points) { setGisStationsStaticDistrict(data[0].Points); } else { console.error("Daten für GisStationsStaticDistrict nicht gefunden"); setGisStationsStaticDistrict([]); } if (data[1] && data[1].Statis) { setGisStationsStatusDistrict(data[1].Statis); } else { console.error("Daten für GisStationsStatusDistrict nicht gefunden"); setGisStationsStatusDistrict([]); } // Weitere Datenverarbeitung... } catch (error) { console.error("Fehler beim Laden der Daten: ", error); // Setzen Sie Zustände auf leere Arrays oder Fehlerzustände } }; fetchData(); }, []); //----------------------------------------------------------------- // TALAS Marker hinzufügen //----------------------------------------------------------------- const [talasVisible, setTalasVisible] = useRecoilState(mapLayersState); const [talasMarkers, setTalasMarkers] = useState([]); // Daten von einer externen Quelle laden useEffect(() => { async function fetchData() { try { const responses = await Promise.all([ fetch(config.mapGisStationsStaticDistrictUrl), fetch(config.mapGisStationsStatusDistrictUrl), ]); const [jsonResponse, statusResponse] = await Promise.all( responses.map((res) => res.json()) ); if ( jsonResponse && jsonResponse.Points && statusResponse && statusResponse.Statis ) { const statisMap = new Map( statusResponse.Statis.map((s) => [s.IdLD, s]) ); let markersData = jsonResponse.Points.filter( (p) => p.System === 1 ).map((p) => { const statis = statisMap.get(p.IdLD); const marker = L.marker([p.X, p.Y], { icon: L.icon({ iconUrl: statis ? `img/icons/${statis.Na}-marker-icon-${p.Icon}.png` : `img/icons/marker-icon-${p.Icon}.png`, iconSize: [25, 41], iconAnchor: [12, 41], popupAnchor: [1, -34], }), bounceOnAdd: !!statis, }); if (statis) { marker.on("add", () => marker.bounce(3)); } // Ein Popup und Tooltip mit Informationen zur Station binden marker.bindPopup( `Station: ${p.LD_Name}
Device: ${p.Device}` ); /* marker.bindTooltip( `
Station: ${p.LD_Name}
`, { permanent: false, direction: "top", } ); */ return marker; }); setTalasMarkers(markersData); } } catch (error) { console.error("Error fetching data: ", error); } } if (!map) return; fetchData(); }, [map]); // Abhängigkeit nur auf `map` setzen useEffect(() => { if (map && talasMarkers.length) { talasMarkers.forEach((marker) => { marker.addTo(map); oms.addMarker(marker); // Popup beim Überfahren mit der Maus öffnen und schließen marker.on("mouseover", function () { this.openPopup(); }); marker.on("mouseout", function () { this.closePopup(); }); }); map.addLayer(TALAS); } }, [map, talasMarkers]); // Abhängigkeiten auf `map` und `talasMarkers` beschränken console.log("talasMarkers", talasMarkers); //------------------------------------------- const mapLayersVisibility = useRecoilValue(mapLayersState); useEffect(() => { if (!map || !talasMarkers) return; const toggleLayer = (isVisible) => { if (isVisible) { talasMarkers.forEach((marker) => marker.addTo(map)); // Ensure markers are added } else { talasMarkers.forEach((marker) => map.removeLayer(marker)); // Remove markers individually } }; // Apply visibility state to the TALAS layer toggleLayer(mapLayersVisibility.TALAS); }, [map, talasMarkers, mapLayersVisibility.TALAS]); // Depend on map, markers array, and visibility state const handleCheckboxChange = (event) => { const { checked } = event.target; setMapLayersVisibility((prev) => ({ ...prev, TALAS: checked, })); }; //------------------------------------------ // Funktion zum Ein- und Ausblenden der TALAS-Marker basierend auf dem Zustand von mapLayersVisibility.TALAS useEffect(() => { if (!map || !talasMarkers) return; const toggleLayer = (isVisible) => { if (isVisible) { talasMarkers.forEach((marker) => marker.addTo(map)); // Ensure markers are added } else { talasMarkers.forEach((marker) => map.removeLayer(marker)); // Remove markers individually } }; // Apply visibility state to the TALAS layer toggleLayer(mapLayersVisibility.TALAS); }, [map, talasMarkers, mapLayersVisibility.TALAS]); //------------------------------------------ */ return ( <>
); }; export default MapComponent;