diff --git a/build/deps.js b/build/deps.js index f1dfda969..00e290dc3 100644 --- a/build/deps.js +++ b/build/deps.js @@ -1,10 +1,5 @@ var deps = { - Defaults: { - src: ['MarkerCluster.Default.js'], - deps: ['QuickHull', 'Spiderfier'], - desc: 'Provides sensible defaults for the Cluster.' - }, Core: { src: ['MarkerClusterGroup.js', 'MarkerCluster.js'], diff --git a/dist/leaflet.markercluster-src.js b/dist/leaflet.markercluster-src.js index c23f535cc..24076c07d 100644 --- a/dist/leaflet.markercluster-src.js +++ b/dist/leaflet.markercluster-src.js @@ -5,69 +5,6 @@ */ (function (window, undefined) { -(function () { - L.MarkerClusterDefault = { - iconCreateFunction: function (childCount) { - var c = ' marker-cluster-'; - if (childCount < 10) { - c += 'small'; - } else if (childCount < 100) { - c += 'medium'; - } else { - c += 'large'; - } - - return new L.DivIcon({ html: '
' + childCount + '
', className: 'marker-cluster' + c, iconSize: new L.Point(40, 40) }); - }, - - _shownPolygon: null, - - bindEvents: function (map, markerClusterGroup) { - var me = this; - var inZoomAnimation = false; - - map.on('zoomstart', function () { inZoomAnimation = true; }); - map.on('zoomend', function () { inZoomAnimation = false; }); - - - //Zoom on cluster click or spiderfy if we are at the lowest level - markerClusterGroup.on('clusterclick', function (a) { - if (map.getMaxZoom() === map.getZoom()) { - a.layer.spiderfy(); - } else { - a.layer.zoomToBounds(); - } - }); - - //Show convex hull (boundary) polygon on mouse over - markerClusterGroup.on('clustermouseover', function (a) { - if (inZoomAnimation) { - return; - } - if (me._shownPolygon) { - map.removeLayer(me._shownPolygon); - } - if (a.layer.getChildCount() > 2) { - me._shownPolygon = new L.Polygon(a.layer.getConvexHull()); - map.addLayer(me._shownPolygon); - } - }); - markerClusterGroup.on('clustermouseout', function (a) { - if (me._shownPolygon) { - map.removeLayer(me._shownPolygon); - me._shownPolygon = null; - } - }); - map.on('zoomend', function () { - if (me._shownPolygon) { - map.removeLayer(me._shownPolygon); - me._shownPolygon = null; - } - }); - } - }; -}()); - /* * L.MarkerClusterGroup extends L.FeatureGroup by clustering the markers contained within @@ -77,11 +14,18 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({ options: { maxClusterRadius: 60, //A cluster will cover at most this many pixels from its center - iconCreateFunction: L.MarkerClusterDefault ? L.MarkerClusterDefault.iconCreateFunction : null + iconCreateFunction: null, + + spiderfyOnMaxZoom: true, + showCoverageOnHover: true, + zoomToBoundsOnClick: true }, initialize: function (options) { L.Util.setOptions(this, options); + if (!this.options.iconCreateFunction) { + this.options.iconCreateFunction = this._defaultIconCreateFunction; + } L.FeatureGroup.prototype.initialize.call(this, []); @@ -91,6 +35,42 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({ this._currentShownBounds = null; }, + addLayer: function (layer) { + if (!this._map) { + this._needsClustering.push(layer); + return this; + } + + //If we have already clustered we'll need to add this one to a cluster + + var newCluster = this._topClusterLevel._recursivelyAddLayer(layer, this._topClusterLevel._zoom - 1); + + this._animationAddLayer(layer, newCluster); + + return this; + }, + + removeLayer: function (layer) { + this._topClusterLevel._recursivelyRemoveLayer(layer); + + return this; + }, + + //Overrides FeatureGroup.onAdd + onAdd: function (map) { + L.FeatureGroup.prototype.onAdd.call(this, map); + + this._generateInitialClusters(); + this._map.on('zoomend', this._zoomEnd, this); + this._map.on('moveend', this._moveEnd, this); + + if (this._spiderfierOnAdd) { //TODO FIXME: Not sure how to have spiderfier add something on here nicely + this._spiderfierOnAdd(); + } + + this._bindEvents(); + }, + //Overrides FeatureGroup._propagateEvent _propagateEvent: function (e) { if (e.target instanceof L.MarkerCluster) { @@ -99,6 +79,70 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({ L.FeatureGroup.prototype._propagateEvent.call(this, e); }, + //Default functionality + _defaultIconCreateFunction: function (childCount) { + var c = ' marker-cluster-'; + if (childCount < 10) { + c += 'small'; + } else if (childCount < 100) { + c += 'medium'; + } else { + c += 'large'; + } + + return new L.DivIcon({ html: '
' + childCount + '
', className: 'marker-cluster' + c, iconSize: new L.Point(40, 40) }); + }, + + _bindEvents: function () { + var shownPolygon = null, + map = this._map, + + spiderfyOnMaxZoom = this.options.spiderfyOnMaxZoom, + showCoverageOnHover = this.options.showCoverageOnHover, + zoomToBoundsOnClick = this.options.zoomToBoundsOnClick; + + //Zoom on cluster click or spiderfy if we are at the lowest level + if (spiderfyOnMaxZoom || zoomToBoundsOnClick) { + this.on('clusterclick', function (a) { + if (map.getMaxZoom() === map.getZoom()) { + if (spiderfyOnMaxZoom) { + a.layer.spiderfy(); + } + } else if (zoomToBoundsOnClick) { + a.layer.zoomToBounds(); + } + }, this); + } + + //Show convex hull (boundary) polygon on mouse over + if (showCoverageOnHover) { + this.on('clustermouseover', function (a) { + if (this._inZoomAnimation) { + return; + } + if (shownPolygon) { + map.removeLayer(shownPolygon); + } + if (a.layer.getChildCount() > 2) { + shownPolygon = new L.Polygon(a.layer.getConvexHull()); + map.addLayer(shownPolygon); + } + }, this); + this.on('clustermouseout', function () { + if (shownPolygon) { + map.removeLayer(shownPolygon); + shownPolygon = null; + } + }, this); + map.on('zoomend', function () { + if (shownPolygon) { + map.removeLayer(shownPolygon); + shownPolygon = null; + } + }, this); + } + }, + _sqDist: function (p1, p2) { var dx = p2.x - p1.x, dy = p2.y - p1.y; @@ -164,39 +208,6 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({ } }, - addLayer: function (layer) { - if (!this._map) { - this._needsClustering.push(layer); - return this; - } - - //If we have already clustered we'll need to add this one to a cluster - - var newCluster = this._topClusterLevel._recursivelyAddLayer(layer, this._topClusterLevel._zoom - 1); - - this._animationAddLayer(layer, newCluster); - - return this; - }, - - removeLayer: function (layer) { - this._topClusterLevel._recursivelyRemoveLayer(layer); - - return this; - }, - - onAdd: function (map) { - L.FeatureGroup.prototype.onAdd.call(this, map); // LayerGroup - - this._generateInitialClusters(); - this._map.on('zoomend', this._zoomEnd, this); - this._map.on('moveend', this._moveEnd, this); - - if (this._spiderfierOnAdd) { //TODO FIXME: Not sure how to have spiderfier add something on here nicely - this._spiderfierOnAdd(); - } - }, - //Takes a list of markers and clusters the new marker in to them //Will return null or the new MarkerCluster. The clustered in marker is removed from the given array _clusterOne: function (unclusteredMarkers, newMarker, zoom) { diff --git a/dist/leaflet.markercluster.js b/dist/leaflet.markercluster.js index a1b54410e..836917719 100644 --- a/dist/leaflet.markercluster.js +++ b/dist/leaflet.markercluster.js @@ -3,4 +3,4 @@ Leaflet.markercluster is an open-source JavaScript library for Marker Clustering on leaflet powered maps. https://github.com/danzel/Leaflet.markercluster */ -(function(e,t){(function(){L.MarkerClusterDefault={iconCreateFunction:function(e){var t=" marker-cluster-";return e<10?t+="small":e<100?t+="medium":t+="large",new L.DivIcon({html:"
"+e+"
",className:"marker-cluster"+t,iconSize:new L.Point(40,40)})},_shownPolygon:null,bindEvents:function(e,t){var n=this,r=!1;e.on("zoomstart",function(){r=!0}),e.on("zoomend",function(){r=!1}),t.on("clusterclick",function(t){e.getMaxZoom()===e.getZoom()?t.layer.spiderfy():t.layer.zoomToBounds()}),t.on("clustermouseover",function(t){if(r)return;n._shownPolygon&&e.removeLayer(n._shownPolygon),t.layer.getChildCount()>2&&(n._shownPolygon=new L.Polygon(t.layer.getConvexHull()),e.addLayer(n._shownPolygon))}),t.on("clustermouseout",function(t){n._shownPolygon&&(e.removeLayer(n._shownPolygon),n._shownPolygon=null)}),e.on("zoomend",function(){n._shownPolygon&&(e.removeLayer(n._shownPolygon),n._shownPolygon=null)})}}})(),L.MarkerClusterGroup=L.FeatureGroup.extend({options:{maxClusterRadius:60,iconCreateFunction:L.MarkerClusterDefault?L.MarkerClusterDefault.iconCreateFunction:null},initialize:function(e){L.Util.setOptions(this,e),L.FeatureGroup.prototype.initialize.call(this,[]),this._inZoomAnimation=0,this._needsClustering=[],this._currentShownBounds=null},_propagateEvent:function(e){e.target instanceof L.MarkerCluster&&(e.type="cluster"+e.type),L.FeatureGroup.prototype._propagateEvent.call(this,e)},_sqDist:function(e,t){var n=t.x-e.x,r=t.y-e.y;return n*n+r*r},_zoomEnd:function(){this._animationStart(),this._mergeSplitClusters(),this._zoom=this._map._zoom,this._currentShownBounds=this._getExpandedVisibleBounds()},_moveEnd:function(){if(this._inZoomAnimation>0)return;var e=this._getExpandedVisibleBounds(),t=this._zoom-this._topClusterLevel._zoom;this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds,t,e),this._topClusterLevel._recursivelyAddChildrenToMap(null,t+1,e),this._currentShownBounds=e;return},_generateInitialClusters:function(){var e=this._map.getMinZoom(),t=this._map.getMaxZoom(),n=this._map.getZoom();this._topClusterLevel=this._clusterToMarkerCluster(this._needsClustering,t);while(ethis._map._zoom&&this._animationZoomOut(this._zoom,this._map._zoom)},addLayer:function(e){if(!this._map)return this._needsClustering.push(e),this;var t=this._topClusterLevel._recursivelyAddLayer(e,this._topClusterLevel._zoom-1);return this._animationAddLayer(e,t),this},removeLayer:function(e){return this._topClusterLevel._recursivelyRemoveLayer(e),this},onAdd:function(e){L.FeatureGroup.prototype.onAdd.call(this,e),this._generateInitialClusters(),this._map.on("zoomend",this._zoomEnd,this),this._map.on("moveend",this._moveEnd,this),this._spiderfierOnAdd&&this._spiderfierOnAdd()},_clusterOne:function(e,t,n){var r=t._projCenter||this._map.project(t.getLatLng(),n),i=2*this.options.maxClusterRadius*2*this.options.maxClusterRadius,s,o,u;for(s=e.length-1;s>=0;s--){o=e[s],u=o._projCenter||this._map.project(o.getLatLng(),n);if(this._sqDist(r,u)<=i){var a=new L.MarkerCluster(this,o,t);return e.splice(s,1),a}}return null},_cluster:function(e,t){var n=this.options.maxClusterRadius*this.options.maxClusterRadius,r=[],i=[],s,o,u;for(s=e.length-1;s>=0;s--){var a=e[s],f=!1;a._projCenter=this._map.project(a.getLatLng(),t);for(o=r.length-1;o>=0;o--){u=r[o];if(this._sqDist(a._projCenter,u._projCenter)<=n){u._addChild(a),u._projCenter=this._map.project(u.getLatLng(),t),f=!0;break}}if(!f){var l=this._clusterOne(i,a);l?(l._projCenter=this._map.project(l.getLatLng(),t),r.push(l)):i.push(a)}}for(s=i.length-1;s>=0;s--){u=i[s],delete u._projCenter;if(u instanceof L.MarkerCluster){var c=new L.MarkerCluster(this,u);c._haveGeneratedChildClusters=!0,r.push(c),i.splice(s,1)}}for(s=r.length-1;s>=0;s--)delete r[s]._projCenter,r[s]._baseInit();return{clusters:r,unclustered:i}},_clusterToMarkerCluster:function(e,t){var n=this._cluster(e,t),r=n.clusters.concat(n.unclustered),i=new L.MarkerCluster(this,r[0]),s;for(s=r.length-1;s>0;s--)i._addChild(r[s]);return i._zoom=t,i._haveGeneratedChildClusters=!0,i},_getExpandedVisibleBounds:function(){var e=this._map,t=e.getPixelBounds(),n=Math.abs(t.max.x-t.min.x),r=Math.abs(t.max.y-t.min.y),i=e.unproject(new L.Point(t.min.x-n,t.min.y-r)),s=e.unproject(new L.Point(t.max.x+n,t.max.y+r));return new L.LatLngBounds(i,s)}}),L.MarkerClusterGroup.include(L.DomUtil.TRANSITION?{_animationStart:function(){this._map._mapPane.className+=" leaflet-cluster-anim"},_animationEnd:function(){this._map._mapPane.className=this._map._mapPane.className.replace(" leaflet-cluster-anim",""),this._inZoomAnimation--},_animationZoomIn:function(e,t){var n=this,r=this._getExpandedVisibleBounds(),i,s=1+e-this._topClusterLevel._zoom,o=t-e;this._topClusterLevel._recursively(r,s,0,function(e){var t=e._latlng,s=e._markers,u;e._isSingleParent()&&o===1?(L.FeatureGroup.prototype.removeLayer.call(n,e),e._recursivelyAddChildrenToMap(null,o,r)):(e.setOpacity(0),e._recursivelyAddChildrenToMap(t,o,r));for(i=s.length-1;i>=0;i--)u=s[i],r.contains(u._latlng)||L.FeatureGroup.prototype.removeLayer.call(n,u)}),this._forceLayout();var u,a;n._topClusterLevel._recursivelyBecomeVisible(r,s+o);for(u in n._layers)n._layers.hasOwnProperty(u)&&(a=n._layers[u],!(a instanceof L.MarkerCluster)&&a._icon&&a.setOpacity(1));n._topClusterLevel._recursively(r,s,0,function(e){e._recursivelyRestoreChildPositions(o)}),this._inZoomAnimation++,setTimeout(function(){n._topClusterLevel._recursively(r,s,0,function(e){L.FeatureGroup.prototype.removeLayer.call(n,e)}),n._animationEnd()},250)},_animationZoomOut:function(e,t){var n=1+t-this._topClusterLevel._zoom,r=e-t;this._animationZoomOutSingle(this._topClusterLevel,n,r),this._topClusterLevel._recursivelyAddChildrenToMap(null,n,this._getExpandedVisibleBounds())},_animationZoomOutSingle:function(e,t,n){var r=this._getExpandedVisibleBounds();e._recursivelyAnimateChildrenInAndAddSelfToMap(r,t,n),this._inZoomAnimation++;var i=this;this._forceLayout(),e._recursivelyBecomeVisible(r,t),setTimeout(function(){e._recursively(r,t,0,null,function(e){e._recursivelyRemoveChildrenFromMap(r,n-1)}),i._animationEnd()},250)},_animationAddLayer:function(e,t){var n=this;L.FeatureGroup.prototype.addLayer.call(this,e);if(t!==!0)if(t._childCount>2){this._forceLayout(),this._animationStart();var r=e.getLatLng();e.setLatLng(t._latlng),e.setOpacity(0),setTimeout(function(){L.FeatureGroup.prototype.removeLayer.call(n,e),e.setLatLng(r),n._animationEnd()},250)}else this._forceLayout(),n._animationStart(),n._animationZoomOutSingle(t,0,this._map.getMaxZoom())},_forceLayout:function(){L.Util.falseFn(document.body.offsetWidth)}}:{_animationStart:function(){},_animationZoomIn:function(e,t){this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds,e-this._topClusterLevel._zoom),this._topClusterLevel._recursivelyAddChildrenToMap(null,t-this._topClusterLevel._zoom+1,this._getExpandedVisibleBounds())},_animationZoomOut:function(e,t){this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds,e-this._topClusterLevel._zoom),this._topClusterLevel._recursivelyAddChildrenToMap(null,t-this._topClusterLevel._zoom+1,this._getExpandedVisibleBounds())},_animationAddLayer:function(e,t){t===!0?L.FeatureGroup.prototype.addLayer.call(this,e):t._childCount===2&&(t._addToMap(),t._recursivelyRemoveChildrenFromMap(t._bounds,this._map.getMaxZoom()))}}),L.MarkerCluster=L.Marker.extend({initialize:function(e,t,n){this._group=e,this._markers=[],this._childClusters=[],this._childCount=0,this._bounds=new L.LatLngBounds,this._addChild(t),n&&this._addChild(n)},getAllChildMarkers:function(e){e=e||[];for(var t=this._childClusters.length-1;t>=0;t--)this._childClusters[t].getAllChildMarkers(e);for(var n=this._markers.length-1;n>=0;n--)e.push(this._markers[n]);return e},getChildCount:function(){return this._childCount},zoomToBounds:function(){this._group._map.fitBounds(this._bounds)},_baseInit:function(){L.Marker.prototype.initialize.call(this,this._latlng,{icon:this._group.options.iconCreateFunction(this._childCount)})},_addChild:function(e){e instanceof L.MarkerCluster?(this._childClusters.push(e),this._childCount+=e._childCount):(this._markers.push(e),this._childCount++),this._icon&&this.setIcon(this._group.options.iconCreateFunction(this._childCount)),this._expandBounds(e)},_expandBounds:function(e){e instanceof L.MarkerCluster?this._bounds.extend(e._bounds):this._bounds.extend(e.getLatLng()),this._latlng=this._bounds.getCenter()},_addToMap:function(e){e&&(this._backupLatlng=this._latlng,this.setLatLng(e)),L.FeatureGroup.prototype.addLayer.call(this._group,this)},_recursivelyAddLayer:function(e,t){var n=!1;for(var r=this._childClusters.length-1;r>=0;r--){var i=this._childClusters[r];if(i._bounds.contains(e.getLatLng())||i._canAcceptPosition(e.getLatLng(),t+1)){n=i._recursivelyAddLayer(e,t+1);if(n){this._childCount++;break}}}if(!n&&(this._canAcceptPosition(e.getLatLng(),t)||this._zoom)){n=this._group._clusterOne(this._markers,e,t+1);if(n){n._baseInit(),this._childCount--,this._addChild(n);var s=this._group._map.getZoom()-1,o=this._group._map.getMaxZoom(),u,a=t===s?n:!0;while(t=0;i--)if(n[i]===e)return n[i]._icon&&L.FeatureGroup.prototype.removeLayer.call(t,n[i]),n.splice(i,1),this._recalculateBounds(),this._childCount--,"_zoom"in this||this.setIcon(t.options.iconCreateFunction(this._childCount)),!0;for(i=r.length-1;i>=0;i--){var s=r[i];if(s._bounds.contains(e._latlng)&&s._recursivelyRemoveLayer(e))return this._childCount--,"_zoom"in this||this.setIcon(t.options.iconCreateFunction(this._childCount)),s._childCount===1&&(s._icon&&(L.FeatureGroup.prototype.removeLayer.call(t,s),L.FeatureGroup.prototype.addLayer.call(t,s._markers[0])),n.push(s._markers[0]),r.splice(i,1)),this._recalculateBounds(),this._icon&&this._childCount>1&&this.setIcon(t.options.iconCreateFunction(this._childCount)),!0}return!1},_recursivelyAnimateChildrenIn:function(e,t,n){this._recursively(e,0,n-1,function(e){var n=e._markers,r,i;for(r=n.length-1;r>=0;r--)i=n[r],i._icon&&(i._setPos(t),i.setOpacity(0))},function(e){var n=e._childClusters,r,i;for(r=n.length-1;r>=0;r--)i=n[r],i._icon&&(i._setPos(t),i.setOpacity(0))})},_recursivelyAnimateChildrenInAndAddSelfToMap:function(e,t,n){this._recursively(e,t,0,function(t){t._recursivelyAnimateChildrenIn(e,t._group._map.latLngToLayerPoint(t.getLatLng()).round(),n),t._isSingleParent()&&n===1?(t.setOpacity(1),t._recursivelyRemoveChildrenFromMap(e,n-1)):t.setOpacity(0),t._addToMap()})},_recursivelyBecomeVisible:function(e,t){this._recursively(e,0,t,null,function(e){e.setOpacity(1)})},_recursivelyAddChildrenToMap:function(e,t,n){this._recursively(n,0,t,function(t,r){if(r===0)return;for(var i=t._markers.length-1;i>=0;i--){var s=t._markers[i];if(!n.contains(s._latlng))continue;e&&(s._backupLatlng=s.getLatLng(),s.setLatLng(e),s.setOpacity(0)),L.FeatureGroup.prototype.addLayer.call(t._group,s)}},function(t){t._addToMap(e)})},_recursivelyRestoreChildPositions:function(e){for(var t=this._markers.length-1;t>=0;t--){var n=this._markers[t];n._backupLatlng&&(n.setLatLng(n._backupLatlng),delete n._backupLatlng)}if(e===1)for(var r=this._childClusters.length-1;r>=0;r--)this._childClusters[r]._restorePosition();else for(var i=this._childClusters.length-1;i>=0;i--)this._childClusters[i]._recursivelyRestoreChildPositions(e-1)},_restorePosition:function(){this._backupLatlng&&(this.setLatLng(this._backupLatlng),delete this._backupLatlng)},_recursivelyRemoveChildrenFromMap:function(e,t,n){var r,i;this._recursively(e,0,t,function(e){for(i=e._markers.length-1;i>=0;i--){r=e._markers[i];if(!n||!n.contains(r._latlng))L.FeatureGroup.prototype.removeLayer.call(e._group,r),r.setOpacity(1)}},function(e){for(i=e._childClusters.length-1;i>=0;i--){r=e._childClusters[i];if(!n||!n.contains(r._latlng))L.FeatureGroup.prototype.removeLayer.call(e._group,r),r.setOpacity(1)}})},_recursively:function(e,t,n,r,i){var s=this._childClusters,o,u;if(t>0)for(o=s.length-1;o>=0;o--)u=s[o],e.intersects(u._bounds)&&u._recursively(e,t-1,n,r,i);else{r&&r(this,n),n===0&&i&&i(this);if(n>0)for(o=s.length-1;o>=0;o--)u=s[o],e.intersects(u._bounds)&&u._recursively(e,t,n-1,r,i)}},_recalculateBounds:function(){var e=this._markers,t=this._childClusters,n;this._bounds=new L.LatLngBounds;for(n=e.length-1;n>=0;n--)this._bounds.extend(e[n].getLatLng());for(n=t.length-1;n>=0;n--)this._bounds.extend(t[n]._bounds);this.setLatLng(this._bounds.getCenter())},_isSingleParent:function(){return this._childClusters.length>0&&this._childClusters[0]._childCount===this._childCount}}),function(){L.QuickHull={getDistant:function(e,t){var n=t[1].lat-t[0].lat,r=t[0].lng-t[1].lng;return r*(e.lat-t[0].lat)+n*(e.lng-t[0].lng)},findMostDistantPointFromBaseLine:function(e,t){var n=0,r=null,i=[],s,o,u;for(s=t.length-1;s>=0;s--){o=t[s],u=this.getDistant(o,e);if(!(u>0))continue;i.push(o),u>n&&(n=u,r=o)}return{maxPoint:r,newPoints:i}},buildConvexHull:function(e,t){var n=[],r=this.findMostDistantPointFromBaseLine(e,t);return r.maxPoint?(n=n.concat(this.buildConvexHull([e[0],r.maxPoint],r.newPoints)),n=n.concat(this.buildConvexHull([r.maxPoint,e[1]],r.newPoints)),n):[e]},getConvexHull:function(e){var t=!1,n=!1,r=null,i=null,s;for(s=e.length-1;s>=0;s--){var o=e[s];if(t===!1||o.lat>t)r=o,t=o.lat;if(n===!1||o.lat=0;s--)i=e[s].getLatLng(),t.push(i);r=L.QuickHull.getConvexHull(t);for(s=r.length-1;s>=0;s--)n.push(r[s][0]);return n}}),L.MarkerCluster.include({_2PI:Math.PI*2,_circleFootSeparation:25,_circleStartAngle:Math.PI/6,_spiralFootSeparation:28,_spiralLengthStart:11,_spiralLengthFactor:5,_circleSpiralSwitchover:9,spiderfy:function(){if(this._group._spiderfied===this)return;var e=this.getAllChildMarkers(),t=this._group,n=t._map,r=n.latLngToLayerPoint(this._latlng),i;this._group._unspiderfy(),this._group._spiderfied=this,e.length>=this._circleSpiralSwitchover?i=this._generatePointsSpiral(e.length,r):(r.y+=10,i=this._generatePointsCircle(e.length,r)),this._animationSpiderfy(e,i)},unspiderfy:function(){this._animationUnspiderfy(),this._group._spiderfied=null},_generatePointsCircle:function(e,t){var n=this._circleFootSeparation*(2+e),r=n/this._2PI,i=this._2PI/e,s=[],o,u;s.length=e;for(o=e-1;o>=0;o--)u=this._circleStartAngle+o*i,s[o]=new L.Point(t.x+r*Math.cos(u),t.y+r*Math.sin(u));return s},_generatePointsSpiral:function(e,t){var n=this._spiralLengthStart,r=0,i=[],s;i.length=e;for(s=e-1;s>=0;s--)r+=this._spiralFootSeparation/n+s*5e-4,i[s]=new L.Point(t.x+n*Math.cos(r),t.y+n*Math.sin(r)),n+=this._2PI*this._spiralLengthFactor/r;return i}}),L.MarkerCluster.include(L.DomUtil.TRANSITION?{_animationSpiderfy:function(e,t){var n=this,r=this._group,i=r._map,s,o,u;for(s=e.length-1;s>=0;s--)o=e[s],o._backupPosSpider=o._latlng,o.setLatLng(this._latlng),o.setZIndexOffset(1e6),o.setOpacity(0),L.FeatureGroup.prototype.addLayer.call(r,o);this._group._forceLayout(),r._animationStart();var a=L.Browser.svg?0:.3,f=L.Path.SVG_NS;for(s=e.length-1;s>=0;s--){o=e[s],o.setLatLng(i.layerPointToLatLng(t[s])),o.setOpacity(1),u=new L.Polyline([n._latlng,o._latlng],{weight:1.5,color:"#222",opacity:a}),i.addLayer(u),o._spiderLeg=u;if(!L.Browser.svg)continue;var l=u._path.getTotalLength();u._path.setAttribute("stroke-dasharray",l+","+l);var c=document.createElementNS(f,"animate");c.setAttribute("attributeName","stroke-dashoffset"),c.setAttribute("begin","indefinite"),c.setAttribute("from",l),c.setAttribute("to",0),c.setAttribute("dur",.25),u._path.appendChild(c),c.beginElement(),c=document.createElementNS(f,"animate"),c.setAttribute("attributeName","stroke-opacity"),c.setAttribute("attributeName","stroke-opacity"),c.setAttribute("begin","indefinite"),c.setAttribute("from",0),c.setAttribute("to",.5),c.setAttribute("dur",.25),u._path.appendChild(c),c.beginElement()}n.setOpacity(.3);if(L.Browser.svg){this._group._forceLayout();for(s=e.length-1;s>=0;s--)o=e[s]._spiderLeg,o.options.opacity=.5,o._path.setAttribute("stroke-opacity",.5)}setTimeout(function(){r._animationEnd()},250)},_animationUnspiderfy:function(){var e=this._group,t=e._map,n=this.getAllChildMarkers(),r=L.Browser.svg,i,s,o;e._animationStart(),this.setOpacity(1);for(s=n.length-1;s>=0;s--)i=n[s],i.setLatLng(this._latlng),i.setOpacity(0),r&&(o=i._spiderLeg._path.childNodes[0],o.setAttribute("to",o.getAttribute("from")),o.setAttribute("from",0),o.beginElement(),o=i._spiderLeg._path.childNodes[1],o.setAttribute("from",.5),o.setAttribute("to",0),o.setAttribute("stroke-opacity",0),o.beginElement(),i._spiderLeg._path.setAttribute("stroke-opacity",0));setTimeout(function(){for(s=n.length-1;s>=0;s--)i=n[s],i.setLatLng(i._backupPosSpider),delete i._backupPosSpider,i.setZIndexOffset(0),L.FeatureGroup.prototype.removeLayer.call(e,i),t.removeLayer(i._spiderLeg),delete i._spiderLeg},250)}}:{_animationSpiderfy:function(e,t){var n=this._group,r=n._map,i,s,o;for(i=e.length-1;i>=0;i--)s=e[i],s._backupPosSpider=s._latlng,s.setLatLng(r.layerPointToLatLng(t[i])),s.setZIndexOffset(1e6),L.FeatureGroup.prototype.addLayer.call(n,s),o=new L.Polyline([this._latlng,s._latlng],{weight:1.5,color:"#222"}),r.addLayer(o),s._spiderLeg=o;this.setOpacity(.3)},_animationUnspiderfy:function(){var e=this._group,t=e._map,n=this.getAllChildMarkers(),r,i;this.setOpacity(1);for(i=n.length-1;i>=0;i--)r=n[i],r.setLatLng(r._backupPosSpider),delete r._backupPosSpider,r.setZIndexOffset(0),L.FeatureGroup.prototype.removeLayer.call(e,r),t.removeLayer(r._spiderLeg),delete r._spiderLeg}}),L.MarkerClusterGroup.include({_spiderfied:null,_spiderfierOnAdd:function(){this._map.on("click zoomstart",this._unspiderfy,this),L.Browser.svg&&this._map._initPathRoot()},_unspiderfy:function(){this._spiderfied&&this._spiderfied.unspiderfy()}})})(this); \ No newline at end of file +(function(e,t){L.MarkerClusterGroup=L.FeatureGroup.extend({options:{maxClusterRadius:60,iconCreateFunction:null,spiderfyOnMaxZoom:!0,showCoverageOnHover:!0,zoomToBoundsOnClick:!0},initialize:function(e){L.Util.setOptions(this,e),this.options.iconCreateFunction||(this.options.iconCreateFunction=this._defaultIconCreateFunction),L.FeatureGroup.prototype.initialize.call(this,[]),this._inZoomAnimation=0,this._needsClustering=[],this._currentShownBounds=null},addLayer:function(e){if(!this._map)return this._needsClustering.push(e),this;var t=this._topClusterLevel._recursivelyAddLayer(e,this._topClusterLevel._zoom-1);return this._animationAddLayer(e,t),this},removeLayer:function(e){return this._topClusterLevel._recursivelyRemoveLayer(e),this},onAdd:function(e){L.FeatureGroup.prototype.onAdd.call(this,e),this._generateInitialClusters(),this._map.on("zoomend",this._zoomEnd,this),this._map.on("moveend",this._moveEnd,this),this._spiderfierOnAdd&&this._spiderfierOnAdd(),this._bindEvents()},_propagateEvent:function(e){e.target instanceof L.MarkerCluster&&(e.type="cluster"+e.type),L.FeatureGroup.prototype._propagateEvent.call(this,e)},_defaultIconCreateFunction:function(e){var t=" marker-cluster-";return e<10?t+="small":e<100?t+="medium":t+="large",new L.DivIcon({html:"
"+e+"
",className:"marker-cluster"+t,iconSize:new L.Point(40,40)})},_bindEvents:function(){var e=null,t=this._map,n=this.options.spiderfyOnMaxZoom,r=this.options.showCoverageOnHover,i=this.options.zoomToBoundsOnClick;(n||i)&&this.on("clusterclick",function(e){t.getMaxZoom()===t.getZoom()?n&&e.layer.spiderfy():i&&e.layer.zoomToBounds()},this),r&&(this.on("clustermouseover",function(n){if(this._inZoomAnimation)return;e&&t.removeLayer(e),n.layer.getChildCount()>2&&(e=new L.Polygon(n.layer.getConvexHull()),t.addLayer(e))},this),this.on("clustermouseout",function(){e&&(t.removeLayer(e),e=null)},this),t.on("zoomend",function(){e&&(t.removeLayer(e),e=null)},this))},_sqDist:function(e,t){var n=t.x-e.x,r=t.y-e.y;return n*n+r*r},_zoomEnd:function(){this._animationStart(),this._mergeSplitClusters(),this._zoom=this._map._zoom,this._currentShownBounds=this._getExpandedVisibleBounds()},_moveEnd:function(){if(this._inZoomAnimation>0)return;var e=this._getExpandedVisibleBounds(),t=this._zoom-this._topClusterLevel._zoom;this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds,t,e),this._topClusterLevel._recursivelyAddChildrenToMap(null,t+1,e),this._currentShownBounds=e;return},_generateInitialClusters:function(){var e=this._map.getMinZoom(),t=this._map.getMaxZoom(),n=this._map.getZoom();this._topClusterLevel=this._clusterToMarkerCluster(this._needsClustering,t);while(ethis._map._zoom&&this._animationZoomOut(this._zoom,this._map._zoom)},_clusterOne:function(e,t,n){var r=t._projCenter||this._map.project(t.getLatLng(),n),i=2*this.options.maxClusterRadius*2*this.options.maxClusterRadius,s,o,u;for(s=e.length-1;s>=0;s--){o=e[s],u=o._projCenter||this._map.project(o.getLatLng(),n);if(this._sqDist(r,u)<=i){var a=new L.MarkerCluster(this,o,t);return e.splice(s,1),a}}return null},_cluster:function(e,t){var n=this.options.maxClusterRadius*this.options.maxClusterRadius,r=[],i=[],s,o,u;for(s=e.length-1;s>=0;s--){var a=e[s],f=!1;a._projCenter=this._map.project(a.getLatLng(),t);for(o=r.length-1;o>=0;o--){u=r[o];if(this._sqDist(a._projCenter,u._projCenter)<=n){u._addChild(a),u._projCenter=this._map.project(u.getLatLng(),t),f=!0;break}}if(!f){var l=this._clusterOne(i,a);l?(l._projCenter=this._map.project(l.getLatLng(),t),r.push(l)):i.push(a)}}for(s=i.length-1;s>=0;s--){u=i[s],delete u._projCenter;if(u instanceof L.MarkerCluster){var c=new L.MarkerCluster(this,u);c._haveGeneratedChildClusters=!0,r.push(c),i.splice(s,1)}}for(s=r.length-1;s>=0;s--)delete r[s]._projCenter,r[s]._baseInit();return{clusters:r,unclustered:i}},_clusterToMarkerCluster:function(e,t){var n=this._cluster(e,t),r=n.clusters.concat(n.unclustered),i=new L.MarkerCluster(this,r[0]),s;for(s=r.length-1;s>0;s--)i._addChild(r[s]);return i._zoom=t,i._haveGeneratedChildClusters=!0,i},_getExpandedVisibleBounds:function(){var e=this._map,t=e.getPixelBounds(),n=Math.abs(t.max.x-t.min.x),r=Math.abs(t.max.y-t.min.y),i=e.unproject(new L.Point(t.min.x-n,t.min.y-r)),s=e.unproject(new L.Point(t.max.x+n,t.max.y+r));return new L.LatLngBounds(i,s)}}),L.MarkerClusterGroup.include(L.DomUtil.TRANSITION?{_animationStart:function(){this._map._mapPane.className+=" leaflet-cluster-anim"},_animationEnd:function(){this._map._mapPane.className=this._map._mapPane.className.replace(" leaflet-cluster-anim",""),this._inZoomAnimation--},_animationZoomIn:function(e,t){var n=this,r=this._getExpandedVisibleBounds(),i,s=1+e-this._topClusterLevel._zoom,o=t-e;this._topClusterLevel._recursively(r,s,0,function(e){var t=e._latlng,s=e._markers,u;e._isSingleParent()&&o===1?(L.FeatureGroup.prototype.removeLayer.call(n,e),e._recursivelyAddChildrenToMap(null,o,r)):(e.setOpacity(0),e._recursivelyAddChildrenToMap(t,o,r));for(i=s.length-1;i>=0;i--)u=s[i],r.contains(u._latlng)||L.FeatureGroup.prototype.removeLayer.call(n,u)}),this._forceLayout();var u,a;n._topClusterLevel._recursivelyBecomeVisible(r,s+o);for(u in n._layers)n._layers.hasOwnProperty(u)&&(a=n._layers[u],!(a instanceof L.MarkerCluster)&&a._icon&&a.setOpacity(1));n._topClusterLevel._recursively(r,s,0,function(e){e._recursivelyRestoreChildPositions(o)}),this._inZoomAnimation++,setTimeout(function(){n._topClusterLevel._recursively(r,s,0,function(e){L.FeatureGroup.prototype.removeLayer.call(n,e)}),n._animationEnd()},250)},_animationZoomOut:function(e,t){var n=1+t-this._topClusterLevel._zoom,r=e-t;this._animationZoomOutSingle(this._topClusterLevel,n,r),this._topClusterLevel._recursivelyAddChildrenToMap(null,n,this._getExpandedVisibleBounds())},_animationZoomOutSingle:function(e,t,n){var r=this._getExpandedVisibleBounds();e._recursivelyAnimateChildrenInAndAddSelfToMap(r,t,n),this._inZoomAnimation++;var i=this;this._forceLayout(),e._recursivelyBecomeVisible(r,t),setTimeout(function(){e._recursively(r,t,0,null,function(e){e._recursivelyRemoveChildrenFromMap(r,n-1)}),i._animationEnd()},250)},_animationAddLayer:function(e,t){var n=this;L.FeatureGroup.prototype.addLayer.call(this,e);if(t!==!0)if(t._childCount>2){this._forceLayout(),this._animationStart();var r=e.getLatLng();e.setLatLng(t._latlng),e.setOpacity(0),setTimeout(function(){L.FeatureGroup.prototype.removeLayer.call(n,e),e.setLatLng(r),n._animationEnd()},250)}else this._forceLayout(),n._animationStart(),n._animationZoomOutSingle(t,0,this._map.getMaxZoom())},_forceLayout:function(){L.Util.falseFn(document.body.offsetWidth)}}:{_animationStart:function(){},_animationZoomIn:function(e,t){this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds,e-this._topClusterLevel._zoom),this._topClusterLevel._recursivelyAddChildrenToMap(null,t-this._topClusterLevel._zoom+1,this._getExpandedVisibleBounds())},_animationZoomOut:function(e,t){this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds,e-this._topClusterLevel._zoom),this._topClusterLevel._recursivelyAddChildrenToMap(null,t-this._topClusterLevel._zoom+1,this._getExpandedVisibleBounds())},_animationAddLayer:function(e,t){t===!0?L.FeatureGroup.prototype.addLayer.call(this,e):t._childCount===2&&(t._addToMap(),t._recursivelyRemoveChildrenFromMap(t._bounds,this._map.getMaxZoom()))}}),L.MarkerCluster=L.Marker.extend({initialize:function(e,t,n){this._group=e,this._markers=[],this._childClusters=[],this._childCount=0,this._bounds=new L.LatLngBounds,this._addChild(t),n&&this._addChild(n)},getAllChildMarkers:function(e){e=e||[];for(var t=this._childClusters.length-1;t>=0;t--)this._childClusters[t].getAllChildMarkers(e);for(var n=this._markers.length-1;n>=0;n--)e.push(this._markers[n]);return e},getChildCount:function(){return this._childCount},zoomToBounds:function(){this._group._map.fitBounds(this._bounds)},_baseInit:function(){L.Marker.prototype.initialize.call(this,this._latlng,{icon:this._group.options.iconCreateFunction(this._childCount)})},_addChild:function(e){e instanceof L.MarkerCluster?(this._childClusters.push(e),this._childCount+=e._childCount):(this._markers.push(e),this._childCount++),this._icon&&this.setIcon(this._group.options.iconCreateFunction(this._childCount)),this._expandBounds(e)},_expandBounds:function(e){e instanceof L.MarkerCluster?this._bounds.extend(e._bounds):this._bounds.extend(e.getLatLng()),this._latlng=this._bounds.getCenter()},_addToMap:function(e){e&&(this._backupLatlng=this._latlng,this.setLatLng(e)),L.FeatureGroup.prototype.addLayer.call(this._group,this)},_recursivelyAddLayer:function(e,t){var n=!1;for(var r=this._childClusters.length-1;r>=0;r--){var i=this._childClusters[r];if(i._bounds.contains(e.getLatLng())||i._canAcceptPosition(e.getLatLng(),t+1)){n=i._recursivelyAddLayer(e,t+1);if(n){this._childCount++;break}}}if(!n&&(this._canAcceptPosition(e.getLatLng(),t)||this._zoom)){n=this._group._clusterOne(this._markers,e,t+1);if(n){n._baseInit(),this._childCount--,this._addChild(n);var s=this._group._map.getZoom()-1,o=this._group._map.getMaxZoom(),u,a=t===s?n:!0;while(t=0;i--)if(n[i]===e)return n[i]._icon&&L.FeatureGroup.prototype.removeLayer.call(t,n[i]),n.splice(i,1),this._recalculateBounds(),this._childCount--,"_zoom"in this||this.setIcon(t.options.iconCreateFunction(this._childCount)),!0;for(i=r.length-1;i>=0;i--){var s=r[i];if(s._bounds.contains(e._latlng)&&s._recursivelyRemoveLayer(e))return this._childCount--,"_zoom"in this||this.setIcon(t.options.iconCreateFunction(this._childCount)),s._childCount===1&&(s._icon&&(L.FeatureGroup.prototype.removeLayer.call(t,s),L.FeatureGroup.prototype.addLayer.call(t,s._markers[0])),n.push(s._markers[0]),r.splice(i,1)),this._recalculateBounds(),this._icon&&this._childCount>1&&this.setIcon(t.options.iconCreateFunction(this._childCount)),!0}return!1},_recursivelyAnimateChildrenIn:function(e,t,n){this._recursively(e,0,n-1,function(e){var n=e._markers,r,i;for(r=n.length-1;r>=0;r--)i=n[r],i._icon&&(i._setPos(t),i.setOpacity(0))},function(e){var n=e._childClusters,r,i;for(r=n.length-1;r>=0;r--)i=n[r],i._icon&&(i._setPos(t),i.setOpacity(0))})},_recursivelyAnimateChildrenInAndAddSelfToMap:function(e,t,n){this._recursively(e,t,0,function(t){t._recursivelyAnimateChildrenIn(e,t._group._map.latLngToLayerPoint(t.getLatLng()).round(),n),t._isSingleParent()&&n===1?(t.setOpacity(1),t._recursivelyRemoveChildrenFromMap(e,n-1)):t.setOpacity(0),t._addToMap()})},_recursivelyBecomeVisible:function(e,t){this._recursively(e,0,t,null,function(e){e.setOpacity(1)})},_recursivelyAddChildrenToMap:function(e,t,n){this._recursively(n,0,t,function(t,r){if(r===0)return;for(var i=t._markers.length-1;i>=0;i--){var s=t._markers[i];if(!n.contains(s._latlng))continue;e&&(s._backupLatlng=s.getLatLng(),s.setLatLng(e),s.setOpacity(0)),L.FeatureGroup.prototype.addLayer.call(t._group,s)}},function(t){t._addToMap(e)})},_recursivelyRestoreChildPositions:function(e){for(var t=this._markers.length-1;t>=0;t--){var n=this._markers[t];n._backupLatlng&&(n.setLatLng(n._backupLatlng),delete n._backupLatlng)}if(e===1)for(var r=this._childClusters.length-1;r>=0;r--)this._childClusters[r]._restorePosition();else for(var i=this._childClusters.length-1;i>=0;i--)this._childClusters[i]._recursivelyRestoreChildPositions(e-1)},_restorePosition:function(){this._backupLatlng&&(this.setLatLng(this._backupLatlng),delete this._backupLatlng)},_recursivelyRemoveChildrenFromMap:function(e,t,n){var r,i;this._recursively(e,0,t,function(e){for(i=e._markers.length-1;i>=0;i--){r=e._markers[i];if(!n||!n.contains(r._latlng))L.FeatureGroup.prototype.removeLayer.call(e._group,r),r.setOpacity(1)}},function(e){for(i=e._childClusters.length-1;i>=0;i--){r=e._childClusters[i];if(!n||!n.contains(r._latlng))L.FeatureGroup.prototype.removeLayer.call(e._group,r),r.setOpacity(1)}})},_recursively:function(e,t,n,r,i){var s=this._childClusters,o,u;if(t>0)for(o=s.length-1;o>=0;o--)u=s[o],e.intersects(u._bounds)&&u._recursively(e,t-1,n,r,i);else{r&&r(this,n),n===0&&i&&i(this);if(n>0)for(o=s.length-1;o>=0;o--)u=s[o],e.intersects(u._bounds)&&u._recursively(e,t,n-1,r,i)}},_recalculateBounds:function(){var e=this._markers,t=this._childClusters,n;this._bounds=new L.LatLngBounds;for(n=e.length-1;n>=0;n--)this._bounds.extend(e[n].getLatLng());for(n=t.length-1;n>=0;n--)this._bounds.extend(t[n]._bounds);this.setLatLng(this._bounds.getCenter())},_isSingleParent:function(){return this._childClusters.length>0&&this._childClusters[0]._childCount===this._childCount}}),function(){L.QuickHull={getDistant:function(e,t){var n=t[1].lat-t[0].lat,r=t[0].lng-t[1].lng;return r*(e.lat-t[0].lat)+n*(e.lng-t[0].lng)},findMostDistantPointFromBaseLine:function(e,t){var n=0,r=null,i=[],s,o,u;for(s=t.length-1;s>=0;s--){o=t[s],u=this.getDistant(o,e);if(!(u>0))continue;i.push(o),u>n&&(n=u,r=o)}return{maxPoint:r,newPoints:i}},buildConvexHull:function(e,t){var n=[],r=this.findMostDistantPointFromBaseLine(e,t);return r.maxPoint?(n=n.concat(this.buildConvexHull([e[0],r.maxPoint],r.newPoints)),n=n.concat(this.buildConvexHull([r.maxPoint,e[1]],r.newPoints)),n):[e]},getConvexHull:function(e){var t=!1,n=!1,r=null,i=null,s;for(s=e.length-1;s>=0;s--){var o=e[s];if(t===!1||o.lat>t)r=o,t=o.lat;if(n===!1||o.lat=0;s--)i=e[s].getLatLng(),t.push(i);r=L.QuickHull.getConvexHull(t);for(s=r.length-1;s>=0;s--)n.push(r[s][0]);return n}}),L.MarkerCluster.include({_2PI:Math.PI*2,_circleFootSeparation:25,_circleStartAngle:Math.PI/6,_spiralFootSeparation:28,_spiralLengthStart:11,_spiralLengthFactor:5,_circleSpiralSwitchover:9,spiderfy:function(){if(this._group._spiderfied===this)return;var e=this.getAllChildMarkers(),t=this._group,n=t._map,r=n.latLngToLayerPoint(this._latlng),i;this._group._unspiderfy(),this._group._spiderfied=this,e.length>=this._circleSpiralSwitchover?i=this._generatePointsSpiral(e.length,r):(r.y+=10,i=this._generatePointsCircle(e.length,r)),this._animationSpiderfy(e,i)},unspiderfy:function(){this._animationUnspiderfy(),this._group._spiderfied=null},_generatePointsCircle:function(e,t){var n=this._circleFootSeparation*(2+e),r=n/this._2PI,i=this._2PI/e,s=[],o,u;s.length=e;for(o=e-1;o>=0;o--)u=this._circleStartAngle+o*i,s[o]=new L.Point(t.x+r*Math.cos(u),t.y+r*Math.sin(u));return s},_generatePointsSpiral:function(e,t){var n=this._spiralLengthStart,r=0,i=[],s;i.length=e;for(s=e-1;s>=0;s--)r+=this._spiralFootSeparation/n+s*5e-4,i[s]=new L.Point(t.x+n*Math.cos(r),t.y+n*Math.sin(r)),n+=this._2PI*this._spiralLengthFactor/r;return i}}),L.MarkerCluster.include(L.DomUtil.TRANSITION?{_animationSpiderfy:function(e,t){var n=this,r=this._group,i=r._map,s,o,u;for(s=e.length-1;s>=0;s--)o=e[s],o._backupPosSpider=o._latlng,o.setLatLng(this._latlng),o.setZIndexOffset(1e6),o.setOpacity(0),L.FeatureGroup.prototype.addLayer.call(r,o);this._group._forceLayout(),r._animationStart();var a=L.Browser.svg?0:.3,f=L.Path.SVG_NS;for(s=e.length-1;s>=0;s--){o=e[s],o.setLatLng(i.layerPointToLatLng(t[s])),o.setOpacity(1),u=new L.Polyline([n._latlng,o._latlng],{weight:1.5,color:"#222",opacity:a}),i.addLayer(u),o._spiderLeg=u;if(!L.Browser.svg)continue;var l=u._path.getTotalLength();u._path.setAttribute("stroke-dasharray",l+","+l);var c=document.createElementNS(f,"animate");c.setAttribute("attributeName","stroke-dashoffset"),c.setAttribute("begin","indefinite"),c.setAttribute("from",l),c.setAttribute("to",0),c.setAttribute("dur",.25),u._path.appendChild(c),c.beginElement(),c=document.createElementNS(f,"animate"),c.setAttribute("attributeName","stroke-opacity"),c.setAttribute("attributeName","stroke-opacity"),c.setAttribute("begin","indefinite"),c.setAttribute("from",0),c.setAttribute("to",.5),c.setAttribute("dur",.25),u._path.appendChild(c),c.beginElement()}n.setOpacity(.3);if(L.Browser.svg){this._group._forceLayout();for(s=e.length-1;s>=0;s--)o=e[s]._spiderLeg,o.options.opacity=.5,o._path.setAttribute("stroke-opacity",.5)}setTimeout(function(){r._animationEnd()},250)},_animationUnspiderfy:function(){var e=this._group,t=e._map,n=this.getAllChildMarkers(),r=L.Browser.svg,i,s,o;e._animationStart(),this.setOpacity(1);for(s=n.length-1;s>=0;s--)i=n[s],i.setLatLng(this._latlng),i.setOpacity(0),r&&(o=i._spiderLeg._path.childNodes[0],o.setAttribute("to",o.getAttribute("from")),o.setAttribute("from",0),o.beginElement(),o=i._spiderLeg._path.childNodes[1],o.setAttribute("from",.5),o.setAttribute("to",0),o.setAttribute("stroke-opacity",0),o.beginElement(),i._spiderLeg._path.setAttribute("stroke-opacity",0));setTimeout(function(){for(s=n.length-1;s>=0;s--)i=n[s],i.setLatLng(i._backupPosSpider),delete i._backupPosSpider,i.setZIndexOffset(0),L.FeatureGroup.prototype.removeLayer.call(e,i),t.removeLayer(i._spiderLeg),delete i._spiderLeg},250)}}:{_animationSpiderfy:function(e,t){var n=this._group,r=n._map,i,s,o;for(i=e.length-1;i>=0;i--)s=e[i],s._backupPosSpider=s._latlng,s.setLatLng(r.layerPointToLatLng(t[i])),s.setZIndexOffset(1e6),L.FeatureGroup.prototype.addLayer.call(n,s),o=new L.Polyline([this._latlng,s._latlng],{weight:1.5,color:"#222"}),r.addLayer(o),s._spiderLeg=o;this.setOpacity(.3)},_animationUnspiderfy:function(){var e=this._group,t=e._map,n=this.getAllChildMarkers(),r,i;this.setOpacity(1);for(i=n.length-1;i>=0;i--)r=n[i],r.setLatLng(r._backupPosSpider),delete r._backupPosSpider,r.setZIndexOffset(0),L.FeatureGroup.prototype.removeLayer.call(e,r),t.removeLayer(r._spiderLeg),delete r._spiderLeg}}),L.MarkerClusterGroup.include({_spiderfied:null,_spiderfierOnAdd:function(){this._map.on("click zoomstart",this._unspiderfy,this),L.Browser.svg&&this._map._initPathRoot()},_unspiderfy:function(){this._spiderfied&&this._spiderfied.unspiderfy()}})})(this); \ No newline at end of file diff --git a/example/marker-clustering-convexhull.html b/example/marker-clustering-convexhull.html index 1028a40a7..17662aba0 100644 --- a/example/marker-clustering-convexhull.html +++ b/example/marker-clustering-convexhull.html @@ -12,7 +12,6 @@ - @@ -32,7 +31,7 @@ var map = new L.Map('map', {center: latlng, zoom: 15, layers: [cloudmade]}); - var markers = new L.MarkerClusterGroup(); + var markers = new L.MarkerClusterGroup({ spiderfyOnMaxZoom: false, showCoverageOnHover: false, zoomToBoundsOnClick: false }); function populate() { for (var i = 0; i < 100; i++) { diff --git a/example/marker-clustering-custom.html b/example/marker-clustering-custom.html index c9f8c6b0d..e461caf44 100644 --- a/example/marker-clustering-custom.html +++ b/example/marker-clustering-custom.html @@ -45,7 +45,9 @@ maxClusterRadius: 120, iconCreateFunction: function (count) { return new L.DivIcon({ html: count, className: 'mycluster', iconSize: new L.Point(40, 40) }); - } + }, + //Disable all of the defaults: + spiderfyOnMaxZoom: false, showCoverageOnHover: false, zoomToBoundsOnClick: false }); diff --git a/example/marker-clustering-spiderfier.html b/example/marker-clustering-spiderfier.html index e77a9dd69..2b35e1547 100644 --- a/example/marker-clustering-spiderfier.html +++ b/example/marker-clustering-spiderfier.html @@ -12,7 +12,6 @@ - @@ -32,7 +31,7 @@ var map = new L.Map('map', {center: latlng, zoom: 15, layers: [cloudmade]}); - var markers = new L.MarkerClusterGroup(); + var markers = new L.MarkerClusterGroup({ spiderfyOnMaxZoom: false, showCoverageOnHover: false, zoomToBoundsOnClick: false }); function populate() { for (var i = 0; i < 100; i++) { diff --git a/example/marker-clustering-zoomtobounds.html b/example/marker-clustering-zoomtobounds.html index 3a8777479..aedb2bf04 100644 --- a/example/marker-clustering-zoomtobounds.html +++ b/example/marker-clustering-zoomtobounds.html @@ -12,7 +12,6 @@ - @@ -30,7 +29,7 @@ var map = new L.Map('map', {center: latlng, zoom: 15, layers: [cloudmade]}); - var markers = new L.MarkerClusterGroup(); + var markers = new L.MarkerClusterGroup({spiderfyOnMaxZoom: false, showCoverageOnHover: false, zoomToBoundsOnClick: false}); function populate() { for (var i = 0; i < 100; i++) { diff --git a/example/marker-clustering.html b/example/marker-clustering.html index 5732344ea..157600b39 100644 --- a/example/marker-clustering.html +++ b/example/marker-clustering.html @@ -12,7 +12,6 @@ - diff --git a/src/MarkerCluster.Default.js b/src/MarkerCluster.Default.js deleted file mode 100644 index 903bc11d9..000000000 --- a/src/MarkerCluster.Default.js +++ /dev/null @@ -1,62 +0,0 @@ -(function () { - L.MarkerClusterDefault = { - iconCreateFunction: function (childCount) { - var c = ' marker-cluster-'; - if (childCount < 10) { - c += 'small'; - } else if (childCount < 100) { - c += 'medium'; - } else { - c += 'large'; - } - - return new L.DivIcon({ html: '
' + childCount + '
', className: 'marker-cluster' + c, iconSize: new L.Point(40, 40) }); - }, - - _shownPolygon: null, - - bindEvents: function (map, markerClusterGroup) { - var me = this; - var inZoomAnimation = false; - - map.on('zoomstart', function () { inZoomAnimation = true; }); - map.on('zoomend', function () { inZoomAnimation = false; }); - - - //Zoom on cluster click or spiderfy if we are at the lowest level - markerClusterGroup.on('clusterclick', function (a) { - if (map.getMaxZoom() === map.getZoom()) { - a.layer.spiderfy(); - } else { - a.layer.zoomToBounds(); - } - }); - - //Show convex hull (boundary) polygon on mouse over - markerClusterGroup.on('clustermouseover', function (a) { - if (inZoomAnimation) { - return; - } - if (me._shownPolygon) { - map.removeLayer(me._shownPolygon); - } - if (a.layer.getChildCount() > 2) { - me._shownPolygon = new L.Polygon(a.layer.getConvexHull()); - map.addLayer(me._shownPolygon); - } - }); - markerClusterGroup.on('clustermouseout', function (a) { - if (me._shownPolygon) { - map.removeLayer(me._shownPolygon); - me._shownPolygon = null; - } - }); - map.on('zoomend', function () { - if (me._shownPolygon) { - map.removeLayer(me._shownPolygon); - me._shownPolygon = null; - } - }); - } - }; -}()); \ No newline at end of file diff --git a/src/MarkerClusterGroup.js b/src/MarkerClusterGroup.js index 0577f0955..88ac08d12 100644 --- a/src/MarkerClusterGroup.js +++ b/src/MarkerClusterGroup.js @@ -7,11 +7,18 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({ options: { maxClusterRadius: 60, //A cluster will cover at most this many pixels from its center - iconCreateFunction: L.MarkerClusterDefault ? L.MarkerClusterDefault.iconCreateFunction : null + iconCreateFunction: null, + + spiderfyOnMaxZoom: true, + showCoverageOnHover: true, + zoomToBoundsOnClick: true }, initialize: function (options) { L.Util.setOptions(this, options); + if (!this.options.iconCreateFunction) { + this.options.iconCreateFunction = this._defaultIconCreateFunction; + } L.FeatureGroup.prototype.initialize.call(this, []); @@ -21,6 +28,42 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({ this._currentShownBounds = null; }, + addLayer: function (layer) { + if (!this._map) { + this._needsClustering.push(layer); + return this; + } + + //If we have already clustered we'll need to add this one to a cluster + + var newCluster = this._topClusterLevel._recursivelyAddLayer(layer, this._topClusterLevel._zoom - 1); + + this._animationAddLayer(layer, newCluster); + + return this; + }, + + removeLayer: function (layer) { + this._topClusterLevel._recursivelyRemoveLayer(layer); + + return this; + }, + + //Overrides FeatureGroup.onAdd + onAdd: function (map) { + L.FeatureGroup.prototype.onAdd.call(this, map); + + this._generateInitialClusters(); + this._map.on('zoomend', this._zoomEnd, this); + this._map.on('moveend', this._moveEnd, this); + + if (this._spiderfierOnAdd) { //TODO FIXME: Not sure how to have spiderfier add something on here nicely + this._spiderfierOnAdd(); + } + + this._bindEvents(); + }, + //Overrides FeatureGroup._propagateEvent _propagateEvent: function (e) { if (e.target instanceof L.MarkerCluster) { @@ -29,6 +72,70 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({ L.FeatureGroup.prototype._propagateEvent.call(this, e); }, + //Default functionality + _defaultIconCreateFunction: function (childCount) { + var c = ' marker-cluster-'; + if (childCount < 10) { + c += 'small'; + } else if (childCount < 100) { + c += 'medium'; + } else { + c += 'large'; + } + + return new L.DivIcon({ html: '
' + childCount + '
', className: 'marker-cluster' + c, iconSize: new L.Point(40, 40) }); + }, + + _bindEvents: function () { + var shownPolygon = null, + map = this._map, + + spiderfyOnMaxZoom = this.options.spiderfyOnMaxZoom, + showCoverageOnHover = this.options.showCoverageOnHover, + zoomToBoundsOnClick = this.options.zoomToBoundsOnClick; + + //Zoom on cluster click or spiderfy if we are at the lowest level + if (spiderfyOnMaxZoom || zoomToBoundsOnClick) { + this.on('clusterclick', function (a) { + if (map.getMaxZoom() === map.getZoom()) { + if (spiderfyOnMaxZoom) { + a.layer.spiderfy(); + } + } else if (zoomToBoundsOnClick) { + a.layer.zoomToBounds(); + } + }, this); + } + + //Show convex hull (boundary) polygon on mouse over + if (showCoverageOnHover) { + this.on('clustermouseover', function (a) { + if (this._inZoomAnimation) { + return; + } + if (shownPolygon) { + map.removeLayer(shownPolygon); + } + if (a.layer.getChildCount() > 2) { + shownPolygon = new L.Polygon(a.layer.getConvexHull()); + map.addLayer(shownPolygon); + } + }, this); + this.on('clustermouseout', function () { + if (shownPolygon) { + map.removeLayer(shownPolygon); + shownPolygon = null; + } + }, this); + map.on('zoomend', function () { + if (shownPolygon) { + map.removeLayer(shownPolygon); + shownPolygon = null; + } + }, this); + } + }, + _sqDist: function (p1, p2) { var dx = p2.x - p1.x, dy = p2.y - p1.y; @@ -94,39 +201,6 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({ } }, - addLayer: function (layer) { - if (!this._map) { - this._needsClustering.push(layer); - return this; - } - - //If we have already clustered we'll need to add this one to a cluster - - var newCluster = this._topClusterLevel._recursivelyAddLayer(layer, this._topClusterLevel._zoom - 1); - - this._animationAddLayer(layer, newCluster); - - return this; - }, - - removeLayer: function (layer) { - this._topClusterLevel._recursivelyRemoveLayer(layer); - - return this; - }, - - onAdd: function (map) { - L.FeatureGroup.prototype.onAdd.call(this, map); // LayerGroup - - this._generateInitialClusters(); - this._map.on('zoomend', this._zoomEnd, this); - this._map.on('moveend', this._moveEnd, this); - - if (this._spiderfierOnAdd) { //TODO FIXME: Not sure how to have spiderfier add something on here nicely - this._spiderfierOnAdd(); - } - }, - //Takes a list of markers and clusters the new marker in to them //Will return null or the new MarkerCluster. The clustered in marker is removed from the given array _clusterOne: function (unclusteredMarkers, newMarker, zoom) {