// 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;