Merge pull request 'feature/start-end-line-marker' (#1) from feature/start-end-line-marker into develop

Reviewed-on: http://10.10.0.12:3000/ISA/nodeMap/pulls/1
This commit is contained in:
ISA
2024-07-18 08:21:25 +02:00
35 changed files with 9071 additions and 1103 deletions

3
.babelrc Normal file
View File

@@ -0,0 +1,3 @@
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}

1
.gitignore vendored
View File

@@ -26,3 +26,4 @@ trace
# Ignore specific Next.js build files
pages-manifest.json
nodeMap für 13 am 16.07.2024.zip

32
Jenkinsfile vendored Normal file
View File

@@ -0,0 +1,32 @@
pipeline {
agent any
stages {
stage('Install Dependencies') {
steps {
// Installiere npm Abhängigkeiten
sh 'npm install'
}
}
stage('Run Tests') {
steps {
// Führt Ihre Tests aus
sh 'npm test'
}
}
}
post {
always {
// Archivieren Sie die Testberichte, wenn verfügbar
junit '**/test-results.xml'
}
success {
echo 'Die Tests wurden erfolgreich abgeschlossen!'
}
failure {
echo 'Einige Tests sind fehlgeschlagen.'
}
}
}

12
__mocks__/leaflet.js Normal file
View File

@@ -0,0 +1,12 @@
module.exports = {
map: () => ({
setView: jest.fn(),
addLayer: jest.fn(),
}),
tileLayer: () => ({
addTo: jest.fn(),
}),
marker: () => ({
addTo: jest.fn(),
}),
};

View File

@@ -0,0 +1,89 @@
// __tests__/MapComponent.test.js
// Ein einfacher Testfall, der sicherstellt, dass die Addition korrekt ist
test("simple addition", () => {
const a = 1;
const b = 2;
const c = a + b;
expect(c).toBe(3); // Überprüft, ob c gleich 3 ist
});
//import L from "leaflet";
//import { checkOverlappingMarkers } from "../utils/mapUtils"; // Passe den Pfad entsprechend an
/* describe("checkOverlappingMarkers", () => {
let map;
beforeEach(() => {
// Erstelle eine neue Leaflet-Karte für jeden Test
map = L.map(document.createElement("div"));
});
it("should group markers by coordinates and add plus icons for overlapping markers", () => {
// Erstelle einige Beispielmarker
const markers = [
L.marker([51.505, -0.09]),
L.marker([51.505, -0.09]),
L.marker([51.51, -0.1]),
];
const plusIcon = L.divIcon({ className: "plus-icon" });
// Rufe die Funktion auf
checkOverlappingMarkers(map, markers, plusIcon);
// Überprüfe, dass die Marker zu Gruppen hinzugefügt wurden
const overlappingGroups = map._layers;
expect(Object.keys(overlappingGroups).length).toBeGreaterThan(0);
// Überprüfe, dass die Plus-Marker hinzugefügt wurden
const plusMarkers = Object.values(overlappingGroups).filter(
(layer) =>
layer.options.icon &&
layer.options.icon.options.className === "plus-icon"
);
expect(plusMarkers.length).toBeGreaterThan(0);
});
it("should handle non-array markers argument gracefully", () => {
const plusIcon = L.divIcon({ className: "plus-icon" });
// Rufe die Funktion mit einem ungültigen Argument auf
checkOverlappingMarkers(map, null, plusIcon);
// Stelle sicher, dass keine Marker hinzugefügt wurden
const layers = map._layers;
expect(Object.keys(layers).length).toBe(0);
});
it("should not add plus markers if there are no overlaps", () => {
// Erstelle einige Beispielmarker
const markers = [
L.marker([51.505, -0.09]),
L.marker([51.51, -0.1]),
L.marker([51.52, -0.12]),
];
const plusIcon = L.divIcon({ className: "plus-icon" });
// Rufe die Funktion auf
checkOverlappingMarkers(map, markers, plusIcon);
// Überprüfe, dass keine Plus-Marker hinzugefügt wurden
const plusMarkers = Object.values(map._layers).filter(
(layer) =>
layer.options.icon &&
layer.options.icon.options.className === "plus-icon"
);
expect(plusMarkers.length).toBe(0);
});
}); */
/*
In diesem Test:
Wird eine neue Leaflet-Karte vor jedem Test erstellt.
checkOverlappingMarkers wird aufgerufen, um zu überprüfen, ob die Funktion die Marker richtig gruppiert und Plus-Icons für überlappende Marker hinzufügt.
Der Test überprüft auch, ob die Funktion ungültige Argumente (wie null für Marker) korrekt behandelt.
Es wird sichergestellt, dass keine Plus-Marker hinzugefügt werden, wenn keine Überlappungen vorliegen.
Stelle sicher, dass du die Pfade und Importe entsprechend deiner Projektstruktur anpasst.
*/

3
babel.config.js Normal file
View File

@@ -0,0 +1,3 @@
module.exports = {
presets: ["@babel/preset-env", "@babel/preset-react"],
};

13
components/CircleIcon.js Normal file
View File

@@ -0,0 +1,13 @@
// /components/CircleIcon.js
// Custom circle icon for draggable markers
import L from "leaflet";
import "leaflet/dist/leaflet.css";
const circleIcon = L.divIcon({
className: "custom-div-icon",
html: "<div style='background-color:gray;border-radius:50%;width:10px;height:10px;border: solid black 1px;'></div>",
iconSize: [25, 25],
iconAnchor: [5, 5],
});
export default circleIcon;

10
components/EndIcon.js Normal file
View File

