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 (
<>
+
>
);
diff --git a/public/js/OverlappingMarkerSpiderfier.js b/public/js/OverlappingMarkerSpiderfier.js
new file mode 100644
index 000000000..eef88bb22
--- /dev/null
+++ b/public/js/OverlappingMarkerSpiderfier.js
@@ -0,0 +1,398 @@
+// 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
+*/
+
+
+(function() {
+ var __hasProp = {}.hasOwnProperty,
+ __slice = [].slice;
+
+ 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'
+ };
+
+ function _Class(map, opts) {
+ var e, k, v, _i, _len, _ref,
+ _this = this;
+
+ 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']();
+ });
+ }
+ }
+
+ p.initMarkerArrays = function() {
+ this.markers = [];
+ return this.markerListeners = [];
+ };
+
+ p['addMarker'] = function(marker) {
+ var markerListener,
+ _this = this;
+
+ if (marker['_oms'] != null) {
+ return this;
+ }
+ marker['_oms'] = true;
+ markerListener = function() {
+ return _this.spiderListener(marker);
+ };
+ marker.addEventListener('click', markerListener);
+ this.markerListeners.push(markerListener);
+ this.markers.push(marker);
+ return this;
+ };
+
+ p['getMarkers'] = function() {
+ return this.markers.slice(0);
+ };
+
+ p['removeMarker'] = function(marker) {
+ var i, markerListener;
+
+ if (marker['_omsData'] != null) {
+ this['unspiderfy']();
+ }
+ 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