// components/MapComponent.js import React, { useEffect, useRef, useState } from "react"; import L from "leaflet"; import "leaflet/dist/leaflet.css"; import "leaflet-contextmenu/dist/leaflet.contextmenu.css"; import "leaflet-contextmenu"; import * as config from "../config/config.js"; const MapComponent = ({ locations, onLocationUpdate }) => { const mapRef = useRef(null); // Referenz auf das DIV-Element der Karte const [map, setMap] = useState(null); // Zustand der Karteninstanz const [online, setOnline] = useState(navigator.onLine); // Zustand der Internetverbindung const [GisStationsStaticDistrict, setGisStationsStaticDistrict] = useState( [] ); // Zustand für statische Daten const [GisStationsStatusDistrict, setGisStationsStatusDistrict] = useState( [] ); // Zustand für Statusdaten const [GisStationsMeasurements, setGisStationsMeasurements] = useState([]); // Zustand für Messdaten const [GisSystemStatic, setGisSystemStatic] = useState([]); // 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 //------------------------------------------ //\talas5\TileMap\img\icons\icon1.png // minor-marker-icon-23.png // Marker hinzufügen für GisStationsStaticDistrict useEffect(() => { if (map && GisStationsStaticDistrict.length > 0) { // Zuerst alte Marker entfernen /* map.eachLayer((layer) => { if (layer instanceof L.Marker) { map.removeLayer(layer); } }); */ // Neue Marker für jede Station hinzufügen GisStationsStaticDistrict.forEach((station) => { const marker = L.marker([station.X, station.Y], { // X als Breitengrad, Y als Längengrad icon: L.icon({ iconUrl: getIconPath(station.Icon), iconSize: [25, 41], iconAnchor: [12, 41], popupAnchor: [1, -34], shadowSize: [41, 41], }), }).addTo(map); // Popup beim Überfahren mit der Maus öffnen marker.on("mouseover", function (e) { this.openPopup(); }); // Popup schließen, wenn die Maus den Marker verlässt marker.on("mouseout", function (e) { this.closePopup(); }); // Ein Popup mit Informationen zur Station hinzufügen marker .bindPopup(`${station.LD_Name}
${station.Device}`) .openPopup(); marker.bindTooltip( `
${station.LD_Name}
`, { permanent: false, direction: "top" } ); // Zugriff auf das Tooltip-Element und Anwendung von Stilen marker.on("mouseover", () => { document.querySelector(".tooltip-content").style.backgroundColor = "#ffffff"; document.querySelector(".tooltip-content").style.padding = "0.5rem"; document.querySelector(".tooltip-content").style.borderRadius = "0.25rem"; document.querySelector(".tooltip-content").style.border = "1px solid #d1d5db"; }); }); } }, [map, GisStationsStaticDistrict]); // Abhängigkeiten hinzufügen, um sicherzustellen, dass Effekt bei Änderungen neu ausgeführt wird //------------------------------------------ //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' } 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(); let initialMap = []; 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)); }; // Initialisiere die Karte useEffect(() => { if (mapRef.current && !map) { initialMap = L.map(mapRef.current, { center: [53.111111, 8.4625], zoom: 10, layers: [ TALAS, ECI, ULAF, GSMModem, CiscoRouter, WAGO, Siemens, OTDR, WDM, GMA, Sonstige, TALASICL, ], zoomControl: false, // Deaktiviere die Standard-Zoomsteuerung 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(initialMap); setMap(initialMap); } }, [mapRef, map]); // Handle online/offline status useEffect(() => { window.addEventListener("online", checkInternet); window.addEventListener("offline", checkInternet); return () => { window.removeEventListener("online", checkInternet); window.removeEventListener("offline", checkInternet); }; }, []); // Update map layers based on online status useEffect(() => { if (map) { const newLayer = L.tileLayer( online ? onlineTileLayer : offlineTileLayer, { minZoom: 7, maxZoom: online ? 19 : 14, attribution: 'Map data © OpenStreetMap contributors', } ); map.eachLayer((layer) => { if (layer instanceof L.TileLayer) { map.removeLayer(layer); } }); newLayer.addTo(map); } }, [online, map]); // Marker handling useEffect(() => { // Remove old markers if (map) { map.eachLayer((layer) => { if (layer instanceof L.Marker) { map.removeLayer(layer); } }); // Add new markers locations.forEach((location) => { const { latitude, longitude } = parsePoint(location.position); const marker = L.marker([latitude, longitude], { icon: L.icon({ iconUrl: "/location.svg", iconSize: [34, 34], iconAnchor: [17, 34], popupAnchor: [0, -34], }), draggable: true, id: location.idPoi, }); marker.bindPopup( `${location.description || "Unbekannt"}
Type: ${location.idPoiTyp || "N/A"}
Lat: ${latitude.toFixed(5)}, Lng: ${longitude.toFixed(5)}` ); marker.bindTooltip( `
${location.description}
`, { permanent: false, direction: "top" } ); marker.on("dragend", function (e) { const newLat = e.target.getLatLng().lat; const newLng = e.target.getLatLng().lng; const markerId = e.target.options.id; updateLocationInDatabase(markerId, newLat, newLng).then(() => { onLocationUpdate(markerId, newLat, newLng); }); }); marker.addTo(map); }); } }, [map, locations, onLocationUpdate]); //------------------------------------------ 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) => { initialMap.flyTo(e.latlng, 12); }; const zoomOut = (e) => { fly(); }; const centerHere = (e) => { initialMap.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 (!initialMap) { return; } const popupContent = L.DomUtil.create("div"); popupContent.innerHTML = `
`; L.popup().setLatLng(e.latlng).setContent(popupContent).openOn(initialMap); // Attach event listener here L.DomEvent.on(popupContent, "submit", handleSubmit); }; /* const 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, }; onAddLocation(name, type, lat, lng); console.log("Name: ", name, "Type: ", type, "Lat: ", lat, "Lng: ", lng); map.closePopup(); }; */ // 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; /* for (var i = 0; i < GisStationsStaticDistrictlength; i++) { var gisStatics = GisStationsStaticDistrict[i]; if (stationValue === gisStatics.Area_Name) { //console.log(gisStatics.X+","+gisStatics.Y); x = gisStatics.X; y = gisStatics.Y; } } if (y === 7.739617925303934) { zoom = 8; } */ initialMap.flyTo([x, y], zoom); /* var popup = new L.Popup(); oms.addListener("click", function (marker) { popup.setContent(marker.desc); popup.setLatLng(marker.getLatLng()); map.openPopup(popup); }); for (var i = 0; i < window.mapData.length; i++) { var datum = window.mapData[i]; var loc = new L.LatLng(datum.lat, datum.lon); var marker = new L.Marker(loc); marker.desc = datum.d; map.addLayer(marker); //oms.addMarker(marker); // <-- here } */ //------------------------------------- } //------------------------------------------ //Informationen in Tooltips einfügen // Marker hinzufügen für GisStationsStaticDistrict useEffect(() => { if (map && GisStationsStaticDistrict.length > 0) { map.eachLayer((layer) => { if (layer instanceof L.Marker) { map.removeLayer(layer); } }); GisStationsStaticDistrict.forEach((station) => { // Filtere alle Statusobjekte für diese station.Na const statusObjects = GisStationsStatusDistrict.filter( (status) => status.IdLD === station.IdLD ); // Alle Status-Objekte mit gleicher IdLD finden const matchingStatuses = GisStationsStatusDistrict.filter( (status) => status.IdLD === station.IdLD ); let status2 = ""; let statusInfo = ""; // Umdrehen der Reihenfolge der Statusmeldungen matchingStatuses.reverse().forEach((status) => { statusInfo += `
${status.Me} (${status.Na})
`; status2 = status.Na; }); let iconPath = getIconPath(status2, station.Icon); const marker = L.marker([station.X, station.Y], { icon: L.icon({ iconUrl: iconPath, iconSize: [25, 41], iconAnchor: [12, 41], popupAnchor: [1, -34], shadowSize: [41, 41], }), }).addTo(map); marker.on("mouseover", function (e) { this.openPopup(); }); marker.on("mouseout", function (e) { this.closePopup(); }); marker .bindPopup( `${station.LD_Name}
${station.Device}
${station.Area_Short} (${station.Area_Name})
${station.Location_Short} (${station.Location_Name})
${statusInfo}

` ) .openPopup(); }); } }, [map, GisStationsStaticDistrict, GisStationsStatusDistrict]); // Include GisStationsStatusDistrict in dependencies //------------------------------------------ // Funktion, die den Pfad zum entsprechenden Icon basierend auf dem Status generiert /* function getIconPath(status, iconId) { let prefix = ""; switch (status) { case "critical": prefix = "critical-marker-icon"; break; case "major": prefix = "major-marker-icon"; break; case "minor": prefix = "minor-marker-icon"; break; case "system": prefix = "system-marker-icon"; break; case "ok": default: prefix = "marker-icon"; // Annahme: "ok" ist der Standardstatus und grün break; } return `path/to/icons/${prefix}-${iconId}.png`; } */ //------------------------------------------ function getIconPath(status, iconNumber) { if (status) { // Wenn status vorhanden ist, füge ihn in den Pfad ein mit Bindestrich return `TileMap/img/icons/${status}-marker-icon-${iconNumber}.png`; } else { // Wenn kein status vorhanden ist, lasse den Status-Teil ganz weg return `TileMap/img/icons/marker-icon-${iconNumber}.png`; } } return (
); }; export default MapComponent;