diff --git a/components/MapComponent.js b/components/MapComponent.js
index 3e40d43a9..1a8e2421d 100644
--- a/components/MapComponent.js
+++ b/components/MapComponent.js
@@ -5,6 +5,8 @@ import "leaflet/dist/leaflet.css";
import "leaflet-contextmenu/dist/leaflet.contextmenu.css";
import "leaflet-contextmenu";
import * as config from "../config/config.js";
+import { OverlappingMarkerSpiderfier } from "../lib/OverlappingMarkerSpiderfier.js";
+
const MapComponent = ({ locations, onLocationUpdate }) => {
const mapRef = useRef(null); // Referenz auf das DIV-Element der Karte
const [map, setMap] = useState(null); // Zustand der Karteninstanz
@@ -27,6 +29,7 @@ const MapComponent = ({ locations, onLocationUpdate }) => {
const mapGisStationsMeasurementsUrl = config.mapGisStationsMeasurementsUrl;
const mapGisSystemStaticUrl = config.mapGisSystemStaticUrl;
const mapDataIconUrl = config.mapDataIconUrl;
+ const [oms, setOms] = useState(null); // State für OMS-Instanz
// Funktion zum Aktualisieren der Position in der Datenbank
const updateLocationInDatabase = async (id, newLatitude, newLongitude) => {
@@ -682,7 +685,9 @@ const MapComponent = ({ locations, onLocationUpdate }) => {
popupAnchor: [1, -34],
shadowSize: [41, 41],
}),
- }).addTo(map);
+ });
+ //oms.addMarker(marker); // Marker zum OMS hinzufügen
+ marker.addTo(map);
marker.on("mouseover", function (e) {
this.openPopup();
diff --git a/lib/OverlappingMarkerSpiderfier.js b/lib/OverlappingMarkerSpiderfier.js
new file mode 100644
index 000000000..a953b3303
--- /dev/null
+++ b/lib/OverlappingMarkerSpiderfier.js
@@ -0,0 +1,113 @@
+import L from "leaflet";
+
+export class OverlappingMarkerSpiderfier {
+ constructor(map, options = {}) {
+ this.map = map;
+ this.markers = [];
+ this.markerListeners = [];
+ this.listeners = {};
+ this.nearbyDistance = options.nearbyDistance || 20;
+ this.circleSpiralSwitchover = options.circleSpiralSwitchover || 9;
+ this.circleFootSeparation = options.circleFootSeparation || 25; // pixels
+ this.circleStartAngle = options.circleStartAngle || Math.PI / 6;
+ this.spiralFootSeparation = options.spiralFootSeparation || 28; // pixels
+ this.spiralLengthStart = options.spiralLengthStart || 11;
+ this.spiralLengthFactor = options.spiralLengthFactor || 5;
+ this.legWeight = options.legWeight || 1.5;
+ this.legColors = options.legColors || {
+ usual: "#222",
+ highlighted: "#f00",
+ };
+
+ this.initMarkerArrays();
+ this.map.on("click", this.unspiderfy.bind(this));
+ this.map.on("zoomend", this.unspiderfy.bind(this));
+ }
+
+ initMarkerArrays() {
+ this.markers = [];
+ this.markerListeners = [];
+ }
+
+ addMarker(marker) {
+ if (marker._oms) return this;
+ marker._oms = true;
+
+ const listener = () => {
+ this.spiderListener(marker);
+ };
+
+ marker.on("click", listener);
+ this.markerListeners.push(listener);
+ this.markers.push(marker);
+
+ return this;
+ }
+
+ spiderListener(marker) {
+ const spidered = !!marker._omsData;
+ if (!spidered) {
+ const nearMarkers = this.nearbyMarkers(marker);
+ if (nearMarkers.length > 1) {
+ this.spiderfy(nearMarkers);
+ }
+ }
+ }
+
+ nearbyMarkers(marker) {
+ const nearby = [];
+ const markerPt = this.map.latLngToLayerPoint(marker.getLatLng());
+ this.markers.forEach((m) => {
+ if (m !== marker) {
+ const mPt = this.map.latLngToLayerPoint(m.getLatLng());
+ const distanceSq = this.ptDistanceSq(mPt, markerPt);
+ if (distanceSq < this.nearbyDistance * this.nearbyDistance) {
+ nearby.push(m);
+ }
+ }
+ });
+ return nearby;
+ }
+
+ spiderfy(markers) {
+ const centerPt = this.map.latLngToLayerPoint(markers[0].getLatLng());
+ markers.forEach((marker, index) => {
+ const angle =
+ this.circleStartAngle + (index * 2 * Math.PI) / markers.length;
+ const legLength =
+ this.circleFootSeparation * (2 + index / markers.length);
+ const newPt = L.point(
+ centerPt.x + legLength * Math.cos(angle),
+ centerPt.y + legLength * Math.sin(angle)
+ );
+
+ const newLatLng = this.map.layerPointToLatLng(newPt);
+ marker.setLatLng(newLatLng);
+ marker.setZIndexOffset(1000);
+
+ const polyline = L.polyline([marker.getLatLng(), newLatLng], {
+ color: this.legColors.usual,
+ weight: this.legWeight,
+ clickable: false,
+ });
+ this.map.addLayer(polyline);
+ });
+ }
+
+ unspiderfy() {
+ this.markers.forEach((marker) => {
+ if (marker._omsData) {
+ marker.setLatLng(marker._omsData.usualPosition);
+ marker.setZIndexOffset(0);
+ this.map.removeLayer(marker._omsData.leg);
+ delete marker._omsData;
+ }
+ });
+ }
+
+ ptDistanceSq(pt1, pt2) {
+ const dx = pt1.x - pt2.x;
+ const dy = pt1.y - pt2.y;
+ return dx * dx + dy * dy;
+ }
+}
diff --git a/pages/_app.js b/pages/_app.js
index c55121b3e..7617273bd 100644
--- a/pages/_app.js
+++ b/pages/_app.js
@@ -1,6 +1,12 @@
import "../styles/global.css"; // Pfad zur globalen CSS-Datei anpassen
+import Script from "next/script";
+
import React from "react";
export default function MyApp({ Component, pageProps }) {
- return ;
+ return (
+ <>
+
+ >
+ );
}
diff --git a/public/js/spiderfier-Leaflet-cdn.js b/public/js/spiderfier-Leaflet-cdn.js
new file mode 100644
index 000000000..14b38bc46
--- /dev/null
+++ b/public/js/spiderfier-Leaflet-cdn.js
@@ -0,0 +1,19 @@
+(function(){/*
+ OverlappingMarkerSpiderfier
+https://github.com/jawj/OverlappingMarkerSpiderfier-Leaflet
+Copyright (c) 2011 - 2012 George MacKerron
+Released under the MIT licence: http://opensource.org/licenses/mit-license
+Note: The Leaflet maps API must be included *before* this code
+*/
+(function(){var q={}.hasOwnProperty,r=[].slice;null!=this.L&&(this.OverlappingMarkerSpiderfier=function(){function n(c,b){var a,e,g,f,d=this;this.map=c;null==b&&(b={});for(a in b)q.call(b,a)&&(e=b[a],this[a]=e);this.initMarkerArrays();this.listeners={};f=["click","zoomend"];e=0;for(g=f.length;eb)return this;a=this.markerListeners.splice(b,1)[0];c.removeEventListener("click",a);delete c._oms;this.markers.splice(b,1);return this};d.clearMarkers=function(){var c,b,a,e,g;this.unspiderfy();g=this.markers;c=a=0;for(e=g.length;aa||this.listeners[c].splice(a,1);return this};d.clearListeners=function(c){this.listeners[c]=[];return this};d.trigger=function(){var c,b,a,e,g,f;b=arguments[0];c=2<=arguments.length?r.call(arguments,1):[];b=null!=(a=this.listeners[b])?a:[];f=[];e=0;for(g=b.length;ec;a=0<=c?++f:--f)a=this.circleStartAngle+a*e,d.push(new L.Point(b.x+g*Math.cos(a),b.y+g*Math.sin(a)));return d};d.generatePtsSpiral=function(c,b){var a,e,g,f,d;g=this.spiralLengthStart;a=0;d=[];for(e=f=0;0<=c?fc;e=0<=c?++f:--f)a+=this.spiralFootSeparation/g+5E-4*e,e=new L.Point(b.x+g*Math.cos(a),b.y+g*Math.sin(a)),g+=k*this.spiralLengthFactor/a,d.push(e);return d};d.spiderListener=function(c){var b,a,e,g,f,d,h,k,l;(b=null!=
+c._omsData)&&this.keepSpiderfied||this.unspiderfy();if(b)return this.trigger("click",c);g=[];f=[];d=this.nearbyDistance*this.nearbyDistance;e=this.map.latLngToLayerPoint(c.getLatLng());l=this.markers;h=0;for(k=l.length;h=this.circleSpiralSwitchover?this.generatePtsSpiral(m,a).reverse():this.generatePtsCircle(m,a);a=function(){var a,b,k,m=this;k=[];a=0;for(b=d.length;a