@@ -0,0 +1,10 @@
// Custom circle icon for draggable markers
import L from "leaflet";
const endIcon = L.divIcon({
className: "custom-end-icon",
html: "<div style='background-color: gray; width: 14px; height: 14px; border: solid black 2px;'></div>", // Graues Viereck
iconSize: [14, 14],
iconAnchor: [7, 7], // Mittelpunkt des Vierecks als Anker
});
export default endIcon;

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
// pages/api/poiUpdateModal.js
//
import React, { useState, useEffect } from "react";
import { useRecoilValue } from "recoil";
import { selectedPoiState } from "../store/atoms/poiState";
@@ -15,52 +15,24 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
const [locationDeviceData, setLocationDeviceData] = useState([]);
const [deviceName, setDeviceName] = useState("");
const [idLD, setIdLD] = useState(poiData ? poiData.idLD : "");
const [idLocationDevice, setIdLocationDevice] = useState("");
const [description, setDescription] = useState(
poiData ? poiData.description : ""
);
// Log the initial POI data
useEffect(() => {
if (poiData) {
console.log("Initial poiData:", poiData);
setPoiId(poiData.idPoi);
setName(poiData.name);
setPoiTypeId(poiData.idPoiTyp);
setIdLD(poiData.idLD);
setDescription(poiData.description);
setDeviceName(poiData.idLD);
console.log("Loaded POI Data for editing:", poiData);
console.log("POI ID:", poiData.idPoi);
console.log("POI Name:", poiData.name);
console.log("POI Typ ID:", poiData.idPoiTyp);
console.log("POI Beschreibung:", poiData.description);
console.log("POI Geräte-ID:", poiData.idLD);
}
}, [poiData]);
/* const fetchDeviceNameById = async (idLD) => {
try {
const response = await fetch(`/api/getDeviceNameById?idLD=${idLD}`);
const data = await response.json();
setDeviceName(data.deviceName);
} catch (error) {
console.error("Error fetching device name:", error);
}
}; */
/* const fetchDeviceNameById = async (idLD) => {
try {
const response = await fetch(`/api/talas_v5_DB/locationDevice/locationDeviceNameById?idLD=${idLD}`);
const data = await response.json();
setDeviceName(data.deviceName);
} catch (error) {
console.error("Error fetching device name:", error);
}
}; */
// Beim Öffnen des Modals die Geräte-ID basierend auf dem Gerätenamen abrufen, wenn vorhanden
useEffect(() => {
const fetchDeviceId = async () => {
if (poiData && poiData.idLD) {
@@ -82,7 +54,6 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
fetchDeviceId();
}, [poiData]);
// Function to handle deleting a POI
const handleDeletePoi = async () => {
if (confirm("Sind Sie sicher, dass Sie diesen POI löschen möchten?")) {
try {
@@ -94,8 +65,7 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
);
if (response.ok) {
alert("POI wurde erfolgreich gelöscht.");
onClose(); // Close the modal
//Browser neu laden, um die aktualisierte Liste anzuzeigen
onClose();
window.location.reload();
} else {
throw new Error("Fehler beim Löschen des POI.");
@@ -107,7 +77,6 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
}
};
// Fetch POI types
useEffect(() => {
const fetchPoiTypData = async () => {
try {
@@ -127,22 +96,20 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
fetchPoiTypData();
}, [selectedPoi]);
// Fetch device data um den Gerät Namen in den dropdown menu anzuzeigen also erstmal die Liste der Geräte abrufen
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch("/api/talas_v5/location_device");
// const response = await fetch("/api/talas_v5/location_device"); //"/api/talas_v5_DB/locationDevice/location_device"
const response = await fetch(
"/api/talas_v5_DB/locationDevice/locationDevices"
);
const data = await response.json();
//console.log("Standort- und Gerätedaten:", data);
setLocationDeviceData(data);
console.log("Standort- und Gerätedaten poiData:", poiData);
if (poiData && poiData.idLD) {
const selectedDevice = data.find(
(device) => device.id === poiData.idLD
);
setDeviceName(selectedDevice ? selectedDevice.id : data[0].id); // Hier wird die ID als initialer Zustand gesetzt
console.log("Selected Device:", selectedDevice);
console.log("Selected devciceName:", deviceName);
setDeviceName(selectedDevice ? selectedDevice.id : data[0].id);
}
} catch (error) {
console.error(
@@ -153,18 +120,12 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
};
fetchData();
}, []);
//--------------------------------------------------------------------------------------------
// Fetch device name basierend auf der Geräte-ID
useEffect(() => {
console.log("currentPoi von PoiUpdateModal.js : ", currentPoi.idLD);
fetch("/api/talas_v5_DB/locationDevice/locationDevices")
.then((response) => response.json())
.then((data) => {
setLocationDeviceData(data);
console.log("Standort- und Gerätedaten 3:", data);
console.log("Standort- und Gerätedaten 3 poiData:", poiData);
// Findet das Gerät, das der aktuellen IDLD entspricht
const currentDevice = data.find(
(device) => device.idLD === currentPoi.idLD
);
@@ -178,10 +139,6 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
});
}, [poiData?.idLD, currentPoi]);
//--------------------------------------------------------------------------------------------
// Angenommen, deviceName enthält die Geräte-ID
//const idLD = deviceName; // Stellen Sie sicher, dass dies eine ID ist und kein Name
const handleSubmit = async (event) => {
event.preventDefault();
const idLDResponse = await fetch(
@@ -201,7 +158,6 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
description: description,
idPoiTyp: poiTypeId,
idLD: idLD,
//idLD: parseInt(deviceName, 10), // Konvertieren in eine Ganzzahl
}),
});
@@ -220,19 +176,6 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
}
};
//ausgewählte poi Informationen in Console anzeigen
console.log("Selected POI:", selectedPoi);
console.log("Selected POI Gerät id in poiUpdateModal.js:", selectedPoi.id);
console.log("Selected POI Typ name in poiUpdateModal.js:", selectedPoi.typ); //als Typ in dropdown menu
console.log(
"Selected POI Beschreibung in poiUpdateModal.js:",
selectedPoi.description
);
console.log(
"Selected POI Gerät deviceId in poiUpdateModal.js:",
selectedPoi.deviceId
);
return (
<form onSubmit={handleSubmit} className="m-0 p-2 w-full">
<div className="flex items-center mb-4">
@@ -261,16 +204,11 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
onChange={(e) => setDeviceName(e.target.value)}
className="block p-2 w-full border-2 border-gray-200 rounded-md text-sm"
>
{locationDeviceData.map(
(device, index) => (
console.log("device.id und name:", device),
(
<option key={index} value={device.id}>
{device.name}
</option>
)
)
)}
{locationDeviceData.map((device, index) => (
<option key={index} value={device.id}>
{device.name}
</option>
))}
</select>
</div>
@@ -294,7 +232,7 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
</div>
<button
type="button" // Use button type to prevent form submission
type="button"
onClick={handleDeletePoi}
className="bg-red-400 hover:bg-red-600 text-white font-bold py-2 px-4 rounded w-full mb-4"
>

View File

@@ -109,6 +109,9 @@ const ShowAddStationPopup = ({ onClose, map, latlng }) => {
onClose();
return newTrigger;
});
// Browser aktualisieren
window.location.reload();
} else {
console.error("Fehler beim Hinzufügen des POI");
}
@@ -117,6 +120,7 @@ const ShowAddStationPopup = ({ onClose, map, latlng }) => {
map.closePopup();
}
};
//-----------------handleSubmit-------------------
return (

16
components/StartIcon.js Normal file
View File

@@ -0,0 +1,16 @@
// Custom triangle icon for draggable markers
import L from "leaflet";
const startIcon = L.divIcon({
className: "custom-start-icon",
html: `
<svg width="18" height="18" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<polygon points="10,2 18,18 2,18" fill="black" />
<polygon points="10,5 16,16 4,16" fill="gray" />
</svg>
`, // Schwarzes Dreieck innerhalb eines grauen Dreiecks
iconSize: [18, 18],
iconAnchor: [9, 18],
});
export default startIcon;

View File

@@ -0,0 +1,22 @@
import { useState, useCallback } from "react";
const useMapContextMenu = (map, hasRights, addStationCallback) => {
const [menuItemAdded, setMenuItemAdded] = useState(false);
const addItemsToMapContextMenu = useCallback(() => {
if (map && !menuItemAdded) {
map.contextmenu.addItem({
text: "POI hinzufügen",
icon: "img/add_station.png",
className: "background-red",
callback: (event) => addStationCallback(event, hasRights),
});
setMenuItemAdded(true); // Menüpunkt wurde hinzugefült, Zustand aktualisieren
}
}, [map, menuItemAdded, hasRights, addStationCallback]);
return { addItemsToMapContextMenu };
};
export default useMapContextMenu;

View File

@@ -1,11 +1,14 @@
// Definieren der grundlegenden Umgebungseinstellungen und Konfigurationen der Karte
// /config/config.js
// Definieren der grundlegenden Umgebungseinstellungen und Konfigurationen der Karte
const mapVersion = "0.5.3"; // Die Version der verwendeten Karte
const standardSideMenu = true; // Einstellung, ob ein standardmäßiges Seitenmenü verwendet wird
const fullSideMenu = false; // Einstellung, ob ein vollständiges Seitenmenü verwendet wird
const serverURL = "/api"; // Die Basis-URL des Servers, von dem Daten bezogen werden
//const serverURL = "/api"; // Die Basis-URL des Servers, von dem Daten bezogen werden
const serverURL = "http://10.10.0.13";
console.log("serverURL in config:", serverURL);
// Initialisieren von Variablen, die später im Browserkontext gesetzt werden
let windowHeight, url_string, url, c, user;
let windowHeight, url_string, url, idMap, idUser;
//Online Daten
let mapGisStationsStaticDistrictUrl,
mapGisStationsStatusDistrictUrl,
@@ -20,28 +23,30 @@ if (typeof window !== "undefined") {
windowHeight = window.innerHeight; // Die Höhe des Browserfensters
url_string = window.location.href; // Die vollständige URL als String
url = new URL(url_string); // Die URL als URL-Objekt, um Teile der URL einfacher zu handhaben
c = url.searchParams.get("m"); // Ein Parameter aus der URL, Standardwert ist '10'
user = url.searchParams.get("u"); // Ein weiterer Parameter aus der URL, Standardwert ist '484 admin zu testen von Stationen ausblenden und einblenden in der Card'
console.log("URL in config:", url);
console.log("URL origin in config:", url.origin); //http://localhost:3000
idMap = url.searchParams.get("m"); // Ein Parameter aus der URL, Standardwert ist '10'
idUser = url.searchParams.get("u"); // Ein weiterer Parameter aus der URL, Standardwert ist '484 admin zu testen von Stationen ausblenden und einblenden in der Card'
console.log(`Parameter 'idMap' : ${c}`);
console.log(`Parameter 'idUser': ${user}`);
console.log(`Parameter 'idMap' : ${c}`);
console.log(`Parameter 'idUser': ${user}`);
console.log(`Parameter 'idMap' : ${idMap}`);
console.log(`Parameter 'idUser': ${idUser}`);
// Konstruktion von URLs, die auf spezifische Ressourcen auf dem Server zeigen
//http://localhost:3000/?m=10&u=485
//-----------------Von WebService------------------------------------------------
mapGisStationsStaticDistrictUrl = `${serverURL}/talas5/ClientData/WebserviceMap.asmx/GisStationsStaticDistrict?idMap=${c}&idUser=${user}`; //idMap: 10, idUser: 484
mapGisStationsStatusDistrictUrl = `${serverURL}/talas5/ClientData/WebserviceMap.asmx/GisStationsStatusDistrict?idMap=${c}&idUser=${user}`;
mapGisStationsMeasurementsUrl = `${serverURL}/talas5/ClientData/WebserviceMap.asmx/GisStationsMeasurements?idMap=${c}`;
mapGisSystemStaticUrl = `${serverURL}/talas5/ClientData/WebserviceMap.asmx/GisSystemStatic?idMap=${c}&idUser=${user}`;
mapGisStationsStaticDistrictUrl = `${serverURL}/talas5/ClientData/WebserviceMap.asmx/GisStationsStaticDistrict?idMap=${idMap}&idUser=${idUser}`; //idMap: 10, idUser: 484
mapGisStationsStatusDistrictUrl = `${serverURL}/talas5/ClientData/WebserviceMap.asmx/GisStationsStatusDistrict?idMap=${idMap}&idUser=${idUser}`;
mapGisStationsMeasurementsUrl = `${serverURL}/talas5/ClientData/WebserviceMap.asmx/GisStationsMeasurements?idMap=${idMap}`;
mapGisSystemStaticUrl = `${serverURL}/talas5/ClientData/WebserviceMap.asmx/GisSystemStatic?idMap=${idMap}&idUser=${idUser}`;
mapDataIconUrl = `${serverURL}/talas5/ClientData/WebserviceMap.asmx/GetIconsStatic`;
//webserviceGisLinesStatusUrl = `http://10.10.0.13/talas5/ClientData/WebServiceMap.asmx/GisLinesStatus?idMap=${c}`;
//webserviceGisLinesStatusUrl = `http://10.10.0.13/talas5/ClientData/WebServiceMap.asmx/GisLinesStatus?idMap=${idMap}`;
//webserviceGisLinesStatusUrl = `http://localhost:3000/api/linesColorApi`;
//webserviceGisLinesStatusUrl = `http://localhost:3000/api/linesColorApi`;
//webserviceGisLinesStatusUrl = `${"serverURL"}:3000/api/linesColorApi`;
webserviceGisLinesStatusUrl = `http://localhost:3000/api/linesColorApi`;
//webserviceGisLinesStatusUrl = `http://192.168.10.14/talas5/ClientData/WebServiceMap.asmx/GisLinesStatus?idMap=${c}`;
//webserviceGisLinesStatusUrl = `http://192.168.10.14/talas5/ClientData/WebServiceMap.asmx/GisLinesStatus?idMap=${idMap}`;
//http://10.10.0.13/talas5/ClientData/WebserviceMap.asmx/GisSystemStatic?idMap=12&idUser=484
@@ -51,11 +56,11 @@ if (typeof window !== "undefined") {
mapGisSystemStaticUrl = `${serverURL}/talas5/ClientData/WebserviceMap.asmx/GisSystemStatic`;
mapDataIconUrl = `${serverURL}/talas5/ClientData/WebserviceMap.asmx/GetIconsStatic`; */
/* mapGisStationsStaticDistrictUrl = `${serverURL}/api/talas5/webserviceMap/GisStationsStaticDistrict?idMap=${c}&idUser=${user}`;
mapGisStationsStatusDistrictUrl = `${serverURL}/api/talas5/webserviceMap/GisStationsStatusDistrict?idMap=${c}&idUser=${user}`;
mapGisStationsMeasurementsUrl = `${serverURL}/api/talas5/webserviceMap/GisStationsMeasurements?idMap=${c}`;
mapGisStationsMeasurementsUrl = `${serverURL}/api/talas5/webserviceMap/gisStationsMeasurementsSQL?idMap=${c}`;
mapGisSystemStaticUrl = `${serverURL}/api/talas5/webserviceMap/GisSystemStatic?idMap=${c}&idUser=${user}`;
/* mapGisStationsStaticDistrictUrl = `${serverURL}/api/talas5/webserviceMap/GisStationsStaticDistrict?idMap=${idMap}&idUser=${idUser}`;
mapGisStationsStatusDistrictUrl = `${serverURL}/api/talas5/webserviceMap/GisStationsStatusDistrict?idMap=${idMap}&idUser=${idUser}`;
mapGisStationsMeasurementsUrl = `${serverURL}/api/talas5/webserviceMap/GisStationsMeasurements?idMap=${idMap}`;
mapGisStationsMeasurementsUrl = `${serverURL}/api/talas5/webserviceMap/gisStationsMeasurementsSQL?idMap=${idMap}`;
mapGisSystemStaticUrl = `${serverURL}/api/talas5/webserviceMap/GisSystemStatic?idMap=${idMap}&idUser=${idUser}`;
mapDataIconUrl = `${serverURL}/api/talas5/webserviceMap/GetIconsStatic`; */
}
@@ -68,8 +73,8 @@ export {
windowHeight,
url_string,
url,
c,
user,
idMap,
idUser,
mapGisStationsStaticDistrictUrl,
mapGisStationsStatusDistrictUrl,
mapGisStationsMeasurementsUrl,
@@ -77,3 +82,9 @@ export {
mapDataIconUrl,
webserviceGisLinesStatusUrl,
};
/*
Access to fetch at 'http://localhost:3000/api/linesColorApi' from origin 'http://10.10.0.13:3000' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
*/

17
config/layers.js Normal file
View File

@@ -0,0 +1,17 @@
import L from "leaflet";
export const MAP_LAYERS = {
TALAS: new L.layerGroup(),
ECI: new L.layerGroup(),
ULAF: new L.layerGroup(),
GSMModem: new L.layerGroup(),
CiscoRouter: new L.layerGroup(),
WAGO: new L.layerGroup(),
Siemens: new L.layerGroup(),
OTDR: new L.layerGroup(),
WDM: new L.layerGroup(),
GMA: new L.layerGroup(),
Sonstige: new L.layerGroup(),
TALASICL: new L.layerGroup(),
lineLayer: new L.LayerGroup(),
};

5
config/settings.js Normal file
View File

@@ -0,0 +1,5 @@
// /config/settings.js
// Definieren der grundlegenden Umgebungseinstellungen und Konfigurationen der Karte
export const MAP_VERSION = "1.0.0";
//export const STANDARD_SIDE_MENU = true;
//export const FULL_SIDE_MENU = false;

36
config/urls.js Normal file
View File

@@ -0,0 +1,36 @@
// /sonstige/urls.js
// BASE_URL für Station öffnen in neuer tab und gleicher tab, im localhost gab es keine Probleme mit der Frame
//export const BASE_URL = "http://10.10.0.13/talas5/devices/";
//const baseUrl = "http://localhost:3000/talas5/devices/";
//const baseUrl = "http://192.168.10.14/talas5/devices/";
//----
//Talas_v5 Server
//export const OFFLINE_TILE_LAYER = "/mapTiles/{z}/{x}/{y}.png"; // wenn im von localhost also selben Server die Karte angezeigt wird
//export const OFFLINE_TILE_LAYER = "/mapTiles/{z}/{x}/{y}.png";
export const BASE_URL = "http://10.10.0.13/talas5/devices/";
export const OFFLINE_TILE_LAYER = "/mapTiles/{z}/{x}/{y}.png";
export const ONLINE_TILE_LAYER =
"http://10.10.0.13:3000/mapTiles/{z}/{x}/{y}.png"; //Talas_v5 Server */
//-----------------------------------
// weil ich keine API habe, ansonsten serverURL ist localhost(IP-Adresse) für GisSystemStatic für die Benutzerrechte
//const serverURL = `${protocol}//${hostname}`;
//const serverURL = `${protocol}//${hostname}${port ? `:${port}` : ""}`;
//const serverURL = "http://localhost:3000";
export const SERVER_URL = "http://10.10.0.13";
// Online Daten URLs
/* export const MAP_GIS_STATIONS_STATIC_DISTRICT_URL = `${SERVER_URL}/talas5/ClientData/WebserviceMap.asmx/GisStationsStaticDistrict?idMap=${c}&idUser=${user}`; //idMap: 10, idUser: 484
export const MAP_GIS_STATIONS_STATUS_DISTRICT_URL = `${SERVER_URL}/talas5/ClientData/WebserviceMap.asmx/GisStationsStatusDistrict?idMap=${c}&idUser=${user}`;
export const MAP_GIS_STATIONS_MEASUREMENTS_URL = `${SERVER_URL}/talas5/ClientData/WebserviceMap.asmx/GisStationsMeasurements?idMap=${c}`;
export const MAP_GIS_SYSTEM_STATIC_URL = `${SERVER_URL}/talas5/ClientData/WebserviceMap.asmx/GisSystemStatic?idMap=${c}&idUser=${user}`;
export const MAP_DATA_ICON_URL = `${SERVER_URL}/talas5/ClientData/WebserviceMap.asmx/GetIconsStatic`;
export const WEBSERVICE_GIS_LINES_STATUS_URL =
"http://localhost:3000/api/linesColorApi";
*/
/*
Access to fetch at 'http://localhost:3000/api/linesColorApi' from origin 'http://10.10.0.13:3000' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
*/

13
jest.config.js Normal file
View File

@@ -0,0 +1,13 @@
module.exports = {
setupFilesAfterEnv: ["<rootDir>/setupTests.js"],
transform: {
"^.+\\.(js|jsx)$": "babel-jest",
},
transformIgnorePatterns: [
"/node_modules/(?!(@react-leaflet|react-leaflet|leaflet)/)",
],
testEnvironment: "jsdom",
moduleNameMapper: {
"\\.(css|less|scss|sass)$": "identity-obj-proxy",
},
};

1
jest.setup.js Normal file
View File

@@ -0,0 +1 @@
import "@testing-library/jest-dom";

Binary file not shown.

7834
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -10,8 +10,9 @@
"mysql": "^2.18.1",
"mysql2": "^3.10.1",
"next": "^14.2.3",
"nextjs-cors": "^2.2.0",
"overlapping-marker-spiderfier-leaflet": "^0.2.7",
"react": "^18.2.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-leaflet": "^4.2.1",
"react-toastify": "^10.0.5",
@@ -21,15 +22,26 @@
"dev": "next dev",
"build": "next build",
"start": "next start",
"export": "next export"
"export": "next export",
"test": "jest"
},
"devDependencies": {
"@babel/core": "^7.24.7",
"@babel/preset-env": "^7.24.7",
"@babel/preset-react": "^7.24.7",
"@testing-library/jest-dom": "^6.4.6",
"@testing-library/react": "^16.0.0",
"@types/leaflet": "^1.9.12",
"@types/leaflet-contextmenu": "^1.4.3",
"@types/react": "^18.3.1",
"@types/react-dom": "^18.3.0",
"autoprefixer": "^10.4.19",
"postcss": "^8.4.38",
"babel-jest": "^29.7.0",
"identity-obj-proxy": "^3.0.0",
"jest": "^29.7.0",
"jest-css-modules-transform": "^4.4.2",
"jest-environment-jsdom": "^29.7.0",
"postcss": "^8.4.39",
"prettier": "^3.2.5",
"tailwindcss": "^3.4.3"
}

View File

@@ -1,5 +1,6 @@
// Pfad: pages/_app.js
import { RecoilRoot } from 'recoil';
import React from "react";
import { RecoilRoot } from "recoil";
import "../styles/global.css";
function MyApp({ Component, pageProps }) {

View File

@@ -2,7 +2,18 @@
// http://10.10.0.13/talas5/ClientData/WebServiceMap.asmx/GisStationsStatusDistrict
//In DB gis_lines idLD und idModul anpassen entsprechend
export default function handler(req, res) {
// /pages/api/linesColorApi.js
import NextCors from "nextjs-cors";
export default async function handler(req, res) {
// Run the cors middleware
await NextCors(req, res, {
// Options
methods: ["GET", "HEAD", "PUT", "PATCH", "POST", "DELETE"],
origin: "*", // Erlauben Sie alle Ursprünge, oder geben Sie spezifische Ursprünge an
optionsSuccessStatus: 200, // Legacy-Browser-Unterstützung für 204
});
const response = {
Name: "Liste aller Statis der Linien",
Zeitstempel: new Date().toISOString(), // Aktuellen Zeitstempel hinzufügen

View File

@@ -1,8 +1,7 @@
// pages/index.js
import { useEffect, useState } from "react";
import React, { useEffect, useState } from "react";
import dynamic from "next/dynamic";
import { useRecoilState, useRecoilValue } from "recoil";
import { readPoiMarkersStore } from "../store/selectors/readPoiMarkersStore"; // Aktualisiert mit atom
import { readPoiMarkersStore } from "../store/selectors/readPoiMarkersStore";
import { poiReadFromDbTriggerAtom } from "../store/atoms/poiReadFromDbTriggerAtom";
const MapComponentWithNoSSR = dynamic(
@@ -24,14 +23,12 @@ export default function Home() {
}
const data = await response.json();
setLocations(data);
//console.log("Geladene Daten in Home.js:", data);
} catch (error) {
console.error(error.message);
}
};
useEffect(() => {
// URL-Parameter abfragen
function getURLParameter(name) {
const params = new URLSearchParams(window.location.search);
return params.get(name);
@@ -39,10 +36,7 @@ export default function Home() {
setMParam(getURLParameter("m"));
setUParam(getURLParameter("u"));
// Daten beim Laden der Seite holen
loadData();
//console.log("poiReadTrigger in Home.js:", poiReadTrigger);
}, [poiReadTrigger]);
const handleAddLocation = async (name, type, lat, lng) => {
@@ -56,8 +50,7 @@ export default function Home() {
throw new Error("Fehler beim Hinzufügen des Standorts");
}
console.log("Standort erfolgreich hinzugefügt");
loadData(); // Aktualisiere die Daten nach dem Hinzufügen
console.log("poiReadTrigger in Home.js:", poiReadTrigger);
loadData();
} catch (error) {
console.error(error.message);
}
@@ -72,13 +65,11 @@ export default function Home() {
)
);
};
//------------------------------------
// Daten beim Laden der Seite holen
useEffect(() => {
loadData();
//console.log("poiReadTrigger in Home.js:", poiReadTrigger);
}, [poiReadTrigger]);
//------------------------------------
return (
<div>
<MapComponentWithNoSSR

142
services/apiService.js Normal file
View File

@@ -0,0 +1,142 @@
// services/apiService.js
import * as config from "../config/config";
import { setPriorityConfig } from "../utils/utils";
import * as urls from "../config/urls";
export const fetchGisStatusStations = async (idMap, idUser) => {
try {
const response = await fetch(
`/api/talas5/webserviceMap/GisStationsStatusDistrict?idMap=${idMap}&idUser=${idUser}`
);
if (!response.ok) {
throw new Error(`Error: ${response.statusText}`);
}
const data = await response.json();
console.log("GisStatusStations:", data);
return data;
} catch (error) {
console.error("Fehler beim Abrufen der Daten:", error);
throw error; // Fehler weiter werfen, um ihn in der Komponente behandeln zu können
}
};
// ----------------------------------------------
export const fetchPriorityConfig = async () => {
try {
const response = await fetch("/api/talas_v5_DB/priorityConfig");
const data = await response.json();
console.log("Prioritätskonfiguration:", data);
setPriorityConfig(data);
} catch (error) {
console.error("Fehler beim Laden der Prioritätskonfiguration:", error);
}
};
// ----------------------------------------------
export const fetchPoiData = async (idPoi) => {
try {
const response = await fetch(
`/api/talas_v5_DB/pois/getPoiById?idPoi=${idPoi}`
);
if (!response.ok) {
throw new Error("Fehler beim Abrufen der POI-Daten");
}
const data = await response.json();
return {
idPoi,
name: data.name,
description: data.description,
};
} catch (error) {
console.error("Fehler beim Abrufen der POI-Daten", error);
return null;
}
};
// ----------------------------------------------
// Funktion zum Aktualisieren der Position in der Datenbank
export const updateLocationInDatabase = async (
id,
newLatitude,
newLongitude
) => {
const response = await fetch("/api/talas_v5_DB/pois/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");
}
};
// ----------------------------------------------
// Funktionen zur Überwachung der Internetverbindung
export const checkInternet = () => {
fetch("https://tile.openstreetmap.org/1/1/1.png", { method: "HEAD" })
.then((response) => setOnline(response.ok))
.catch(() => setOnline(false));
};
// ----------------------------------------------
export const fetchDeviceNameById = async (idLD) => {
try {
const response = await fetch(
`/api/talas_v5_DB/locationDevice/locationDeviceNameById?idLD=${idLD}`
);
const data = await response.json();
if (response.ok) {
return data.name;
} else {
throw new Error(data.error || "Gerät nicht gefunden");
}
} catch (error) {
/* console.error(
"Fehler beim Abrufen des Gerätenamens in MapComponent.js:",
error
); */
return "Unbekannt";
}
};
// ----------------------------------------------
// services/apiService.js
export const fetchUserRights = async () => {
try {
const response = await fetch(
`${urls.SERVER_URL}/talas5/ClientData/WebserviceMap.asmx/GisSystemStatic?idMap=${config.idMap}&idUser=${config.idUser}`
);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
// console.log("Benutzerrechte in fetchRights:", data);
// Überprüfen der Struktur der Antwort
if (!data || !data.Rights || !Array.isArray(data.Rights)) {
throw new Error("Invalid response structure");
}
const rightsArray = data.Rights; // Nehmen an, dass 'Rights' das Array von Rechten ist
//console.log("rightsArray in apiService:", rightsArray);
// Speichert die IDs der Rechte in einem Array
const userRightsIds = rightsArray.map((right) => right.IdRight);
// Wenn alles gut geht, logge die erfolgreichen Abschluss
// console.log("Benutzerrechte erfolgreich abgerufen:", userRightsIds);
return userRightsIds;
} catch (error) {
console.error("Fehler beim Abrufen der Benutzerrechte", error);
return [];
}
};

2
setupTests.js Normal file
View File

@@ -0,0 +1,2 @@
// setupTests.js
import "@testing-library/jest-dom";

View File

@@ -1,7 +1,9 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
purge: ["./pages/**/*.{js,ts,jsx,tsx}", "./components/**/*.{js,ts,jsx,tsx}"],
content: [],
content: [
"./pages/**/*.{js,ts,jsx,tsx}",
"./components/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {
zIndex: {

33
utils/contextMenuUtils.js Normal file
View File

@@ -0,0 +1,33 @@
// contextMenuUtils.js
import { BASE_URL } from "../config/urls";
export function addContextMenuToMarker(marker) {
marker.unbindContextMenu(); // Entferne das Kontextmenü, um Duplikate zu vermeiden
marker.bindContextMenu({
contextmenu: true,
contextmenuWidth: 140,
contextmenuItems: [
/* {
text: "Station öffnen (Tab)",
icon: "/img/screen_new.png",
callback: (e) => openInNewTab(e, marker),
},
{
text: "Station öffnen",
icon: "/img/screen_same.png",
callback: (e) => openInSameWindow(e, marker),
}, */
],
});
}
// Funktion zum Öffnen in einem neuen Tab
export function openInNewTab(e, marker) {
const baseUrl = BASE_URL;
console.log("baseUrl:", baseUrl);
if (marker && marker.options && marker.options.link) {
//console.log("Marker data:", baseUrl + marker.options.link);
window.open(baseUrl + marker.options.link, "_blank");
} else {
console.error("Fehler: Marker hat keine gültige 'link' Eigenschaft");
}
}

21
utils/geometryUtils.js Normal file
View File

@@ -0,0 +1,21 @@
export const parsePoint = (position) => {
const [longitude, latitude] = position.slice(6, -1).split(" ");
return { latitude: parseFloat(latitude), longitude: parseFloat(longitude) };
};
export const findClosestPoints = (coordinates, newPoint, map) => {
let minDist = Infinity;
let closestPair = [];
for (let i = 1; i < coordinates.length; i++) {
const dist = L.LineUtil.pointToSegmentDistance(
map.latLngToLayerPoint(newPoint),
map.latLngToLayerPoint(coordinates[i - 1]),
map.latLngToLayerPoint(coordinates[i])
);
if (dist < minDist) {
minDist = dist;
closestPair = [coordinates[i - 1], coordinates[i], i];
}
}
return closestPair;
};

111
utils/mapUtils.js Normal file
View File

@@ -0,0 +1,111 @@
// /utils/mapUtils.js
import L from "leaflet";
export const redrawPolyline = (lineData, lineColors, tooltipContents, map) => {
if (!lineData || !lineColors || !tooltipContents || !map) {
console.error("Invalid parameters for redrawPolyline");
return;
}
if (!lineData.coordinates || !Array.isArray(lineData.coordinates)) {
console.error("Invalid coordinates in lineData");
return;
}
const color = lineColors[lineData.idModul] || "#000000";
const tooltipContent =
tooltipContents[lineData.idModul] || "Standard-Tooltip-Inhalt";
if (lineData.polyline) map.removeLayer(lineData.polyline);
lineData.polyline = L.polyline(lineData.coordinates, {
color: color,
}).addTo(map);
lineData.polyline.bindTooltip(tooltipContent, {
permanent: false,
direction: "auto",
});
lineData.polyline.on("mouseover", () => {
lineData.polyline.setStyle({ weight: 10 });
lineData.polyline.bringToFront();
});
lineData.polyline.on("mouseout", () => {
lineData.polyline.setStyle({ weight: 5 });
});
};
export const saveLineData = (lineData) => {
fetch("/api/talas_v5_DB/gisLines/updateLineCoordinates", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
idModul: lineData.idModul,
idLD: lineData.idLD,
newCoordinates: lineData.coordinates,
}),
})
.then((response) => {
if (!response.ok) {
throw new Error("Fehler beim Speichern der Linienänderungen");
}
return response.json();
})
.then((data) => {
console.log("Linienänderungen gespeichert:", data);
})
.catch((error) => {
console.error("Fehler beim Speichern der Linienänderungen:", error);
});
};
// Call this function on page load to restore zoom and center
export const restoreMapSettings = (map) => {
const savedZoom = localStorage.getItem("mapZoom");
const savedCenter = localStorage.getItem("mapCenter");
if (savedZoom && savedCenter) {
try {
const centerCoords = JSON.parse(savedCenter);
map.setView(centerCoords, parseInt(savedZoom));
} catch (e) {
console.error("Error parsing stored map center:", e);
map.setView([53.111111, 8.4625], 12); // Standardkoordinaten und -zoom
}
}
};
// Now update checkOverlappingMarkers to check if oms is initialized
export const checkOverlappingMarkers = (map, markers, plusIcon) => {
// Ensure markers is always an array
if (!Array.isArray(markers)) {
//console.error("The `markers` argument is not an array:", markers);
return;
}
const overlappingGroups = {};
// Group markers by coordinates as strings
markers.forEach((marker) => {
const latlngStr = marker.getLatLng().toString();
if (overlappingGroups[latlngStr]) {
overlappingGroups[latlngStr].push(marker);
} else {
overlappingGroups[latlngStr] = [marker];
}
});
// Add plus markers at coordinates where overlaps occur
for (const coords in overlappingGroups) {
if (overlappingGroups[coords].length > 1) {
const latLng = L.latLng(coords.match(/[-.\d]+/g).map(Number));
const plusMarker = L.marker(latLng, { icon: plusIcon });
plusMarker.addTo(map);
//console.log("Adding plus icon marker at", latLng);
}
}
};

117
utils/markerUtils.js Normal file
View File

@@ -0,0 +1,117 @@
// /utils/markerUtils.js
import circleIcon from "../components/CircleIcon";
import { saveLineData, redrawPolyline } from "./mapUtils";
import L from "leaflet";
import { toast } from "react-toastify";
export const insertNewMarker = (closestPoints, newPoint, lineData, map) => {
const newMarker = L.marker(newPoint, {
icon: circleIcon,
draggable: true,
}).addTo(map);
lineData.coordinates.splice(closestPoints[2], 0, [
newPoint.lat,
newPoint.lng,
]);
// Hier direkt speichern nach Einfügen
saveLineData(lineData);
redrawPolyline(lineData);
// Event-Listener für das Verschieben des Markers hinzufügen
newMarker.on("dragend", () => {
const newCoords = newMarker.getLatLng();
setNewCoords(newCoords);
const newCoordinates = [...lineData.coordinates];
newCoordinates[closestPoints[2]] = [newCoords.lat, newCoords.lng];
lineData.coordinates = newCoordinates;
redrawPolyline(lineData);
updateMarkerPosition(newMarker.getLatLng(), lineData, newMarker);
saveLineData(lineData); // Speichern der neuen Koordinaten nach dem Verschieben
});
};
export const removeMarker = (marker, lineData, currentZoom, currentCenter) => {
// Save zoom and center to localStorage
//localStorage.setItem("mapZoom", currentZoom);
//localStorage.setItem("mapCenter", JSON.stringify(currentCenter));
// Find the index of the coordinate that matches the marker's position
const index = lineData.coordinates.findIndex((coord) =>
L.latLng(coord[0], coord[1]).equals(marker.getLatLng())
);
if (index !== -1) {
// Remove the coordinate from the line data
lineData.coordinates.splice(index, 1);
// Redraw the polyline with the updated coordinates
redrawPolyline(lineData);
// Remove the marker from the map
marker.remove();
// Save the updated line data
saveLineData(lineData);
// Refresh the browser
window.location.reload();
}
};
export const handleEditPoi = (
marker,
userRights,
setCurrentPoiData,
setShowPoiUpdateModal,
fetchPoiData,
toast // Hier toast als Parameter erhalten
) => {
console.log("Selected Marker ID (idPoi):", marker.options.id);
console.log("Selected Marker Description:", marker.options.description);
console.log("User Rights:", userRights);
// Sicherstellen, dass userRights ein Array ist
if (!Array.isArray(userRights)) {
console.error("User Rights is not an array:", userRights);
toast.error("Benutzerrechte sind ungültig.", {
position: "top-center",
autoClose: 5000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
});
return;
}
console.log("User Rights includes 56:", userRights.includes(56));
// Prüfung, ob der Benutzer die notwendigen Rechte hat
if (!userRights.includes(56)) {
toast.error("Benutzer hat keine Berechtigung zum Bearbeiten.", {
position: "top-center",
autoClose: 5000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
});
console.log("Benutzer hat keine Berechtigung zum Bearbeiten.");
return; // Beendet die Funktion frühzeitig, wenn keine Berechtigung vorliegt
}
setCurrentPoiData({
idPoi: marker.options.id,
name: marker.options.name,
description: marker.options.description,
});
fetchPoiData(marker.options.id);
setShowPoiUpdateModal(true);
};

10
utils/openInSameWindow.js Normal file
View File

@@ -0,0 +1,10 @@
// utils/openInSameWindow.js
export function openInSameWindow(e, marker, baseUrl) {
if (marker && marker.options && marker.options.link) {
//console.log("Marker data:", baseUrl + marker.options.link);
window.location.href = baseUrl + marker.options.link;
} else {
console.error("Fehler: Marker hat keine gültige 'link' Eigenschaft");
}
}

265
utils/utils.js Normal file
View File

@@ -0,0 +1,265 @@
// /utils/utils.js
import { useState } from "react";
import circleIcon from "../components/CircleIcon";
export const parsePoint = (position) => {
const [longitude, latitude] = position.slice(6, -1).split(" ");
return { latitude: parseFloat(latitude), longitude: parseFloat(longitude) };
};
//----------------------------------------------
export const determinePriority = (iconPath) => {
const [priorityConfig, setPriorityConfig] = useState([]);
for (let priority of priorityConfig) {
if (iconPath.includes(priority.name.toLowerCase())) {
return priority.level;
}
}
return 5; // Default priority (lowest)
};
//----------------------------------------------
export const createAndSetMarkers = async (systemId, setMarkersFunction) => {
try {
const response1 = await fetch(config.mapGisStationsStaticDistrictUrl);
const jsonResponse = await response1.json();
const response2 = await fetch(config.mapGisStationsStatusDistrictUrl);
const statusResponse = await response2.json();
const getIdSystemAndAllowValueMap = new Map(
GisSystemStatic.map((system) => [system.IdSystem, system.Allow])
);
//console.log("getIdSystemAndAllowValueMap:", getIdSystemAndAllowValueMap);
if (jsonResponse.Points && statusResponse.Statis) {
const statisMap = new Map(statusResponse.Statis.map((s) => [s.IdLD, s]));
let markersData = jsonResponse.Points.filter(
(station) =>
station.System === systemId &&
getIdSystemAndAllowValueMap.get(station.System) === 1
).map((station) => {
const statis = statisMap.get(station.IdLD);
const iconPath = statis
? `img/icons/${statis.Na}-marker-icon-${station.Icon}.png`
: `img/icons/marker-icon-${station.Icon}.png`;
const priority = determinePriority(iconPath);
const zIndexOffset = 100 * (5 - priority); // Adjusted for simplicity and positive values
const marker = L.marker([station.X, station.Y], {
icon: L.icon({
iconUrl: iconPath,
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
}),
areaName: station.Area_Name, // Stelle sicher, dass dieser Bereich gesetzt wird
link: station.Link,
zIndexOffset: zIndexOffset,
bounceOnAdd: !!statis,
});
if (statis) {
marker.on("add", () => marker.bounce(3));
}
const statusInfo = statusResponse.Statis.filter(
(status) => status.IdLD === station.IdLD
)
.reverse()
.map(
(status) => `
<div class="flex items-center my-1">
<div class="w-2 h-2 mr-2 inline-block rounded-full" style="background-color: ${status.Co};"></div>
${status.Me}&nbsp;<span style="color: ${status.Co};">(${status.Na})</span>
</div>
`
)
.join("");
marker.bindPopup(`
<div class=" bg-white rounded-lg ">
<span class="text-lg font-semibold text-gray-900">${station.LD_Name}</span>
<span class="text-md font-bold text-gray-800"> ${station.Device}</span><br>
<span class="text-gray-800"><strong> ${station.Area_Short} </strong>(${station.Area_Name})</span><br>
<span class="text-gray-800"><strong>${station.Location_Short} </strong> (${station.Location_Name})</span>
<div class="mt-2">${statusInfo}</div>
</div>
`);
return marker;
});
setMarkersFunction(markersData);
}
} catch (error) {
console.error("Error fetching data: ", error);
}
};
//----------------------------------------------
export const fetchPriorityConfig = async () => {
try {
const response = await fetch("/api/talas_v5_DB/priorityConfig");
const data = await response.json();
console.log("Prioritätskonfiguration:", data);
setPriorityConfig(data);
} catch (error) {
console.error("Fehler beim Laden der Prioritätskonfiguration:", error);
}
};
//----------------------------------------------
export const fetchGisStatusStations = async (idMap, idUser) => {
try {
const response = await fetch(
`/api/talas5/webserviceMap/GisStationsStatusDistrict?idMap=${idMap}&idUser=${idUser}`
);
if (!response.ok) {
throw new Error(`Error: ${response.statusText}`);
}
const data = await response.json();
console.log("GisStatusStations:", data);
return data;
} catch (error) {
console.error("Fehler beim Abrufen der Daten:", error);
}
};
//----------------------------------------------
export const handleEditPoi = (marker) => {
// Prüfung, ob der Benutzer die notwendigen Rechte hat
if (!userRights || !userRights.includes(56)) {
toast.error("Benutzer hat keine Berechtigung zum Bearbeiten.", {
position: "top-center",
autoClose: 5000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
});
console.log("Benutzer hat keine Berechtigung zum Bearbeiten.");
return; // Beendet die Funktion frühzeitig, wenn keine Berechtigung vorliegt
}
//console.log("Selected Marker ID (idPoi):", marker.options.idPoi);
//console.log("Selected Marker Description:", marker.options.description);
setCurrentPoiData({
idPoi: marker.options.id,
name: marker.options.name,
description: marker.options.description,
});
//console.log("POI-Daten1:", currentPoiData);
fetchPoiData(marker.options.id);
setShowPoiUpdateModal(true);
};
//----------------------------------------------
export const insertNewMarker = (closestPoints, newPoint, lineData, map) => {
const newMarker = L.marker(newPoint, {
icon: circleIcon,
draggable: true,
}).addTo(map);
lineData.coordinates.splice(closestPoints[2], 0, [
newPoint.lat,
newPoint.lng,
]);
// Hier direkt speichern nach Einfügen
saveLineData(lineData);
redrawPolyline(lineData);
// Event-Listener für das Verschieben des Markers hinzufügen
newMarker.on("dragend", () => {
const newCoords = newMarker.getLatLng();
setNewCoords(newCoords);
const newCoordinates = [...lineData.coordinates];
newCoordinates[closestPoints[2]] = [newCoords.lat, newCoords.lng];
lineData.coordinates = newCoordinates;
redrawPolyline(lineData);
updateMarkerPosition(newMarker.getLatLng(), lineData, newMarker);
saveLineData(lineData); // Speichern der neuen Koordinaten nach dem Verschieben
});
};
//----------------------------------------------
/* export const addItemsToMapContextMenu = () => {
const [menuItemAdded, setMenuItemAdded] = useState(false);
if (!menuItemAdded) {
//console.log("contextMenuItems hasRights:", hasRights);
map.contextmenu.addItem({
text: "POI hinzufügen",
icon: "img/add_station.png",
className: "background-red",
callback: (event) => addStationCallback(event, hasRights),
});
setMenuItemAdded(true); // Menüpunkt wurde hinzugefült, Zustand aktualisieren
}
}; */
//----------------------------------------------
export const saveLineData = (lineData) => {
fetch("/api/talas_v5_DB/gisLines/updateLineCoordinates", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
idModul: lineData.idModul,
idLD: lineData.idLD,
newCoordinates: lineData.coordinates,
}),
})
.then((response) => {
if (!response.ok) {
throw new Error("Fehler beim Speichern der Linienänderungen");
}
return response.json();
})
.then((data) => {
console.log("Linienänderungen gespeichert:", data);
})
.catch((error) => {
console.error("Fehler beim Speichern der Linienänderungen:", error);
});
};
//----------------------------------------------
/* export const redrawPolyline = (lineData) => {
const [lineColors, setLineColors] = useState({}); */
import L from "leaflet";
export const redrawPolyline = (lineData, lineColors, tooltipContents, map) => {
if (!lineData || !lineColors || !tooltipContents || !map) {
console.error("Invalid parameters for redrawPolyline");
return;
}
if (!lineData.coordinates || !Array.isArray(lineData.coordinates)) {
console.error("Invalid coordinates in lineData");
return;
}
const color = lineColors[lineData.idModul] || "#000000";
const tooltipContent =
tooltipContents[lineData.idModul] || "Standard-Tooltip-Inhalt";
if (lineData.polyline) map.removeLayer(lineData.polyline);
lineData.polyline = L.polyline(lineData.coordinates, {
color: color,
}).addTo(map);
lineData.polyline.bindTooltip(tooltipContent, {
permanent: false,
direction: "auto",
});
lineData.polyline.on("mouseover", () => {
lineData.polyline.setStyle({ weight: 10 });
lineData.polyline.bringToFront();
});
lineData.polyline.on("mouseout", () => {
lineData.polyline.setStyle({ weight: 5 });
});
};

View File

@@ -0,0 +1,45 @@
// utils/zoomAndCenterUtils.js
/* export const zoomIn = (e, map) => {
if (!map) {
console.error("map is not defined in zoomIn");
return;
}
map.flyTo(e.latlng, map.getZoom() + 1);
localStorage.setItem("mapZoom", map.getZoom());
localStorage.setItem("mapCenter", JSON.stringify(map.getCenter()));
}; */
export const zoomIn = (e, map) => {
if (!map) {
console.error("map is not defined in zoomIn");
return;
}
map.flyTo(e.latlng, 12);
localStorage.setItem("mapZoom", map.getZoom());
localStorage.setItem("mapCenter", JSON.stringify(map.getCenter()));
};
export const zoomOut = (map) => {
if (!map) {
console.error("map is not defined in zoomOut");
return;
}
const x = 51.41321407879154;
const y = 7.739617925303934;
const zoom = 7;
console.log("map");
console.log(map);
map.flyTo([x, y], zoom);
localStorage.setItem("mapZoom", map.getZoom());
localStorage.setItem("mapCenter", JSON.stringify(map.getCenter()));
};
export const centerHere = (e, map) => {
if (!map) {
console.error("map is not defined in centerHere");
return;
}
map.panTo(e.latlng);
localStorage.setItem("mapZoom", map.getZoom());
localStorage.setItem("mapCenter", JSON.stringify(map.getCenter()));
};