From 82f259a3a6a8688d8a353b2718ae3c7428f5921b Mon Sep 17 00:00:00 2001 From: ISA Date: Thu, 18 Apr 2024 09:47:25 +0200 Subject: [PATCH] Einbinden von OverlappingMarkerSpiderfier,js ohne Error, der code muss noch optimiert werden --- components/MapComponent.js | 152 ++++---- lib/OverlappingMarkerSpiderfier.js | 468 ++++++++++++++++++----- pages/_app.js | 4 + public/js/OverlappingMarkerSpiderfier.js | 398 +++++++++++++++++++ 4 files changed, 860 insertions(+), 162 deletions(-) create mode 100644 public/js/OverlappingMarkerSpiderfier.js diff --git a/components/MapComponent.js b/components/MapComponent.js index e92fa5064..f7cfb3cbe 100644 --- a/components/MapComponent.js +++ b/components/MapComponent.js @@ -5,12 +5,88 @@ 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 const [online, setOnline] = useState(navigator.onLine); // Zustand der Internetverbindung + // 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)); + }; + + // Handle online/offline status + useEffect(() => { + window.addEventListener("online", checkInternet); + window.addEventListener("offline", checkInternet); + return () => { + window.removeEventListener("online", checkInternet); + window.removeEventListener("offline", checkInternet); + }; + }, []); + // 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); + + if (window.OverlappingMarkerSpiderfier) { + const oms = new window.OverlappingMarkerSpiderfier(initialMap, { + nearbyDistance: 50, + }); + setOms(oms); + } + setMap(initialMap); + + setMap(initialMap); + } + }, [mapRef, map]); const [GisStationsStaticDistrict, setGisStationsStaticDistrict] = useState( [] ); // Zustand für statische Daten @@ -267,80 +343,6 @@ const MapComponent = ({ locations, onLocationUpdate }) => { } }, []); - // 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); - - const newOms = new OverlappingMarkerSpiderfier(initialMap, { - nearbyDistance: 50, - }); - setOms(newOms); - 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) { diff --git a/lib/OverlappingMarkerSpiderfier.js b/lib/OverlappingMarkerSpiderfier.js index 0e1747459..eef88bb22 100644 --- a/lib/OverlappingMarkerSpiderfier.js +++ b/lib/OverlappingMarkerSpiderfier.js @@ -1,104 +1,398 @@ -import L from "leaflet"; +// Generated by CoffeeScript 1.6.2 +/** @preserve 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 +*/ -export class OverlappingMarkerSpiderfier { - constructor(map, options = {}) { - this.map = map; - this.markers = []; - this.markerListeners = []; - this.keepSpiderfied = options.keepSpiderfied || false; - // Basiseinstellungen für die Distanz und die Zoomstufenabhängigkeit - this.baseNearbyDistance = options.nearbyDistance || 20; - this.nearbyDistance = this.baseNearbyDistance; // Initialwert setzen +(function() { + var __hasProp = {}.hasOwnProperty, + __slice = [].slice; - this.circleSpiralSwitchover = options.circleSpiralSwitchover || 9; - this.circleFootSeparation = options.circleFootSeparation || 25; - this.circleStartAngle = options.circleStartAngle || Math.PI / 6; - this.spiralFootSeparation = options.spiralFootSeparation || 28; - this.spiralLengthStart = options.spiralLengthStart || 11; - this.spiralLengthFactor = options.spiralLengthFactor || 5; - this.legWeight = options.legWeight || 1.5; - this.legColors = options.legColors || { - usual: "#222", - highlighted: "#f00", + if (this['L'] == null) { + return; + } + + this['OverlappingMarkerSpiderfier'] = (function() { + var p, twoPi; + + p = _Class.prototype; + + p['VERSION'] = '0.2.6'; + + twoPi = Math.PI * 2; + + p['keepSpiderfied'] = false; + + p['nearbyDistance'] = 20; + + p['circleSpiralSwitchover'] = 9; + + p['circleFootSeparation'] = 25; + + p['circleStartAngle'] = twoPi / 12; + + p['spiralFootSeparation'] = 28; + + p['spiralLengthStart'] = 11; + + p['spiralLengthFactor'] = 5; + + p['legWeight'] = 1.5; + + p['legColors'] = { + 'usual': '#222', + 'highlighted': '#f00' }; - this.initMarkerArrays(); - this.map.on("click", () => this.unspiderfy()); - this.map.on("zoomend", () => this.unspiderfy()); - } + function _Class(map, opts) { + var e, k, v, _i, _len, _ref, + _this = this; - initMarkerArrays() { - this.markers = []; - this.markerListeners = []; - } - - addMarker(marker) { - if (!marker._oms) { - marker._oms = {}; // Stellt sicher, dass _oms ein Objekt ist + this.map = map; + if (opts == null) { + opts = {}; + } + for (k in opts) { + if (!__hasProp.call(opts, k)) continue; + v = opts[k]; + this[k] = v; + } + this.initMarkerArrays(); + this.listeners = {}; + _ref = ['click', 'zoomend']; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + e = _ref[_i]; + this.map.addEventListener(e, function() { + return _this['unspiderfy'](); + }); + } } - const listener = () => { - this.spiderListener(marker); + p.initMarkerArrays = function() { + this.markers = []; + return this.markerListeners = []; }; - marker.on("click", listener); - this.markerListeners.push(listener); - this.markers.push(marker); + p['addMarker'] = function(marker) { + var markerListener, + _this = this; - return this; - } - - spiderListener(marker) { - const spidered = marker._oms.spidered; - if (!spidered) { - const nearMarkers = this.nearbyMarkers(marker); - if (nearMarkers.length > 1) { - this.spiderfy(nearMarkers); + if (marker['_oms'] != null) { + return this; } - } else { - this.unspiderfy(); // Schließt alle gespiderfied Marker, wenn einer erneut geklickt wird - } - } + marker['_oms'] = true; + markerListener = function() { + return _this.spiderListener(marker); + }; + marker.addEventListener('click', markerListener); + this.markerListeners.push(markerListener); + this.markers.push(marker); + return this; + }; - nearbyMarkers(marker) { - return this.markers.filter((m) => { - const distance = this.map.distance(marker.getLatLng(), m.getLatLng()); - return distance < this.nearbyDistance && marker !== m; - }); - } + p['getMarkers'] = function() { + return this.markers.slice(0); + }; - spiderfy(markers) { - const centerPt = this.map.latLngToLayerPoint(markers[0].getLatLng()); - markers.forEach((marker, i) => { - const angle = this.circleStartAngle + (i * 2 * Math.PI) / markers.length; - const legLength = this.circleFootSeparation * (2 + i / markers.length); - const newPt = L.point( - centerPt.x + legLength * Math.cos(angle), - centerPt.y + legLength * Math.sin(angle) - ); - const newLatLng = this.map.layerPointToLatLng(newPt); + p['removeMarker'] = function(marker) { + var i, markerListener; - if (!marker._oms) { - marker._oms = {}; // Stellt sicher, dass _oms ein Objekt ist + if (marker['_omsData'] != null) { + this['unspiderfy'](); } - - // Speichert die aktuelle Position, bevor sie verändert wird - marker._oms.usualPosition = marker.getLatLng(); - marker._oms.spidered = true; // Markiert, dass der Marker gespiderfied ist - - marker.setLatLng(newLatLng); - marker.setZIndexOffset(1000); - }); - } - unspiderfy() { - this.markers.forEach((marker) => { - if (marker._oms && marker._oms.spidered) { - // Setzt den Marker nur dann zurück, wenn er gespiderfied war - marker.setLatLng(marker._oms.usualPosition); - marker.setZIndexOffset(0); - marker._oms.spidered = false; // Setzt zurück, dass der Marker nicht mehr gespiderfied ist + i = this.arrIndexOf(this.markers, marker); + if (i < 0) { + return this; } - }); - } -} + markerListener = this.markerListeners.splice(i, 1)[0]; + marker.removeEventListener('click', markerListener); + delete marker['_oms']; + this.markers.splice(i, 1); + return this; + }; + + p['clearMarkers'] = function() { + var i, marker, markerListener, _i, _len, _ref; + + this['unspiderfy'](); + _ref = this.markers; + for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { + marker = _ref[i]; + markerListener = this.markerListeners[i]; + marker.removeEventListener('click', markerListener); + delete marker['_oms']; + } + this.initMarkerArrays(); + return this; + }; + + p['addListener'] = function(event, func) { + var _base, _ref; + + ((_ref = (_base = this.listeners)[event]) != null ? _ref : _base[event] = []).push(func); + return this; + }; + + p['removeListener'] = function(event, func) { + var i; + + i = this.arrIndexOf(this.listeners[event], func); + if (!(i < 0)) { + this.listeners[event].splice(i, 1); + } + return this; + }; + + p['clearListeners'] = function(event) { + this.listeners[event] = []; + return this; + }; + + p.trigger = function() { + var args, event, func, _i, _len, _ref, _ref1, _results; + + event = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + _ref1 = (_ref = this.listeners[event]) != null ? _ref : []; + _results = []; + for (_i = 0, _len = _ref1.length; _i < _len; _i++) { + func = _ref1[_i]; + _results.push(func.apply(null, args)); + } + return _results; + }; + + p.generatePtsCircle = function(count, centerPt) { + var angle, angleStep, circumference, i, legLength, _i, _results; + + circumference = this['circleFootSeparation'] * (2 + count); + legLength = circumference / twoPi; + angleStep = twoPi / count; + _results = []; + for (i = _i = 0; 0 <= count ? _i < count : _i > count; i = 0 <= count ? ++_i : --_i) { + angle = this['circleStartAngle'] + i * angleStep; + _results.push(new L.Point(centerPt.x + legLength * Math.cos(angle), centerPt.y + legLength * Math.sin(angle))); + } + return _results; + }; + + p.generatePtsSpiral = function(count, centerPt) { + var angle, i, legLength, pt, _i, _results; + + legLength = this['spiralLengthStart']; + angle = 0; + _results = []; + for (i = _i = 0; 0 <= count ? _i < count : _i > count; i = 0 <= count ? ++_i : --_i) { + angle += this['spiralFootSeparation'] / legLength + i * 0.0005; + pt = new L.Point(centerPt.x + legLength * Math.cos(angle), centerPt.y + legLength * Math.sin(angle)); + legLength += twoPi * this['spiralLengthFactor'] / angle; + _results.push(pt); + } + return _results; + }; + + p.spiderListener = function(marker) { + var m, mPt, markerPt, markerSpiderfied, nearbyMarkerData, nonNearbyMarkers, pxSq, _i, _len, _ref; + + markerSpiderfied = marker['_omsData'] != null; + if (!(markerSpiderfied && this['keepSpiderfied'])) { + this['unspiderfy'](); + } + if (markerSpiderfied) { + return this.trigger('click', marker); + } else { + nearbyMarkerData = []; + nonNearbyMarkers = []; + pxSq = this['nearbyDistance'] * this['nearbyDistance']; + markerPt = this.map.latLngToLayerPoint(marker.getLatLng()); + _ref = this.markers; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + m = _ref[_i]; + if (!this.map.hasLayer(m)) { + continue; + } + mPt = this.map.latLngToLayerPoint(m.getLatLng()); + if (this.ptDistanceSq(mPt, markerPt) < pxSq) { + nearbyMarkerData.push({ + marker: m, + markerPt: mPt + }); + } else { + nonNearbyMarkers.push(m); + } + } + if (nearbyMarkerData.length === 1) { + return this.trigger('click', marker); + } else { + return this.spiderfy(nearbyMarkerData, nonNearbyMarkers); + } + } + }; + + p.makeHighlightListeners = function(marker) { + var _this = this; + + return { + highlight: function() { + return marker['_omsData'].leg.setStyle({ + color: _this['legColors']['highlighted'] + }); + }, + unhighlight: function() { + return marker['_omsData'].leg.setStyle({ + color: _this['legColors']['usual'] + }); + } + }; + }; + + p.spiderfy = function(markerData, nonNearbyMarkers) { + var bodyPt, footLl, footPt, footPts, leg, marker, md, mhl, nearestMarkerDatum, numFeet, spiderfiedMarkers; + + this.spiderfying = true; + numFeet = markerData.length; + bodyPt = this.ptAverage((function() { + var _i, _len, _results; + + _results = []; + for (_i = 0, _len = markerData.length; _i < _len; _i++) { + md = markerData[_i]; + _results.push(md.markerPt); + } + return _results; + })()); + footPts = numFeet >= this['circleSpiralSwitchover'] ? this.generatePtsSpiral(numFeet, bodyPt).reverse() : this.generatePtsCircle(numFeet, bodyPt); + spiderfiedMarkers = (function() { + var _i, _len, _results, + _this = this; + + _results = []; + for (_i = 0, _len = footPts.length; _i < _len; _i++) { + footPt = footPts[_i]; + footLl = this.map.layerPointToLatLng(footPt); + nearestMarkerDatum = this.minExtract(markerData, function(md) { + return _this.ptDistanceSq(md.markerPt, footPt); + }); + marker = nearestMarkerDatum.marker; + leg = new L.Polyline([marker.getLatLng(), footLl], { + color: this['legColors']['usual'], + weight: this['legWeight'], + clickable: false + }); + this.map.addLayer(leg); + marker['_omsData'] = { + usualPosition: marker.getLatLng(), + leg: leg + }; + if (this['legColors']['highlighted'] !== this['legColors']['usual']) { + mhl = this.makeHighlightListeners(marker); + marker['_omsData'].highlightListeners = mhl; + marker.addEventListener('mouseover', mhl.highlight); + marker.addEventListener('mouseout', mhl.unhighlight); + } + marker.setLatLng(footLl); + marker.setZIndexOffset(1000000); + _results.push(marker); + } + return _results; + }).call(this); + delete this.spiderfying; + this.spiderfied = true; + return this.trigger('spiderfy', spiderfiedMarkers, nonNearbyMarkers); + }; + + p['unspiderfy'] = function(markerNotToMove) { + var marker, mhl, nonNearbyMarkers, unspiderfiedMarkers, _i, _len, _ref; + + if (markerNotToMove == null) { + markerNotToMove = null; + } + if (this.spiderfied == null) { + return this; + } + this.unspiderfying = true; + unspiderfiedMarkers = []; + nonNearbyMarkers = []; + _ref = this.markers; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + marker = _ref[_i]; + if (marker['_omsData'] != null) { + this.map.removeLayer(marker['_omsData'].leg); + if (marker !== markerNotToMove) { + marker.setLatLng(marker['_omsData'].usualPosition); + } + marker.setZIndexOffset(0); + mhl = marker['_omsData'].highlightListeners; + if (mhl != null) { + marker.removeEventListener('mouseover', mhl.highlight); + marker.removeEventListener('mouseout', mhl.unhighlight); + } + delete marker['_omsData']; + unspiderfiedMarkers.push(marker); + } else { + nonNearbyMarkers.push(marker); + } + } + delete this.unspiderfying; + delete this.spiderfied; + this.trigger('unspiderfy', unspiderfiedMarkers, nonNearbyMarkers); + return this; + }; + + p.ptDistanceSq = function(pt1, pt2) { + var dx, dy; + + dx = pt1.x - pt2.x; + dy = pt1.y - pt2.y; + return dx * dx + dy * dy; + }; + + p.ptAverage = function(pts) { + var numPts, pt, sumX, sumY, _i, _len; + + sumX = sumY = 0; + for (_i = 0, _len = pts.length; _i < _len; _i++) { + pt = pts[_i]; + sumX += pt.x; + sumY += pt.y; + } + numPts = pts.length; + return new L.Point(sumX / numPts, sumY / numPts); + }; + + p.minExtract = function(set, func) { + var bestIndex, bestVal, index, item, val, _i, _len; + + for (index = _i = 0, _len = set.length; _i < _len; index = ++_i) { + item = set[index]; + val = func(item); + if ((typeof bestIndex === "undefined" || bestIndex === null) || val < bestVal) { + bestVal = val; + bestIndex = index; + } + } + return set.splice(bestIndex, 1)[0]; + }; + + p.arrIndexOf = function(arr, obj) { + var i, o, _i, _len; + + if (arr.indexOf != null) { + return arr.indexOf(obj); + } + for (i = _i = 0, _len = arr.length; _i < _len; i = ++_i) { + o = arr[i]; + if (o === obj) { + return i; + } + } + return -1; + }; + + return _Class; + + })(); + +}).call(this); \ No newline at end of file diff --git a/pages/_app.js b/pages/_app.js index 7617273bd..d53589400 100644 --- a/pages/_app.js +++ b/pages/_app.js @@ -6,6 +6,10 @@ import React from "react"; export default function MyApp({ Component, pageProps }) { return ( <> +