[Pkg-javascript-commits] [leaflet-markercluster] 222/479: Update Build

Jonas Smedegaard dr at jones.dk
Thu Oct 16 16:00:33 UTC 2014


This is an automated email from the git hooks/post-receive script.

js pushed a commit to branch master
in repository leaflet-markercluster.

commit 81e5456759b469813b7dcaa3a5fbef38aae2215a
Author: danzel <danzel at localhost.geek.nz>
Date:   Tue Sep 11 15:33:22 2012 +1200

    Update Build
---
 dist/leaflet.markercluster-src.js | 705 ++++++++++++++++----------------------
 dist/leaflet.markercluster.js     |   2 +-
 2 files changed, 299 insertions(+), 408 deletions(-)

diff --git a/dist/leaflet.markercluster-src.js b/dist/leaflet.markercluster-src.js
index edb01e2..f0dacc0 100644
--- a/dist/leaflet.markercluster-src.js
+++ b/dist/leaflet.markercluster-src.js
@@ -81,12 +81,21 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
 			this._unspiderfy();
 		}
 
-		var newCluster = this._topClusterLevel._recursivelyAddLayer(layer, this._topClusterLevel._zoom - 1);
+		this._addLayer(layer, this._maxZoom);
+
+		//Work out what is visible
+		var visibleLayer = layer,
+			currentZoom = this._map.getZoom();
+		if (layer.__parent) {
+			while (visibleLayer.__parent._zoom >= currentZoom) {
+				visibleLayer = visibleLayer.__parent;
+			}
+		}
 
 		if (this.options.animateAddingMarkers) {
-			this._animationAddLayer(layer, newCluster);
+			this._animationAddLayer(layer, visibleLayer);
 		} else {
-			this._animationAddLayerNonAnimated(layer, newCluster);
+			this._animationAddLayerNonAnimated(layer, visibleLayer);
 		}
 		return this;
 	},
@@ -97,29 +106,93 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
 			this._unspiderfyLayer(layer);
 		}
 
-		if (!this._topClusterLevel._recursivelyRemoveLayer(layer)) {
-			//If this happens you are doing something bad
-			//If you've moved a marker that is in the cluster then that would be why
-			//console.log('failed to remove');
-			var a = 0;
-		}
+		//Remove the marker from clusters
+		this._removeLayer(layer, true);
 
+		if (layer._icon) {
+			L.FeatureGroup.prototype.removeLayer.call(this, layer);
+		}
 		return this;
 	},
 
-	clearLayers: function () {
-		//Need our own special implementation as the LayerGroup one doesn't work for us
+	//Remove the given object from the given array
+	_arraySplice: function (anArray, obj) {
+		for (var i = anArray.length - 1; i >= 0; i--) {
+			if (anArray[i] === obj) {
+				anArray.splice(i, 1);
+				return;
+			}
+		}
+	},
 
-		if (this._unspiderfy) {
-			this._unspiderfy();
+	_removeLayer: function (marker, removeFromDistanceGrid) {
+		var gridClusters = this._gridClusters,
+			gridUnclustered = this._gridUnclustered,
+			map = this._map;
+
+		//Remove the marker from distance clusters it might be in
+		if (removeFromDistanceGrid) {
+			for (var z = this._maxZoom; z >= 0; z--) {
+				if (!gridUnclustered[z].removeObject(marker, map.project(marker.getLatLng(), z))) {
+					break;
+				}
+			}
 		}
 
+		//Work our way up the clusters removing them as we go if required
+		var cluster = marker.__parent,
+			markers = cluster._markers,
+			otherMarker;
+
+		//Remove the marker from the immediate parents marker list
+		this._arraySplice(markers, marker);
+
+		while (cluster) {
+			cluster._childCount--;
+
+			if (cluster._zoom < 0) {
+				//Top level, do nothing
+				break;
+			} else if (removeFromDistanceGrid && cluster._childCount <= 1) { //Cluster no longer required
+				//We need to push the other marker up to the parent
+				otherMarker = cluster._markers[0] === marker ? cluster._markers[1] : cluster._markers[0];
+
+				//Update distance grid
+				gridClusters[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 parent
+				this._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 instead
+					L.FeatureGroup.prototype.removeLayer.call(this, cluster);
+					L.FeatureGroup.prototype.addLayer.call(this, otherMarker);
+				}
+			} else {
+				cluster._recalculateBounds();
+				cluster._updateIcon();
+			}
+
+			cluster = cluster.__parent;
+		}
+	},
+
+	clearLayers: function () {
+		//Need our own special implementation as the LayerGroup one doesn't work for us
+
 		//If we aren't on the map yet, just blow away the markers we know of
 		if (!this._map) {
 			this._needsClustering = [];
 			return this;
 		}
 
+		if (this._unspiderfy) {
+			this._unspiderfy();
+		}
+
 		//Remove all the visible layers
 		for (var i in this._layers) {
 			if (this._layers.hasOwnProperty(i)) {
@@ -127,7 +200,7 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
 			}
 		}
 
-		//Reset _topClusterLevel
+		//Reset _topClusterLevel and the DistanceGrids
 		this._generateInitialClusters();
 
 		return this;
@@ -151,15 +224,14 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
 	onAdd: function (map) {
 		L.FeatureGroup.prototype.onAdd.call(this, map);
 
-		if (!this._topClusterLevel) {
+		if (!this._gridClusters) {
 			this._generateInitialClusters();
-		} else if (this._needsClustering.length > 0) {
-			for (var i = this._needsClustering.length - 1; i >= 0; i--) {
-				this.addLayer(this._needsClustering[i]);
-			}
-			this._needsClustering = [];
 		}
 
+		for (var i = 0, l = this._needsClustering.length; i < l; i++) {
+			this._addLayer(this._needsClustering[i], this._maxZoom);
+		}
+		this._needsClustering = [];
 
 		this._map.on('zoomend', this._zoomEnd, this);
 		this._map.on('moveend', this._moveEnd, this);
@@ -169,6 +241,16 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
 		}
 
 		this._bindEvents();
+
+
+		//Actually add our markers to the map:
+
+		//Remember the current zoom level and bounds
+		this._zoom = this._map.getZoom();
+		this._currentShownBounds = this._getExpandedVisibleBounds();
+
+		//Make things appear on the map
+		this._topClusterLevel._recursivelyAddChildrenToMap(null, this._zoom, this._currentShownBounds);
 	},
 
 	//Overrides FeatureGroup.onRemove
@@ -266,12 +348,6 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
 		}
 	},
 
-	_sqDist: function (p1, p2) {
-		var dx = p2.x - p1.x,
-			dy = p2.y - p1.y;
-		return dx * dx + dy * dy;
-	},
-
 	_zoomEnd: function () {
 		if (!this._map) { //May have been removed from the map by a zoomEnd handler
 			return;
@@ -287,152 +363,111 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
 			return;
 		}
 
-		var newBounds = this._getExpandedVisibleBounds(),
-			depth = this._zoom - this._topClusterLevel._zoom;
+		var newBounds = this._getExpandedVisibleBounds();
 
-		this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds, depth, newBounds);
-		this._topClusterLevel._recursivelyAddChildrenToMap(null, depth + 1, newBounds);
+		this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds, this._zoom, newBounds);
+		this._topClusterLevel._recursivelyAddChildrenToMap(null, this._zoom, newBounds);
 
 		this._currentShownBounds = newBounds;
 		return;
 	},
 
 	_generateInitialClusters: function () {
-		var minZoom = this._map.getMinZoom(),
-			maxZoom = this._map.getMaxZoom(),
-			currentZoom = this._map.getZoom();
+		var maxZoom = this._map.getMaxZoom(),
+			radius = this.options.maxClusterRadius;
 
 		if (this.options.disableClusteringAtZoom) {
 			maxZoom = this.options.disableClusteringAtZoom - 1;
 		}
+		this._maxZoom = maxZoom;
+		this._gridClusters = {};
+		this._gridUnclustered = {};
 
-		//console.time('cluster');
-		this._topClusterLevel = this._clusterToMarkerCluster(this._needsClustering, maxZoom);
-		this._needsClustering = [];
-
-		//Generate to the top
-		while (minZoom < this._topClusterLevel._zoom) {
-			this._topClusterLevel = this._clusterToMarkerCluster(this._topClusterLevel._childClusters.concat(this._topClusterLevel._markers), this._topClusterLevel._zoom - 1);
+		//Set up DistanceGrids for each zoom
+		for (var zoom = maxZoom; zoom >= 0; zoom--) {
+			this._gridClusters[zoom] = new L.DistanceGrid(radius);
+			this._gridUnclustered[zoom] = new L.DistanceGrid(radius);
 		}
-		//console.timeEnd('cluster');
-
-		//Remember the current zoom level and bounds
-		this._zoom = currentZoom;
-		this._currentShownBounds = this._getExpandedVisibleBounds();
-
-		//Make things appear on the map
-		this._topClusterLevel._recursivelyAddChildrenToMap(null, currentZoom - minZoom + 1, this._currentShownBounds);
-	},
-
-	//Merge and split any existing clusters that are too big or small
-	_mergeSplitClusters: function () {
-
-		if (this._zoom < this._map._zoom) { //Zoom in, split
-			this._animationStart();
-			//Remove clusters now off screen
-			this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds, this._zoom - this._topClusterLevel._zoom, this._getExpandedVisibleBounds());
-
-			this._animationZoomIn(this._zoom, this._map._zoom);
-
-		} else if (this._zoom > this._map._zoom) { //Zoom out, merge
-			this._animationStart();
 
-			this._animationZoomOut(this._zoom, this._map._zoom);
-		} else {
-			this._moveEnd();
-		}
+		this._topClusterLevel = new L.MarkerCluster(this, -1);
 	},
 
-	//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 (unclustered, newMarker, markerPoint) {
-		var marker = unclustered.getNearObject(markerPoint);
+	//Zoom: Zoom to start adding at (Pass this._maxZoom to start at the bottom)
+	_addLayer: function (layer, zoom) {
+		var gridClusters = this._gridClusters,
+		    gridUnclustered = this._gridUnclustered,
+		    markerPoint, z;
 
-		if (marker) {
-			// create a new cluster with these 2
-			unclustered.removeObject(marker);
-			return new L.MarkerCluster(this, marker, newMarker);
-		}
+		//Find the lowest zoom level to slot this one in
+		for (; zoom >= 0; zoom--) {
+			markerPoint = this._map.project(layer.getLatLng(), zoom); // calculate pixel position
 
-		return null;
-	},
+			//Try find a cluster close by
+			var closest = gridClusters[zoom].getNearObject(markerPoint);
+			if (closest) {
+				closest._addChild(layer);
+				layer.__parent = closest;
+				return;
+			}
 
-	//Takes a list of objects that have a 'getLatLng()' function (Marker / MarkerCluster)
-	//Performs clustering on them (using a greedy algorithm) and returns those clusters.
-	//markers: List of Markers/MarkerClusters to cluster
-	//Returns { 'clusters': [new clusters], 'unclustered': [unclustered markers] }
-	_cluster: function (markers, zoom) {
-		var radius = this.options.maxClusterRadius,
-		    clusters = new L.DistanceGrid(radius),
-		    unclustered = new L.DistanceGrid(radius),
-		    i, j, marker, markerPoint, cluster, newCluster;
+			//Try find a marker close by to form a new cluster with
+			closest = gridUnclustered[zoom].getNearObject(markerPoint);
+			if (closest) {
+				if (closest.__parent) {
+					this._removeLayer(closest, false);
+				}
+				var parent = closest.__parent || this._topClusterLevel;
 
-		// go through each point
-		for (i = markers.length - 1; i >= 0; i--) {
-			marker = markers[i];
-			markerPoint = this._map.project(marker.getLatLng(), zoom); // calculate pixel position
+				//Create new cluster with these 2 in it
 
-			// try add it to an existing cluster
-			cluster = clusters.getNearObject(markerPoint);
+				var newCluster = new L.MarkerCluster(this, zoom, closest, layer);
+				gridClusters[zoom].addObject(newCluster, this._map.project(newCluster._cLatLng, zoom));
+				closest.__parent = newCluster;
+				layer.__parent = newCluster;
 
-			if (cluster) {
-				cluster._addChild(marker);
-			} else {
-				// otherwise, look through all of the markers we haven't managed to cluster and see if we should form a cluster with them
-				newCluster = this._clusterOne(unclustered, marker, markerPoint);
-				if (newCluster) {
-					clusters.addObject(newCluster, this._map.project(newCluster.getLatLng(), zoom));
-				} else {
-					// didn't manage to use it
-					unclustered.addObject(marker, markerPoint);
+				//First create any new intermediate parent clusters that don't exist
+				var lastParent = newCluster;
+				for (z = zoom - 1; z > parent._zoom; z--) {
+					lastParent = new L.MarkerCluster(this, z, lastParent);
+					gridClusters[z].addObject(lastParent, this._map.project(closest.getLatLng(), z));
 				}
-			}
-		}
-
-		var result = [],
-			group = this;
+				parent._addChild(lastParent);
 
-		// any clusters that did not end up being a child of a new cluster, make them a child of a new cluster
-		unclustered.eachObject(function (cluster) {
-			if (cluster instanceof L.MarkerCluster) {
-				newCluster = new L.MarkerCluster(group, cluster);
-				newCluster._haveGeneratedChildClusters = true;
-
-				clusters.addObject(newCluster, cluster._dGridPoint);
-				unclustered.removeObject(cluster);
+				//Remove closest from this zoom level and any above that it is in, replace with newCluster
+				for (z = zoom; z >= 0; z--) {
+					if (!gridUnclustered[z].removeObject(closest, this._map.project(closest.getLatLng(), z))) {
+						break;
+					}
+				}
 
-				return true;
+				return;
 			}
-			return false;
-		});
+			
+			//Didn't manage to cluster in at this zoom, record us as a marker here and continue upwards
+			gridUnclustered[zoom].addObject(layer, markerPoint);
+		}
 
-		unclustered.eachObject(function (marker) {
-			result.push(marker);
-		});
+		return;
+	},
 
-		// initialize created clusters
-		clusters.eachObject(function (cluster) {
-			cluster._baseInit();
-			result.push(cluster);
-		});
+	//Merge and split any existing clusters that are too big or small
+	_mergeSplitClusters: function () {
+		if (this._zoom < this._map._zoom) { //Zoom in, split
+			this._animationStart();
+			//Remove clusters now off screen
+			this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds, this._zoom, this._getExpandedVisibleBounds());
 
-		return result;
-	},
+			this._animationZoomIn(this._zoom, this._map._zoom);
 
-	//Clusters the given markers (with _cluster) and returns the result as a MarkerCluster
-	_clusterToMarkerCluster: function (markers, zoom) {
-		var toAdd = this._cluster(markers, zoom),
-			result = new L.MarkerCluster(this),
-			i;
+		} else if (this._zoom > this._map._zoom) { //Zoom out, merge
+			this._animationStart();
 
-		for (i = toAdd.length - 1; i >= 0; i--) {
-			result._addChild(toAdd[i]);
+			this._animationZoomOut(this._zoom, this._map._zoom);
+		} else {
+			this._moveEnd();
 		}
-		result._zoom = zoom;
-		result._haveGeneratedChildClusters = true;
-		return result;
 	},
-
+	
 	//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 () {
 		var map = this._map,
@@ -447,11 +482,16 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
 
 	//Shared animation code
 	_animationAddLayerNonAnimated: function (layer, newCluster) {
-		if (newCluster === true) {
+		if (newCluster === layer) {
 			L.FeatureGroup.prototype.addLayer.call(this, layer);
 		} else if (newCluster._childCount === 2) {
 			newCluster._addToMap();
-			newCluster._recursivelyRemoveChildrenFromMap(newCluster._bounds, this._map.getMaxZoom()); //getMaxZoom will always get all children
+
+			var markers = newCluster.getAllChildMarkers();
+			L.FeatureGroup.prototype.removeLayer.call(this, markers[0]);
+			L.FeatureGroup.prototype.removeLayer.call(this, markers[1]);
+		} else {
+			newCluster._updateIcon();
 		}
 	}
 });
@@ -463,12 +503,12 @@ L.MarkerClusterGroup.include(!L.DomUtil.TRANSITION ? {
 		//Do nothing...
 	},
 	_animationZoomIn: function (previousZoomLevel, newZoomLevel) {
-		this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds, previousZoomLevel - this._topClusterLevel._zoom);
-		this._topClusterLevel._recursivelyAddChildrenToMap(null, newZoomLevel - this._topClusterLevel._zoom + 1, this._getExpandedVisibleBounds());
+		this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds, previousZoomLevel);
+		this._topClusterLevel._recursivelyAddChildrenToMap(null, newZoomLevel, this._getExpandedVisibleBounds());
 	},
 	_animationZoomOut: function (previousZoomLevel, newZoomLevel) {
-		this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds, previousZoomLevel - this._topClusterLevel._zoom);
-		this._topClusterLevel._recursivelyAddChildrenToMap(null, newZoomLevel - this._topClusterLevel._zoom + 1, this._getExpandedVisibleBounds());
+		this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds, previousZoomLevel);
+		this._topClusterLevel._recursivelyAddChildrenToMap(null, newZoomLevel, this._getExpandedVisibleBounds());
 	},
 	_animationAddLayer: function (layer, newCluster) {
 		this._animationAddLayerNonAnimated(layer, newCluster);
@@ -489,23 +529,21 @@ L.MarkerClusterGroup.include(!L.DomUtil.TRANSITION ? {
 	_animationZoomIn: function (previousZoomLevel, newZoomLevel) {
 		var me = this,
 		    bounds = this._getExpandedVisibleBounds(),
-		    i,
-		    depthToStartAt = 1 + previousZoomLevel - this._topClusterLevel._zoom,
-		    depthToDescend = newZoomLevel - previousZoomLevel;
+		    i;
 
 		//Add all children of current clusters to map and remove those clusters from map
-		this._topClusterLevel._recursively(bounds, depthToStartAt, 0, function (c) {
+		this._topClusterLevel._recursively(bounds, previousZoomLevel, 0, function (c) {
 			var startPos = c._latlng,
 				markers = c._markers,
 				m;
 
-			if (c._isSingleParent() && depthToDescend === 1) { //Immediately add the new child and remove us
+			if (c._isSingleParent() && previousZoomLevel + 1 === newZoomLevel) { //Immediately add the new child and remove us
 				L.FeatureGroup.prototype.removeLayer.call(me, c);
-				c._recursivelyAddChildrenToMap(null, depthToDescend, bounds);
+				c._recursivelyAddChildrenToMap(null, newZoomLevel, bounds);
 			} else {
 				//Fade out old cluster
 				c.setOpacity(0);
-				c._recursivelyAddChildrenToMap(startPos, depthToDescend, bounds);
+				c._recursivelyAddChildrenToMap(startPos, newZoomLevel, bounds);
 			}
 
 			//Remove all markers that aren't visible any more
@@ -523,7 +561,7 @@ L.MarkerClusterGroup.include(!L.DomUtil.TRANSITION ? {
 		var j, n;
 
 		//Update opacities
-		me._topClusterLevel._recursivelyBecomeVisible(bounds, depthToStartAt + depthToDescend);
+		me._topClusterLevel._recursivelyBecomeVisible(bounds, newZoomLevel);
 		//TODO Maybe? Update markers in _recursivelyBecomeVisible
 		for (j in me._layers) {
 			if (me._layers.hasOwnProperty(j)) {
@@ -536,15 +574,15 @@ L.MarkerClusterGroup.include(!L.DomUtil.TRANSITION ? {
 		}
 
 		//update the positions of the just added clusters/markers
-		me._topClusterLevel._recursively(bounds, depthToStartAt, 0, function (c) {
-			c._recursivelyRestoreChildPositions(depthToDescend);
+		me._topClusterLevel._recursively(bounds, previousZoomLevel, newZoomLevel, function (c) {
+			c._recursivelyRestoreChildPositions(newZoomLevel);
 		});
 
 		//Remove the old clusters and close the zoom animation
 
 		setTimeout(function () {
 			//update the positions of the just added clusters/markers
-			me._topClusterLevel._recursively(bounds, depthToStartAt, 0, function (c) {
+			me._topClusterLevel._recursively(bounds, previousZoomLevel, 0, function (c) {
 				L.FeatureGroup.prototype.removeLayer.call(me, c);
 			});
 
@@ -553,32 +591,29 @@ L.MarkerClusterGroup.include(!L.DomUtil.TRANSITION ? {
 	},
 
 	_animationZoomOut: function (previousZoomLevel, newZoomLevel) {
-		var depthToStartAt = 1 + newZoomLevel - this._topClusterLevel._zoom,
-		    depthToAnimateIn = previousZoomLevel - newZoomLevel;
-
-		this._animationZoomOutSingle(this._topClusterLevel, depthToStartAt, depthToAnimateIn);
+		this._animationZoomOutSingle(this._topClusterLevel, previousZoomLevel, newZoomLevel);
 
 		//Need to add markers for those that weren't on the map before but are now
-		this._topClusterLevel._recursivelyAddChildrenToMap(null, depthToStartAt, this._getExpandedVisibleBounds());
+		this._topClusterLevel._recursivelyAddChildrenToMap(null, newZoomLevel, this._getExpandedVisibleBounds());
 	},
-	_animationZoomOutSingle: function (marker, depthToStartAt, depthToAnimateIn) {
+	_animationZoomOutSingle: function (marker, previousZoomLevel, newZoomLevel) {
 		var bounds = this._getExpandedVisibleBounds();
 
 		//Animate all of the markers in the clusters to move to their cluster center point
-		marker._recursivelyAnimateChildrenInAndAddSelfToMap(bounds, depthToStartAt, depthToAnimateIn);
+		marker._recursivelyAnimateChildrenInAndAddSelfToMap(bounds, previousZoomLevel, newZoomLevel);
 
 		var me = this;
 
 		//Update the opacity (If we immediately set it they won't animate)
 		this._forceLayout();
-		marker._recursivelyBecomeVisible(bounds, depthToStartAt);
+		marker._recursivelyBecomeVisible(bounds, newZoomLevel);
 
 		//TODO: Maybe use the transition timing stuff to make this more reliable
 		//When the animations are done, tidy up
 		setTimeout(function () {
 
-			marker._recursively(bounds, depthToStartAt, 0, null, function (c) {
-				c._recursivelyRemoveChildrenFromMap(bounds, depthToAnimateIn - 1);
+			marker._recursively(bounds, newZoomLevel, 0, function (c) {
+				c._recursivelyRemoveChildrenFromMap(bounds, previousZoomLevel);
 			});
 			me._animationEnd();
 		}, 250);
@@ -587,9 +622,10 @@ L.MarkerClusterGroup.include(!L.DomUtil.TRANSITION ? {
 		var me = this;
 
 		L.FeatureGroup.prototype.addLayer.call(this, layer);
-		if (newCluster !== true) {
+		if (newCluster !== layer) {
 			if (newCluster._childCount > 2) { //Was already a cluster
 
+				newCluster._updateIcon();
 				this._forceLayout();
 				this._animationStart();
 
@@ -607,7 +643,7 @@ L.MarkerClusterGroup.include(!L.DomUtil.TRANSITION ? {
 				this._forceLayout();
 
 				me._animationStart();
-				me._animationZoomOutSingle(newCluster, 0, this._map.getMaxZoom());
+				me._animationZoomOutSingle(newCluster, this._map.getMaxZoom(), this._map.getZoom());
 			}
 		}
 	},
@@ -624,12 +660,18 @@ L.MarkerClusterGroup.include(!L.DomUtil.TRANSITION ? {
 
 
 L.MarkerCluster = L.Marker.extend({
-	initialize: function (group, a, b) {
+	initialize: function (group, zoom, a, b) {
+
+		L.Marker.prototype.initialize.call(this, a ? (a._cLatLng || a.getLatLng()) : new L.LatLng(0, 0), { icon: this });
+
+
 		this._group = group;
+		this._zoom = zoom;
 
 		this._markers = [];
 		this._childClusters = [];
 		this._childCount = 0;
+		this._iconNeedsUpdate = true;
 
 		this._bounds = new L.LatLngBounds();
 
@@ -666,31 +708,54 @@ L.MarkerCluster = L.Marker.extend({
 		this._group._map.fitBounds(this._bounds);
 	},
 
-	_baseInit: function () {
-		this._latlng = this._wLatLng;
-		L.Marker.prototype.initialize.call(this, this._latlng, { icon: this._group.options.iconCreateFunction(this) });
+
+	_updateIcon: function () {
+		this._iconNeedsUpdate = true;
+		if (this._icon) {
+			this.setIcon(this);
+		}
+	},
+
+	//Cludge for Icon, we pretend to be an icon for performance
+	createIcon: function () {
+		if (this._iconNeedsUpdate) {
+			this._iconObj = this._group.options.iconCreateFunction(this);
+			this._iconNeedsUpdate = false;
+		}
+		return this._iconObj.createIcon();
+	},
+	createShadow: function () {
+		return this._iconObj.createShadow();
 	},
 
-	_addChild: function (new1) {
+
+	_addChild: function (new1, isNotificationFromChild) {
+
+		this._iconNeedsUpdate = true;
 		this._expandBounds(new1);
+
 		if (new1 instanceof L.MarkerCluster) {
-			this._childClusters.push(new1);
+			if (!isNotificationFromChild) {
+				this._childClusters.push(new1);
+				new1.__parent = this;
+			}
 			this._childCount += new1._childCount;
 		} else {
-			this._markers.push(new1);
+			if (!isNotificationFromChild) {
+				this._markers.push(new1);
+			}
 			this._childCount++;
 		}
 
-		if (this._icon) {
-			this.setIcon(this._group.options.iconCreateFunction(this));
+		if (this.__parent) {
+			this.__parent._addChild(new1, true);
 		}
-
 	},
 
+	//Expand our bounds and tell our parent to
 	_expandBounds: function (marker) {
-
 		var addedCount,
-		    addedLatLng = marker._latlng;
+		    addedLatLng = marker._wLatLng || marker._latlng;
 
 		if (marker instanceof L.MarkerCluster) {
 			this._bounds.extend(marker._bounds);
@@ -700,9 +765,9 @@ L.MarkerCluster = L.Marker.extend({
 			addedCount = 1;
 		}
 
-		if (!this._latlng) {
+		if (!this._cLatLng) {
 			// when clustering, take position of the first point as the cluster center
-			this._latlng = this._cLatLng = addedLatLng;
+			this._cLatLng = marker._cLatLng || addedLatLng;
 		}
 
 		// when showing clusters, take weighted average of all points as cluster center
@@ -710,7 +775,7 @@ L.MarkerCluster = L.Marker.extend({
 
 		//Calculate weighted latlng for display
 		if (!this._wLatLng) {
-			this._wLatLng = new L.LatLng(addedLatLng.lat, addedLatLng.lng);
+			this._latlng = this._wLatLng = new L.LatLng(addedLatLng.lat, addedLatLng.lng);
 		} else {
 			this._wLatLng.lat = (addedLatLng.lat * addedCount + this._wLatLng.lat * this._childCount) / totalCount;
 			this._wLatLng.lng = (addedLatLng.lng * addedCount + this._wLatLng.lng * this._childCount) / totalCount;
@@ -725,188 +790,7 @@ L.MarkerCluster = L.Marker.extend({
 		}
 		L.FeatureGroup.prototype.addLayer.call(this._group, this);
 	},
-
-	//layer: The layer to try add
-	//returns:
-	//  true: was able to put this marker in, but don't know its current visible parents position (If returned externally, add this marker at its position)
-	//  false: wasn't able to put this marker in
-	//  a MarkerCluster: the visible parent of the marker
-	_recursivelyAddLayer: function (layer, zoom) {
-		var group = this._group,
-			map = group._map,
-			maxClusterRadius = group.options.maxClusterRadius,
-			result = false,
-			sqDist = this._group._sqDist,
-			i;
-
-		for (i = this._childClusters.length - 1; i >= 0; i--) {
-			var c = this._childClusters[i];
-			//Recurse into children where their bounds fits the layer or they can just take it
-			if (c._bounds.contains(layer.getLatLng()) || c._canAcceptPosition(layer.getLatLng(), zoom + 1)) {
-				result = c._recursivelyAddLayer(layer, zoom + 1);
-				if (result) {
-					this._childCount++;
-					break;
-				}
-			}
-		}
-
-		//Couldn't add it to a child, but it should be part of us (this._zoom -> we are the root node)
-		if (!result && (this._canAcceptPosition(layer.getLatLng(), zoom) || ('_zoom' in this))) {
-
-			//If we are allowed to cluster at our childs level
-			if (zoom + 1 !== group.options.disableClusteringAtZoom) {
-
-				//Add to ourself instead
-				var layerPos = map.project(layer.getLatLng(), zoom + 1);
-
-				//var distanceGrid = new L.DistanceGrid(maxClusterRadius);
-				for (i = this._markers.length - 1; i >= 0; i--) {
-					var m = this._markers[i];
-					if (sqDist(layerPos, map.project(m.getLatLng(), zoom + 1)) < (maxClusterRadius * maxClusterRadius)) {
-						result = m;
-						this._markers.splice(i, 1);
-						this._childCount--;
-						break;
-					}
-				}
-			}
-			//result = distanceGrid.getNearObject(map.project(layer.getLatLng(), zoom + 1));
-
-			if (result) {
-				//Create a new cluster for them
-				result = new L.MarkerCluster(this._group, result, layer);
-				result._baseInit();
-
-				//Add our new child
-				this._addChild(result);
-
-				//We may be above the zoom that these 2 markers would initially cluster at
-				// so push the new cluster as deep as it can go
-				var wantedZoom = map.getZoom() - 1,
-					maxZoom = map.getMaxZoom(),
-					newResult,
-					finalResult = (zoom === wantedZoom) ? result : true;
-
-				if (group.options.disableClusteringAtZoom) {
-					maxZoom = group.options.disableClusteringAtZoom - 2;
-				}
-
-				while (zoom < maxZoom) {
-					zoom++;
-
-					//Shouldn't be a cluster at this level
-					if (sqDist(map.project(layer.getLatLng(), zoom + 1), map.project(result._markers[0].getLatLng(), zoom + 1)) >= (maxClusterRadius * maxClusterRadius)) {
-						break;
-					}
-
-					newResult = new L.MarkerCluster(this._group, result._markers[0], layer);
-					newResult._baseInit();
-					result._markers = [];
-					result._childClusters.push(newResult);
-					result = newResult;
-
-					if (zoom === wantedZoom) {
-						finalResult = result;
-					}
-				}
-				result = finalResult;
-
-			} else {
-				this._addChild(layer);
-				result = true;
-			}
-		}
-
-		if (result) {
-			if (!('_zoom' in this)) {
-				this.setIcon(this._group.options.iconCreateFunction(this));
-			}
-			this._recalculateBounds();
-		}
-		if (result === true) {
-			if (this._icon) {
-				result = this;
-			}
-		}
-
-		return result;
-	},
-
-	_canAcceptPosition: function (latlng, zoom) {
-		if (this._childCount === 0) {
-			return true;
-		}
-
-		var clusterRadiusSqrd = this._group.options.maxClusterRadius * this._group.options.maxClusterRadius,
-			pos = this._group._map.project(this._cLatLng, zoom),
-			otherpos = this._group._map.project(latlng, zoom);
-
-		return (this._group._sqDist(pos, otherpos) <= clusterRadiusSqrd);
-	},
-
-	//Removes the given node from this marker cluster (or its child as required)
-	//Returns true if it (or a child cluster) removes the marker
-	_recursivelyRemoveLayer: function (layer) {
-		var group = this._group,
-			markers = this._markers,
-			childClusters = this._childClusters,
-			i;
-
-		//Check our children
-		for (i = markers.length - 1; i >= 0; i--) {
-			if (markers[i] === layer) {
-				if (markers[i]._icon) {
-					L.FeatureGroup.prototype.removeLayer.call(group, markers[i]);
-				}
-
-				markers.splice(i, 1);
-				this._childCount--;
-				this._recalculateBounds();
-
-				if (!('_zoom' in this)) {
-					this.setIcon(group.options.iconCreateFunction(this));
-				}
-				return true;
-			}
-		}
-
-		//Otherwise check our childClusters
-		for (i = childClusters.length - 1; i >= 0; i--) {
-			var child = childClusters[i];
-
-			if (child._bounds.contains(layer._latlng) && child._recursivelyRemoveLayer(layer)) {
-				this._childCount--;
-				if (!('_zoom' in this)) {
-					this.setIcon(group.options.iconCreateFunction(this));
-				}
-
-				//if our child cluster is no longer a cluster, remove it and replace with just the marker
-				if (child._childCount === 1) {
-
-					//If the child is visible, remove it and put the marker on the map
-					if (child._icon) {
-						L.FeatureGroup.prototype.removeLayer.call(group, child);
-						L.FeatureGroup.prototype.addLayer.call(group, child._markers[0]);
-					}
-
-					//Take ownership of its only marker and bin the cluster
-					markers.push(child._markers[0]);
-					childClusters.splice(i, 1);
-				}
-
-				this._recalculateBounds();
-
-				if (this._icon && this._childCount > 1) { //No need to update if we are getting removed anyway
-					this.setIcon(group.options.iconCreateFunction(this));
-				}
-				return true;
-			}
-		}
-
-		return false;
-	},
-
+	
 	_recursivelyAnimateChildrenIn: function (bounds, center, depth) {
 		this._recursively(bounds, 0, depth - 1,
 			function (c) {
@@ -936,16 +820,16 @@ L.MarkerCluster = L.Marker.extend({
 		);
 	},
 
-	_recursivelyAnimateChildrenInAndAddSelfToMap: function (bounds, depthToStartAt, depthToAnimateIn) {
-		this._recursively(bounds, depthToStartAt, 0,
+	_recursivelyAnimateChildrenInAndAddSelfToMap: function (bounds, previousZoomLevel, newZoomLevel) {
+		this._recursively(bounds, newZoomLevel, 0,
 			function (c) {
-				c._recursivelyAnimateChildrenIn(bounds, c._group._map.latLngToLayerPoint(c.getLatLng()).round(), depthToAnimateIn);
+				c._recursivelyAnimateChildrenIn(bounds, c._group._map.latLngToLayerPoint(c.getLatLng()).round(), previousZoomLevel);
 
 				//TODO: depthToAnimateIn affects _isSingleParent, if there is a multizoom we may/may not be.
 				//As a hack we only do a animation free zoom on a single level zoom, if someone does multiple levels then we always animate
-				if (c._isSingleParent() && depthToAnimateIn === 1) {
+				if (c._isSingleParent() && previousZoomLevel - 1 === newZoomLevel) {
 					c.setOpacity(1);
-					c._recursivelyRemoveChildrenFromMap(bounds, depthToAnimateIn - 1); //Immediately remove our children as we are replacing them. TODO previousBounds not bounds
+					c._recursivelyRemoveChildrenFromMap(bounds, previousZoomLevel); //Immediately remove our children as we are replacing them. TODO previousBounds not bounds
 				} else {
 					c.setOpacity(0);
 				}
@@ -955,16 +839,16 @@ L.MarkerCluster = L.Marker.extend({
 		);
 	},
 
-	_recursivelyBecomeVisible: function (bounds, depth) {
-		this._recursively(bounds, 0, depth, null, function (c) {
+	_recursivelyBecomeVisible: function (bounds, zoomLevel) {
+		this._recursively(bounds, 0, zoomLevel, null, function (c) {
 			c.setOpacity(1);
 		});
 	},
 
-	_recursivelyAddChildrenToMap: function (startPos, depth, bounds) {
-		this._recursively(bounds, 0, depth,
-			function (c, recursionDepth) {
-				if (recursionDepth === 0) {
+	_recursivelyAddChildrenToMap: function (startPos, zoomLevel, bounds) {
+		this._recursively(bounds, 0, zoomLevel,
+			function (c) {
+				if (zoomLevel === c._zoom) {
 					return;
 				}
 
@@ -988,12 +872,11 @@ L.MarkerCluster = L.Marker.extend({
 			},
 			function (c) {
 				c._addToMap(startPos);
-
 			}
 		);
 	},
 
-	_recursivelyRestoreChildPositions: function (depth) {
+	_recursivelyRestoreChildPositions: function (zoomLevel) {
 		//Fix positions of child markers
 		for (var i = this._markers.length - 1; i >= 0; i--) {
 			var nm = this._markers[i];
@@ -1003,14 +886,14 @@ L.MarkerCluster = L.Marker.extend({
 			}
 		}
 
-		if (depth === 1) {
+		if (zoomLevel - 1 === this._zoom) {
 			//Reposition child clusters
 			for (var j = this._childClusters.length - 1; j >= 0; j--) {
 				this._childClusters[j]._restorePosition();
 			}
 		} else {
 			for (var k = this._childClusters.length - 1; k >= 0; k--) {
-				this._childClusters[k]._recursivelyRestoreChildPositions(depth - 1);
+				this._childClusters[k]._recursivelyRestoreChildPositions(zoomLevel);
 			}
 		}
 	},
@@ -1023,9 +906,9 @@ L.MarkerCluster = L.Marker.extend({
 	},
 
 	//exceptBounds: If set, don't remove any markers/clusters in it
-	_recursivelyRemoveChildrenFromMap: function (previousBounds, depth, exceptBounds) {
+	_recursivelyRemoveChildrenFromMap: function (previousBounds, zoomLevel, exceptBounds) {
 		var m, i;
-		this._recursively(previousBounds, 0, depth,
+		this._recursively(previousBounds, -1, zoomLevel - 1,
 			function (c) {
 				//Remove markers at every level
 				for (i = c._markers.length - 1; i >= 0; i--) {
@@ -1051,36 +934,37 @@ L.MarkerCluster = L.Marker.extend({
 
 	//Run the given functions recursively to this and child clusters
 	// boundsToApplyTo: a L.LatLngBounds representing the bounds of what clusters to recurse in to
-	// depthToStartAt: the depth to start calling the given functions
-	// timesToRecurse: how many layers deep to recurse in to after hitting depthToStartAt, bottom level: depthToRunFor == 0
+	// zoomLevelToStart: zoom level to start running functions (inclusive)
+	// zoomLevelToStop: zoom level to stop running functions (inclusive)
 	// runAtEveryLevel: function that takes an L.MarkerCluster as an argument that should be applied on every level
 	// runAtBottomLevel: function that takes an L.MarkerCluster as an argument that should be applied at only the bottom level
-	_recursively: function (boundsToApplyTo, depthToStartAt, timesToRecurse, runAtEveryLevel, runAtBottomLevel) {
+	_recursively: function (boundsToApplyTo, zoomLevelToStart, zoomLevelToStop, runAtEveryLevel, runAtBottomLevel) {
 		var childClusters = this._childClusters,
+		    zoom = this._zoom,
 			i, c;
 
-		if (depthToStartAt > 0) { //Still going down to required depth, just recurse to child clusters
+		if (zoomLevelToStart > zoom) { //Still going down to required depth, just recurse to child clusters
 			for (i = childClusters.length - 1; i >= 0; i--) {
 				c = childClusters[i];
 				if (boundsToApplyTo.intersects(c._bounds)) {
-					c._recursively(boundsToApplyTo, depthToStartAt - 1, timesToRecurse, runAtEveryLevel, runAtBottomLevel);
+					c._recursively(boundsToApplyTo, zoomLevelToStart, zoomLevelToStop, runAtEveryLevel, runAtBottomLevel);
 				}
 			}
 		} else { //In required depth
 
 			if (runAtEveryLevel) {
-				runAtEveryLevel(this, timesToRecurse);
+				runAtEveryLevel(this);
 			}
-			if (timesToRecurse === 0 && runAtBottomLevel) {
+			if (runAtBottomLevel && this._zoom === zoomLevelToStop) {
 				runAtBottomLevel(this);
 			}
 
 			//TODO: This loop is almost the same as above
-			if (timesToRecurse > 0) {
+			if (zoomLevelToStop > zoom) {
 				for (i = childClusters.length - 1; i >= 0; i--) {
 					c = childClusters[i];
 					if (boundsToApplyTo.intersects(c._bounds)) {
-						c._recursively(boundsToApplyTo, depthToStartAt, timesToRecurse - 1, runAtEveryLevel, runAtBottomLevel);
+						c._recursively(boundsToApplyTo, zoomLevelToStart, zoomLevelToStop, runAtEveryLevel, runAtBottomLevel);
 					}
 				}
 			}
@@ -1122,6 +1006,7 @@ L.DistanceGrid = function (cellSize) {
 	this._cellSize = cellSize;
 	this._sqCellSize = cellSize * cellSize;
 	this._grid = {};
+	this._objectPoint = { };
 };
 
 L.DistanceGrid.prototype = {
@@ -1131,10 +1016,10 @@ L.DistanceGrid.prototype = {
 		    y = this._getCoord(point.y),
 		    grid = this._grid,
 		    row = grid[y] = grid[y] || {},
-		    cell = row[x] = row[x] || [];
+		    cell = row[x] = row[x] || [],
+		    stamp = L.Util.stamp(obj);
 
-		obj._dGridCell = cell;
-		obj._dGridPoint = point;
+		this._objectPoint[stamp] = point;
 
 		cell.push(obj);
 	},
@@ -1144,25 +1029,30 @@ L.DistanceGrid.prototype = {
 		this.addObject(obj, point);
 	},
 
-	removeObject: function (obj) {
-		var oldCell = obj._dGridCell,
-		    point = obj._dGridPoint,
-		    i, len, x, y;
+	//Returns true if the object was found
+	removeObject: function (obj, point) {
+		var x = this._getCoord(point.x),
+		    y = this._getCoord(point.y),
+		    grid = this._grid,
+		    row = grid[y] = grid[y] || {},
+		    cell = row[x] = row[x] || [],
+		    i, len;
+
+		delete this._objectPoint[L.Util.stamp(obj)];
 
-		for (i = 0, len = oldCell.length; i < len; i++) {
-			if (oldCell[i] === obj) {
+		for (i = 0, len = cell.length; i < len; i++) {
+			if (cell[i] === obj) {
 
-				oldCell.splice(i, 1);
+				cell.splice(i, 1);
 
 				if (len === 1) {
-					x = this._getCoord(point.x);
-					y = this._getCoord(point.y);
-					delete this._grid[y][x];
+					delete row[x];
 				}
 
-				break;
+				return true;
 			}
 		}
+
 	},
 
 	eachObject: function (fn, context) {
@@ -1194,8 +1084,9 @@ L.DistanceGrid.prototype = {
 		var x = this._getCoord(point.x),
 		    y = this._getCoord(point.y),
 		    i, j, k, row, cell, len, obj, dist,
+		    objectPoint = this._objectPoint,
 		    closestDistSq = this._sqCellSize,
-			closest = null;
+		    closest = null;
 
 		for (i = y - 1; i <= y + 1; i++) {
 			row = this._grid[i];
@@ -1207,7 +1098,7 @@ L.DistanceGrid.prototype = {
 
 						for (k = 0, len = cell.length; k < len; k++) {
 							obj = cell[k];
-							dist = this._sqDist(obj._dGridPoint, point);
+							dist = this._sqDist(objectPoint[L.Util.stamp(obj)], point);
 							if (dist < closestDistSq) {
 								closestDistSq = dist;
 								closest = obj;
diff --git a/dist/leaflet.markercluster.js b/dist/leaflet.markercluster.js
index c25db86..0cf3fc2 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){L.MarkerClusterGroup=L.FeatureGroup.extend({options:{maxClusterRadius:80,iconCreateFunction:null,spiderfyOnMaxZoom:!0,showCoverageOnHover:!0,zoomToBoundsOnClick:!0,singleMarkerMode:!1,disableClusteringAtZoom:null,skipDuplicateAddTesting:!1,animateAddingMarkers:!1},initialize:function(e){L.Util.setOptions(this,e),this.options.iconCreateFunction||(this.options.iconCreateFunction=this._defaultIconCreateFunction),L.FeatureGroup.prototype.initialize.call(this,[]),this._inZoomAn [...]
\ No newline at end of file
+(function(e,t){L.MarkerClusterGroup=L.FeatureGroup.extend({options:{maxClusterRadius:80,iconCreateFunction:null,spiderfyOnMaxZoom:!0,showCoverageOnHover:!0,zoomToBoundsOnClick:!0,singleMarkerMode:!1,disableClusteringAtZoom:null,skipDuplicateAddTesting:!1,animateAddingMarkers:!1},initialize:function(e){L.Util.setOptions(this,e),this.options.iconCreateFunction||(this.options.iconCreateFunction=this._defaultIconCreateFunction),L.FeatureGroup.prototype.initialize.call(this,[]),this._inZoomAn [...]
\ No newline at end of file

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/leaflet-markercluster.git



More information about the Pkg-javascript-commits mailing list