452 lines
12 KiB
JavaScript
452 lines
12 KiB
JavaScript
// 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
|
|
*/
|
|
console.log("OverlappingMarkerSpiderfier.js loaded..");
|
|
|
|
(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);
|