You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
//TODO: Do we actually need to do this on the higher levels too?
/* * L.MarkerClusterGroup extends L.FeatureGroup by clustering the markers contained within */exportvarMarkerClusterGroup=L.MarkerClusterGroup=L.FeatureGroup.extend({options: {maxClusterRadius: 80,//A cluster will cover at most this many pixels from its centericonCreateFunction: null,clusterPane: L.Marker.prototype.options.pane,spiderfyOnMaxZoom: true,showCoverageOnHover: true,zoomToBoundsOnClick: true,singleMarkerMode: false,disableClusteringAtZoom: null,// Setting this to false prevents the removal of any clusters outside of the viewpoint, which// is the default behaviour for performance reasons.removeOutsideVisibleBounds: true,// Set to false to disable all animations (zoom and spiderfy).// If false, option animateAddingMarkers below has no effect.// If L.DomUtil.TRANSITION is falsy, this option has no effect.animate: true,//Whether to animate adding markers after adding the MarkerClusterGroup to the map// If you are adding individual markers set to true, if adding bulk markers leave false for massive performance gains.animateAddingMarkers: false,//Increase to increase the distance away that spiderfied markers appear from the centerspiderfyDistanceMultiplier: 1,// Make it possible to specify a polyline options on a spider legspiderLegPolylineOptions: {weight: 1.5,color: '#222',opacity: 0.5},// When bulk adding layers, adds markers in chunks. Means addLayers may not add all the layers in the call, others will be loaded during setTimeoutschunkedLoading: false,chunkInterval: 200,// process markers for a maximum of ~ n milliseconds (then trigger the chunkProgress callback)chunkDelay: 50,// at the end of each interval, give n milliseconds back to system/browserchunkProgress: null,// progress callback: function(processed, total, elapsed) (e.g. for a progress indicator)//Options to pass to the L.Polygon constructorpolygonOptions: {}},initialize: function(options){L.Util.setOptions(this,options);if(!this.options.iconCreateFunction){this.options.iconCreateFunction=this._defaultIconCreateFunction;}this._featureGroup=L.featureGroup();this._featureGroup.addEventParent(this);this._nonPointGroup=L.featureGroup();this._nonPointGroup.addEventParent(this);this._inZoomAnimation=0;this._needsClustering=[];this._needsRemoving=[];//Markers removed while we aren't on the map need to be kept track of//The bounds of the currently shown area (from _getExpandedVisibleBounds) Updated on zoom/movethis._currentShownBounds=null;this._queue=[];this._childMarkerEventHandlers={'dragstart': this._childMarkerDragStart,'move': this._childMarkerMoved,'dragend': this._childMarkerDragEnd,};// Hook the appropriate animation methods.varanimate=L.DomUtil.TRANSITION&&this.options.animate;L.extend(this,animate ? this._withAnimation : this._noAnimation);// Remember which MarkerCluster class to instantiate (animated or not).this._markerCluster=animate ? L.MarkerCluster : L.MarkerClusterNonAnimated;},addLayer: function(layer){if(layerinstanceofL.LayerGroup){returnthis.addLayers([layer]);}//Don't cluster non point dataif(!layer.getLatLng){this._nonPointGroup.addLayer(layer);this.fire('layeradd',{layer: layer});returnthis;}if(!this._map){this._needsClustering.push(layer);this.fire('layeradd',{layer: layer});returnthis;}if(this.hasLayer(layer)){returnthis;}//If we have already clustered we'll need to add this one to a clusterif(this._unspiderfy){this._unspiderfy();}this._addLayer(layer,this._maxZoom);this.fire('layeradd',{layer: layer});// Refresh bounds and weighted positions.this._topClusterLevel._recalculateBounds();this._refreshClustersIcons();//Work out what is visiblevarvisibleLayer=layer,currentZoom=this._zoom;if(layer.__parent){while(visibleLayer.__parent._zoom>=currentZoom){visibleLayer=visibleLayer.__parent;}}if(this._currentShownBounds.contains(visibleLayer.getLatLng())){if(this.options.animateAddingMarkers){this._animationAddLayer(layer,visibleLayer);}else{this._animationAddLayerNonAnimated(layer,visibleLayer);}}returnthis;},removeLayer: function(layer){if(layerinstanceofL.LayerGroup){returnthis.removeLayers([layer]);}//Non point layersif(!layer.getLatLng){this._nonPointGroup.removeLayer(layer);this.fire('layerremove',{layer: layer});returnthis;}if(!this._map){if(!this._arraySplice(this._needsClustering,layer)&&this.hasLayer(layer)){this._needsRemoving.push({layer: layer,latlng: layer._latlng});}this.fire('layerremove',{layer: layer});returnthis;}if(!layer.__parent){returnthis;}if(this._unspiderfy){this._unspiderfy();this._unspiderfyLayer(layer);}//Remove the marker from clustersthis._removeLayer(layer,true);this.fire('layerremove',{layer: layer});// Refresh bounds and weighted positions.this._topClusterLevel._recalculateBounds();this._refreshClustersIcons();layer.off(this._childMarkerEventHandlers,this);if(this._featureGroup.hasLayer(layer)){this._featureGroup.removeLayer(layer);if(layer.clusterShow){layer.clusterShow();}}returnthis;},//Takes an array of markers and adds them in bulkaddLayers: function(layersArray,skipLayerAddEvent){if(!L.Util.isArray(layersArray)){returnthis.addLayer(layersArray);}varfg=this._featureGroup,npg=this._nonPointGroup,chunked=this.options.chunkedLoading,chunkInterval=this.options.chunkInterval,chunkProgress=this.options.chunkProgress,l=layersArray.length,offset=0,originalArray=true,m;if(this._map){varstarted=(newDate()).getTime();varprocess=L.bind(function(){varstart=(newDate()).getTime();for(;offset<l;offset++){if(chunked&&offset%200===0){// every couple hundred markers, instrument the time elapsed since processing started:varelapsed=(newDate()).getTime()-start;if(elapsed>chunkInterval){break;// been working too hard, time to take a break :-)}}m=layersArray[offset];// Group of layers, append children to layersArray and skip.// Side effects:// - Total increases, so chunkProgress ratio jumps backward.// - Groups are not included in this group, only their non-group child layers (hasLayer).// Changing array length while looping does not affect performance in current browsers:// http://jsperf.com/for-loop-changing-length/6if(minstanceofL.LayerGroup){if(originalArray){layersArray=layersArray.slice();originalArray=false;}this._extractNonGroupLayers(m,layersArray);l=layersArray.length;continue;}//Not point data, can't be clusteredif(!m.getLatLng){npg.addLayer(m);if(!skipLayerAddEvent){this.fire('layeradd',{layer: m});}continue;}if(this.hasLayer(m)){continue;}this._addLayer(m,this._maxZoom);if(!skipLayerAddEvent){this.fire('layeradd',{layer: m});}//If we just made a cluster of size 2 then we need to remove the other marker from the map (if it is) or we never willif(m.__parent){if(m.__parent.getChildCount()===2){varmarkers=m.__parent.getAllChildMarkers(),otherMarker=markers[0]===m ? markers[1] : markers[0];fg.removeLayer(otherMarker);}}}if(chunkProgress){// report progress and time elapsed:chunkProgress(offset,l,(newDate()).getTime()-started);}// Completed processing all markers.if(offset===l){// Refresh bounds and weighted positions.this._topClusterLevel._recalculateBounds();this._refreshClustersIcons();this._topClusterLevel._recursivelyAddChildrenToMap(null,this._zoom,this._currentShownBounds);}else{setTimeout(process,this.options.chunkDelay);}},this);process();}else{varneedsClustering=this._needsClustering;for(;offset<l;offset++){m=layersArray[offset];// Group of layers, append children to layersArray and skip.if(minstanceofL.LayerGroup){if(originalArray){layersArray=layersArray.slice();originalArray=false;}this._extractNonGroupLayers(m,layersArray);l=layersArray.length;continue;}//Not point data, can't be clusteredif(!m.getLatLng){npg.addLayer(m);continue;}if(this.hasLayer(m)){continue;}needsClustering.push(m);}}returnthis;},//Takes an array of markers and removes them in bulkremoveLayers: function(layersArray){vari,m,l=layersArray.length,fg=this._featureGroup,npg=this._nonPointGroup,originalArray=true;if(!this._map){for(i=0;i<l;i++){m=layersArray[i];// Group of layers, append children to layersArray and skip.if(minstanceofL.LayerGroup){if(originalArray){layersArray=layersArray.slice();originalArray=false;}this._extractNonGroupLayers(m,layersArray);l=layersArray.length;continue;}this._arraySplice(this._needsClustering,m);npg.removeLayer(m);if(this.hasLayer(m)){this._needsRemoving.push({layer: m,latlng: m._latlng});}this.fire('layerremove',{layer: m});}returnthis;}if(this._unspiderfy){this._unspiderfy();// Work on a copy of the array, so that next loop is not affected.varlayersArray2=layersArray.slice(),l2=l;for(i=0;i<l2;i++){m=layersArray2[i];// Group of layers, append children to layersArray and skip.if(minstanceofL.LayerGroup){this._extractNonGroupLayers(m,layersArray2);l2=layersArray2.length;continue;}this._unspiderfyLayer(m);}}for(i=0;i<l;i++){m=layersArray[i];// Group of layers, append children to layersArray and skip.if(minstanceofL.LayerGroup){if(originalArray){layersArray=layersArray.slice();originalArray=false;}this._extractNonGroupLayers(m,layersArray);l=layersArray.length;continue;}if(!m.__parent){npg.removeLayer(m);this.fire('layerremove',{layer: m});continue;}this._removeLayer(m,true,true);this.fire('layerremove',{layer: m});if(fg.hasLayer(m)){fg.removeLayer(m);if(m.clusterShow){m.clusterShow();}}}// Refresh bounds and weighted positions.this._topClusterLevel._recalculateBounds();this._refreshClustersIcons();//Fix up the clusters and markers on the mapthis._topClusterLevel._recursivelyAddChildrenToMap(null,this._zoom,this._currentShownBounds);returnthis;},//Removes all layers from the MarkerClusterGroupclearLayers: function(){//Need our own special implementation as the LayerGroup one doesn't work for us//If we aren't on the map (yet), blow away the markers we know ofif(!this._map){this._needsClustering=[];this._needsRemoving=[];deletethis._gridClusters;deletethis._gridUnclustered;}if(this._noanimationUnspiderfy){this._noanimationUnspiderfy();}//Remove all the visible layersthis._featureGroup.clearLayers();this._nonPointGroup.clearLayers();this.eachLayer(function(marker){marker.off(this._childMarkerEventHandlers,this);deletemarker.__parent;},this);if(this._map){//Reset _topClusterLevel and the DistanceGridsthis._generateInitialClusters();}returnthis;},//Override FeatureGroup.getBounds as it doesn't workgetBounds: function(){varbounds=newL.LatLngBounds();if(this._topClusterLevel){bounds.extend(this._topClusterLevel._bounds);}for(vari=this._needsClustering.length-1;i>=0;i--){bounds.extend(this._needsClustering[i].getLatLng());}bounds.extend(this._nonPointGroup.getBounds());returnbounds;},//Overrides LayerGroup.eachLayereachLayer: function(method,context){varmarkers=this._needsClustering.slice(),needsRemoving=this._needsRemoving,thisNeedsRemoving,i,j;if(this._topClusterLevel){this._topClusterLevel.getAllChildMarkers(markers);}for(i=markers.length-1;i>=0;i--){thisNeedsRemoving=true;for(j=needsRemoving.length-1;j>=0;j--){if(needsRemoving[j].layer===markers[i]){thisNeedsRemoving=false;break;}}if(thisNeedsRemoving){method.call(context,markers[i]);}}this._nonPointGroup.eachLayer(method,context);},//Overrides LayerGroup.getLayersgetLayers: function(){varlayers=[];this.eachLayer(function(l){layers.push(l);});returnlayers;},//Overrides LayerGroup.getLayer, WARNING: Really bad performancegetLayer: function(id){varresult=null;id=parseInt(id,10);this.eachLayer(function(l){if(L.stamp(l)===id){result=l;}});returnresult;},//Returns true if the given layer is in this MarkerClusterGrouphasLayer: function(layer){if(!layer){returnfalse;}vari,anArray=this._needsClustering;for(i=anArray.length-1;i>=0;i--){if(anArray[i]===layer){returntrue;}}anArray=this._needsRemoving;for(i=anArray.length-1;i>=0;i--){if(anArray[i].layer===layer){returnfalse;}}return!!(layer.__parent&&layer.__parent._group===this)||this._nonPointGroup.hasLayer(layer);},//Zoom down to show the given layer (spiderfying if necessary) then calls the callbackzoomToShowLayer: function(layer,callback){if(typeofcallback!=='function'){callback=function(){};}varshowMarker=function(){if((layer._icon||layer.__parent._icon)&&!this._inZoomAnimation){this._map.off('moveend',showMarker,this);this.off('animationend',showMarker,this);if(layer._icon){callback();}elseif(layer.__parent._icon){this.once('spiderfied',callback,this);layer.__parent.spiderfy();}}};if(layer._icon&&this._map.getBounds().contains(layer.getLatLng())){//Layer is visible ond on screen, immediate returncallback();}elseif(layer.__parent._zoom<Math.round(this._map._zoom)){//Layer should be visible at this zoom level. It must not be on screen so just pan over to itthis._map.on('moveend',showMarker,this);this._map.panTo(layer.getLatLng());}else{this._map.on('moveend',showMarker,this);this.on('animationend',showMarker,this);layer.__parent.zoomToBounds();}},//Overrides FeatureGroup.onAddonAdd: function(map){this._map=map;vari,l,layer;if(!isFinite(this._map.getMaxZoom())){throw"Map has no maxZoom specified";}this._featureGroup.addTo(map);this._nonPointGroup.addTo(map);if(!this._gridClusters){this._generateInitialClusters();}this._maxLat=map.options.crs.projection.MAX_LATITUDE;//Restore all the positions as they are in the MCG before removing themfor(i=0,l=this._needsRemoving.length;i<l;i++){layer=this._needsRemoving[i];layer.newlatlng=layer.layer._latlng;layer.layer._latlng=layer.latlng;}//Remove them, then restore their new positionsfor(i=0,l=this._needsRemoving.length;i<l;i++){layer=this._needsRemoving[i];this._removeLayer(layer.layer,true);layer.layer._latlng=layer.newlatlng;}this._needsRemoving=[];//Remember the current zoom level and boundsthis._zoom=Math.round(this._map._zoom);this._currentShownBounds=this._getExpandedVisibleBounds();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 nicelythis._spiderfierOnAdd();}this._bindEvents();//Actually add our markers to the map:l=this._needsClustering;this._needsClustering=[];this.addLayers(l,true);},//Overrides FeatureGroup.onRemoveonRemove: function(map){map.off('zoomend',this._zoomEnd,this);map.off('moveend',this._moveEnd,this);this._unbindEvents();//In case we are in a cluster animationthis._map._mapPane.className=this._map._mapPane.className.replace(' leaflet-cluster-anim','');if(this._spiderfierOnRemove){//TODO FIXME: Not sure how to have spiderfier add something on here nicelythis._spiderfierOnRemove();}deletethis._maxLat;//Clean up all the layers we added to the mapthis._hideCoverage();this._featureGroup.remove();this._nonPointGroup.remove();this._featureGroup.clearLayers();this._map=null;},getVisibleParent: function(marker){varvMarker=marker;while(vMarker&&!vMarker._icon){vMarker=vMarker.__parent;}returnvMarker||null;},//Remove the given object from the given array_arraySplice: function(anArray,obj){for(vari=anArray.length-1;i>=0;i--){if(anArray[i]===obj){anArray.splice(i,1);returntrue;}}},/** * Removes a marker from all _gridUnclustered zoom levels, starting at the supplied zoom. * @param marker to be removed from _gridUnclustered. * @param z integer bottom start zoom level (included) * @private */_removeFromGridUnclustered: function(marker,z){varmap=this._map,gridUnclustered=this._gridUnclustered,minZoom=Math.floor(this._map.getMinZoom());for(;z>=minZoom;z--){if(!gridUnclustered[z].removeObject(marker,map.project(marker.getLatLng(),z))){break;}}},_childMarkerDragStart: function(e){e.target.__dragStart=e.target._latlng;},_childMarkerMoved: function(e){if(!this._ignoreMove&&!e.target.__dragStart){varisPopupOpen=e.target._popup&&e.target._popup.isOpen();this._moveChild(e.target,e.oldLatLng,e.latlng);if(isPopupOpen){e.target.openPopup();}}},_moveChild: function(layer,from,to){layer._latlng=from;this.removeLayer(layer);layer._latlng=to;this.addLayer(layer);},_childMarkerDragEnd: function(e){vardragStart=e.target.__dragStart;deletee.target.__dragStart;if(dragStart){this._moveChild(e.target,dragStart,e.target._latlng);}},//Internal function for removing a marker from everything.//dontUpdateMap: set to true if you will handle updating the map manually (for bulk functions)_removeLayer: function(marker,removeFromDistanceGrid,dontUpdateMap){vargridClusters=this._gridClusters,gridUnclustered=this._gridUnclustered,fg=this._featureGroup,map=this._map,minZoom=Math.floor(this._map.getMinZoom());//Remove the marker from distance clusters it might be inif(removeFromDistanceGrid){this._removeFromGridUnclustered(marker,this._maxZoom);}//Work our way up the clusters removing them as we go if requiredvarcluster=marker.__parent,markers=cluster._markers,otherMarker;//Remove the marker from the immediate parents marker listthis._arraySplice(markers,marker);while(cluster){cluster._childCount--;cluster._boundsNeedUpdate=true;if(cluster._zoom<minZoom){//Top level, do nothingbreak;}elseif(removeFromDistanceGrid&&cluster._childCount<=1){//Cluster no longer required//We need to push the other marker up to the parentotherMarker=cluster._markers[0]===marker ? cluster._markers[1] : cluster._markers[0];//Update distance gridgridClusters[cluster._zoom].removeObject(cluster,map.project(cluster._cLatLng,cluster._zoom));gridUnclustered[cluster._zoom].addObject(otherMarker,map.project(otherMarker.getLatLng(),cluster._zoom));//Move otherMarker up to parentthis._arraySplice(cluster.__parent._childClusters,cluster);cluster.__parent._markers.push(otherMarker);otherMarker.__parent=cluster.__parent;if(cluster._icon){//Cluster is currently on the map, need to put the marker on the map insteadfg.removeLayer(cluster);if(!dontUpdateMap){fg.addLayer(otherMarker);}}}else{cluster._iconNeedsUpdate=true;}cluster=cluster.__parent;}deletemarker.__parent;},_isOrIsParent: function(el,oel){while(oel){if(el===oel){returntrue;}oel=oel.parentNode;}returnfalse;},//Override L.Evented.firefire: function(type,data,propagate){if(data&&data.layerinstanceofL.MarkerCluster){//Prevent multiple clustermouseover/off events if the icon is made up of stacked divs (Doesn't work in ie <= 8, no relatedTarget)if(data.originalEvent&&this._isOrIsParent(data.layer._icon,data.originalEvent.relatedTarget)){return;}type='cluster'+type;}L.FeatureGroup.prototype.fire.call(this,type,data,propagate);},//Override L.Evented.listenslistens: function(type,propagate){returnL.FeatureGroup.prototype.listens.call(this,type,propagate)||L.FeatureGroup.prototype.listens.call(this,'cluster'+type,propagate);},//Default functionality_defaultIconCreateFunction: function(cluster){varchildCount=cluster.getChildCount();varc=' marker-cluster-';if(childCount<10){c+='small';}elseif(childCount<100){c+='medium';}else{c+='large';}returnnewL.DivIcon({html: '<div><span>'+childCount+'</span></div>',className: 'marker-cluster'+c,iconSize: newL.Point(40,40)});},_bindEvents: function(){varmap=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 levelif(spiderfyOnMaxZoom||zoomToBoundsOnClick){this.on('clusterclick',this._zoomOrSpiderfy,this);}//Show convex hull (boundary) polygon on mouse overif(showCoverageOnHover){this.on('clustermouseover',this._showCoverage,this);this.on('clustermouseout',this._hideCoverage,this);map.on('zoomend',this._hideCoverage,this);}},_zoomOrSpiderfy: function(e){varcluster=e.layer,bottomCluster=cluster;while(bottomCluster._childClusters.length===1){bottomCluster=bottomCluster._childClusters[0];}if(bottomCluster._zoom===this._maxZoom&&bottomCluster._childCount===cluster._childCount&&this.options.spiderfyOnMaxZoom){// All child markers are contained in a single cluster from this._maxZoom to this cluster.cluster.spiderfy();}elseif(this.options.zoomToBoundsOnClick){cluster.zoomToBounds();}// Focus the map again for keyboard users.if(e.originalEvent&&e.originalEvent.keyCode===13){this._map._container.focus();}},_showCoverage: function(e){varmap=this._map;if(this._inZoomAnimation){return;}if(this._shownPolygon){map.removeLayer(this._shownPolygon);}if(e.layer.getChildCount()>2&&e.layer!==this._spiderfied){this._shownPolygon=newL.Polygon(e.layer.getConvexHull(),this.options.polygonOptions);map.addLayer(this._shownPolygon);}},_hideCoverage: function(){if(this._shownPolygon){this._map.removeLayer(this._shownPolygon);this._shownPolygon=null;}},_unbindEvents: function(){varspiderfyOnMaxZoom=this.options.spiderfyOnMaxZoom,showCoverageOnHover=this.options.showCoverageOnHover,zoomToBoundsOnClick=this.options.zoomToBoundsOnClick,map=this._map;if(spiderfyOnMaxZoom||zoomToBoundsOnClick){this.off('clusterclick',this._zoomOrSpiderfy,this);}if(showCoverageOnHover){this.off('clustermouseover',this._showCoverage,this);this.off('clustermouseout',this._hideCoverage,this);map.off('zoomend',this._hideCoverage,this);}},_zoomEnd: function(){if(!this._map){//May have been removed from the map by a zoomEnd handlerreturn;}this._mergeSplitClusters();this._zoom=Math.round(this._map._zoom);this._currentShownBounds=this._getExpandedVisibleBounds();},_moveEnd: function(){if(this._inZoomAnimation){return;}varnewBounds=this._getExpandedVisibleBounds();this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds,Math.floor(this._map.getMinZoom()),this._zoom,newBounds);this._topClusterLevel._recursivelyAddChildrenToMap(null,Math.round(this._map._zoom),newBounds);this._currentShownBounds=newBounds;return;},_generateInitialClusters: function(){varmaxZoom=Math.ceil(this._map.getMaxZoom()),minZoom=Math.floor(this._map.getMinZoom()),radius=this.options.maxClusterRadius,radiusFn=radius;//If we just set maxClusterRadius to a single number, we need to create//a simple function to return that number. Otherwise, we just have to//use the function we've passed in.if(typeofradius!=="function"){radiusFn=function(){returnradius;};}if(this.options.disableClusteringAtZoom!==null){maxZoom=this.options.disableClusteringAtZoom-1;}this._maxZoom=maxZoom;this._gridClusters={};this._gridUnclustered={};//Set up DistanceGrids for each zoomfor(varzoom=maxZoom;zoom>=minZoom;zoom--){this._gridClusters[zoom]=newL.DistanceGrid(radiusFn(zoom));this._gridUnclustered[zoom]=newL.DistanceGrid(radiusFn(zoom));}// Instantiate the appropriate L.MarkerCluster class (animated or not).this._topClusterLevel=newthis._markerCluster(this,minZoom-1);},//Zoom: Zoom to start adding at (Pass this._maxZoom to start at the bottom)_addLayer: function(layer,zoom){vargridClusters=this._gridClusters,gridUnclustered=this._gridUnclustered,minZoom=Math.floor(this._map.getMinZoom()),markerPoint,z;if(this.options.singleMarkerMode){this._overrideMarkerIcon(layer);}layer.on(this._childMarkerEventHandlers,this);//Find the lowest zoom level to slot this one infor(;zoom>=minZoom;zoom--){markerPoint=this._map.project(layer.getLatLng(),zoom);// calculate pixel position//Try find a cluster close byvarclosest=gridClusters[zoom].getNearObject(markerPoint);if(closest){closest._addChild(layer);layer.__parent=closest;return;}//Try find a marker close by to form a new cluster withclosest=gridUnclustered[zoom].getNearObject(markerPoint);if(closest){varparent=closest.__parent;if(parent){this._removeLayer(closest,false);}//Create new cluster with these 2 in itvarnewCluster=newthis._markerCluster(this,zoom,closest,layer);gridClusters[zoom].addObject(newCluster,this._map.project(newCluster._cLatLng,zoom));closest.__parent=newCluster;layer.__parent=newCluster;//First create any new intermediate parent clusters that don't existvarlastParent=newCluster;for(z=zoom-1;z>parent._zoom;z--){lastParent=newthis._markerCluster(this,z,lastParent);gridClusters[z].addObject(lastParent,this._map.project(closest.getLatLng(),z));}parent._addChild(lastParent);//Remove closest from this zoom level and any above that it is in, replace with newClusterthis._removeFromGridUnclustered(closest,zoom);return;}//Didn't manage to cluster in at this zoom, record us as a marker here and continue upwardsgridUnclustered[zoom].addObject(layer,markerPoint);}//Didn't get in anything, add us to the topthis._topClusterLevel._addChild(layer);layer.__parent=this._topClusterLevel;return;},/** * Refreshes the icon of all "dirty" visible clusters. * Non-visible "dirty" clusters will be updated when they are added to the map. * @private */_refreshClustersIcons: function(){this._featureGroup.eachLayer(function(c){if(cinstanceofL.MarkerCluster&&c._iconNeedsUpdate){c._updateIcon();}});},//Enqueue code to fire after the marker expand/contract has happened_enqueue: function(fn){this._queue.push(fn);if(!this._queueTimeout){this._queueTimeout=setTimeout(L.bind(this._processQueue,this),300);}},_processQueue: function(){for(vari=0;i<this._queue.length;i++){this._queue[i].call(this);}this._queue.length=0;clearTimeout(this._queueTimeout);this._queueTimeout=null;},//Merge and split any existing clusters that are too big or small_mergeSplitClusters: function(){varmapZoom=Math.round(this._map._zoom);//In case we are starting to split before the animation finishedthis._processQueue();if(this._zoom<mapZoom&&this._currentShownBounds.intersects(this._getExpandedVisibleBounds())){//Zoom in, splitthis._animationStart();//Remove clusters now off screenthis._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds,Math.floor(this._map.getMinZoom()),this._zoom,this._getExpandedVisibleBounds());this._animationZoomIn(this._zoom,mapZoom);}elseif(this._zoom>mapZoom){//Zoom out, mergethis._animationStart();this._animationZoomOut(this._zoom,mapZoom);}else{this._moveEnd();}},//Gets the maps visible bounds expanded in each direction by the size of the screen (so the user cannot see an area we do not cover in one pan)_getExpandedVisibleBounds: function(){if(!this.options.removeOutsideVisibleBounds){returnthis._mapBoundsInfinite;}elseif(L.Browser.mobile){returnthis._checkBoundsMaxLat(this._map.getBounds());}returnthis._checkBoundsMaxLat(this._map.getBounds().pad(1));// Padding expands the bounds by its own dimensions but scaled with the given factor.},/** * Expands the latitude to Infinity (or -Infinity) if the input bounds reach the map projection maximum defined latitude * (in the case of Web/Spherical Mercator, it is 85.0511287798 / see https://en.wikipedia.org/wiki/Web_Mercator#Formulas). * Otherwise, the removeOutsideVisibleBounds option will remove markers beyond that limit, whereas the same markers without * this option (or outside MCG) will have their position floored (ceiled) by the projection and rendered at that limit, * making the user think that MCG "eats" them and never displays them again. * @param bounds L.LatLngBounds * @returns {L.LatLngBounds} * @private */_checkBoundsMaxLat: function(bounds){varmaxLat=this._maxLat;if(maxLat!==undefined){if(bounds.getNorth()>=maxLat){bounds._northEast.lat=Infinity;}if(bounds.getSouth()<=-maxLat){bounds._southWest.lat=-Infinity;}}returnbounds;},//Shared animation code_animationAddLayerNonAnimated: function(layer,newCluster){if(newCluster===layer){this._featureGroup.addLayer(layer);}elseif(newCluster._childCount===2){newCluster._addToMap();varmarkers=newCluster.getAllChildMarkers();this._featureGroup.removeLayer(markers[0]);this._featureGroup.removeLayer(markers[1]);}else{newCluster._updateIcon();}},/** * Extracts individual (i.e. non-group) layers from a Layer Group. * @param group to extract layers from. * @param output {Array} in which to store the extracted layers. * @returns {*|Array} * @private */_extractNonGroupLayers: function(group,output){varlayers=group.getLayers(),i=0,layer;output=output||[];for(;i<layers.length;i++){layer=layers[i];if(layerinstanceofL.LayerGroup){this._extractNonGroupLayers(layer,output);continue;}output.push(layer);}returnoutput;},/** * Implements the singleMarkerMode option. * @param layer Marker to re-style using the Clusters iconCreateFunction. * @returns {L.Icon} The newly created icon. * @private */_overrideMarkerIcon: function(layer){varicon=layer.options.icon=this.options.iconCreateFunction({getChildCount: function(){return1;},getAllChildMarkers: function(){return[layer];}});returnicon;}});// Constant bounds used in case option "removeOutsideVisibleBounds" is set to false.L.MarkerClusterGroup.include({_mapBoundsInfinite: newL.LatLngBounds(newL.LatLng(-Infinity,-Infinity),newL.LatLng(Infinity,Infinity))});L.MarkerClusterGroup.include({_noAnimation: {//Non Animated versions of everything_animationStart: function(){//Do nothing...},_animationZoomIn: function(previousZoomLevel,newZoomLevel){this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds,Math.floor(this._map.getMinZoom()),previousZoomLevel);this._topClusterLevel._recursivelyAddChildrenToMap(null,newZoomLevel,this._getExpandedVisibleBounds());//We didn't actually animate, but we use this event to mean "clustering animations have finished"this.fire('animationend');},_animationZoomOut: function(previousZoomLevel,newZoomLevel){this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds,Math.floor(this._map.getMinZoom()),previousZoomLevel);this._topClusterLevel._recursivelyAddChildrenToMap(null,newZoomLevel,this._getExpandedVisibleBounds());//We didn't actually animate, but we use this event to mean "clustering animations have finished"this.fire('animationend');},_animationAddLayer: function(layer,newCluster){this._animationAddLayerNonAnimated(layer,newCluster);}},_withAnimation: {//Animated versions here_animationStart: function(){this._map._mapPane.className+=' leaflet-cluster-anim';this._inZoomAnimation++;},_animationZoomIn: function(previousZoomLevel,newZoomLevel){varbounds=this._getExpandedVisibleBounds(),fg=this._featureGroup,minZoom=Math.floor(this._map.getMinZoom()),i;this._ignoreMove=true;//Add all children of current clusters to map and remove those clusters from mapthis._topClusterLevel._recursively(bounds,previousZoomLevel,minZoom,function(c){varstartPos=c._latlng,markers=c._markers,m;if(!bounds.contains(startPos)){startPos=null;}if(c._isSingleParent()&&previousZoomLevel+1===newZoomLevel){//Immediately add the new child and remove usfg.removeLayer(c);c._recursivelyAddChildrenToMap(null,newZoomLevel,bounds);}else{//Fade out old clusterc.clusterHide();c._recursivelyAddChildrenToMap(startPos,newZoomLevel,bounds);}//Remove all markers that aren't visible any more//TODO: Do we actually need to do this on the higher levels too?for(i=markers.length-1;i>=0;i--){m=markers[i];if(!bounds.contains(m._latlng)){fg.removeLayer(m);}}});this._forceLayout();//Update opacitiesthis._topClusterLevel._recursivelyBecomeVisible(bounds,newZoomLevel);//TODO Maybe? Update markers in _recursivelyBecomeVisiblefg.eachLayer(function(n){if(!(ninstanceofL.MarkerCluster)&&n._icon){n.clusterShow();}});//update the positions of the just added clusters/markersthis._topClusterLevel._recursively(bounds,previousZoomLevel,newZoomLevel,function(c){c._recursivelyRestoreChildPositions(newZoomLevel);});this._ignoreMove=false;//Remove the old clusters and close the zoom animationthis._enqueue(function(){//update the positions of the just added clusters/markersthis._topClusterLevel._recursively(bounds,previousZoomLevel,minZoom,function(c){fg.removeLayer(c);c.clusterShow();});this._animationEnd();});},_animationZoomOut: function(previousZoomLevel,newZoomLevel){this._animationZoomOutSingle(this._topClusterLevel,previousZoomLevel-1,newZoomLevel);//Need to add markers for those that weren't on the map before but are nowthis._topClusterLevel._recursivelyAddChildrenToMap(null,newZoomLevel,this._getExpandedVisibleBounds());//Remove markers that were on the map before but won't be nowthis._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds,Math.floor(this._map.getMinZoom()),previousZoomLevel,this._getExpandedVisibleBounds());},_animationAddLayer: function(layer,newCluster){varme=this,fg=this._featureGroup;fg.addLayer(layer);if(newCluster!==layer){if(newCluster._childCount>2){//Was already a clusternewCluster._updateIcon();this._forceLayout();this._animationStart();layer._setPos(this._map.latLngToLayerPoint(newCluster.getLatLng()));layer.clusterHide();this._enqueue(function(){fg.removeLayer(layer);layer.clusterShow();me._animationEnd();});}else{//Just became a clusterthis._forceLayout();me._animationStart();me._animationZoomOutSingle(newCluster,this._map.getMaxZoom(),this._zoom);}}}},// Private methods for animated versions._animationZoomOutSingle: function(cluster,previousZoomLevel,newZoomLevel){varbounds=this._getExpandedVisibleBounds(),minZoom=Math.floor(this._map.getMinZoom());//Animate all of the markers in the clusters to move to their cluster center pointcluster._recursivelyAnimateChildrenInAndAddSelfToMap(bounds,minZoom,previousZoomLevel+1,newZoomLevel);varme=this;//Update the opacity (If we immediately set it they won't animate)this._forceLayout();cluster._recursivelyBecomeVisible(bounds,newZoomLevel);//TODO: Maybe use the transition timing stuff to make this more reliable//When the animations are done, tidy upthis._enqueue(function(){//This cluster stopped being a cluster before the timeout firedif(cluster._childCount===1){varm=cluster._markers[0];//If we were in a cluster animation at the time then the opacity and position of our child could be wrong now, so fix itthis._ignoreMove=true;m.setLatLng(m.getLatLng());this._ignoreMove=false;if(m.clusterShow){m.clusterShow();}}else{cluster._recursively(bounds,newZoomLevel,minZoom,function(c){c._recursivelyRemoveChildrenFromMap(bounds,minZoom,previousZoomLevel+1);});}me._animationEnd();});},_animationEnd: function(){if(this._map){this._map._mapPane.className=this._map._mapPane.className.replace(' leaflet-cluster-anim','');}this._inZoomAnimation--;this.fire('animationend');},//Force a browser layout of stuff in the map// Should apply the current opacity and location to all elements so we can update them again for an animation_forceLayout: function(){//In my testing this works, infact offsetWidth of any element seems to work.//Could loop all this._layers and do this for each _icon if it stops workingL.Util.falseFn(document.body.offsetWidth);}});L.markerClusterGroup=function(options){returnnewL.MarkerClusterGroup(options);};
The text was updated successfully, but these errors were encountered:
decidim-mel/packages/core/node_modules/leaflet.markercluster/src/MarkerClusterGroup.js
Line 1236 in b1e353e
The text was updated successfully, but these errors were encountered: