[Pkg-javascript-commits] [leaflet-markercluster] 151/219: Externalized bound and wLatLng computations

Jonas Smedegaard dr at jones.dk
Sat May 7 09:39:29 UTC 2016


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

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

commit 7bbf70e478894355f886967494fe33401d7c2890
Author: ghybs <ghybs1 at gmail.com>
Date:   Tue Oct 20 14:58:36 2015 +0400

    Externalized bound and wLatLng computations
    
    for cluster._addChild and MCG._removeLayer, only the cluster position is set.
    _bounds and _wLatLng must be recomputed by calling _recalculateBounds manually within each method that uses the 2 above private methods.
    Also re-factored _recalculateBounds to compute the weighted position more simply.
---
 src/MarkerCluster.js      | 102 ++++++++++++++++++++++++++++++----------------
 src/MarkerClusterGroup.js |  49 +++++++++++++++++-----
 2 files changed, 106 insertions(+), 45 deletions(-)

diff --git a/src/MarkerCluster.js b/src/MarkerCluster.js
index 2ce3190..90d387f 100644
--- a/src/MarkerCluster.js
+++ b/src/MarkerCluster.js
@@ -11,6 +11,7 @@ L.MarkerCluster = L.Marker.extend({
 		this._childClusters = [];
 		this._childCount = 0;
 		this._iconNeedsUpdate = true;
+		this._boundsNeedUpdate = true;
 
 		this._bounds = new L.LatLngBounds();
 
@@ -99,7 +100,9 @@ L.MarkerCluster = L.Marker.extend({
 	_addChild: function (new1, isNotificationFromChild) {
 
 		this._iconNeedsUpdate = true;
-		this._expandBounds(new1);
+
+		this._boundsNeedUpdate = true;
+		this._setClusterCenter(new1);
 
 		if (new1 instanceof L.MarkerCluster) {
 			if (!isNotificationFromChild) {
@@ -119,34 +122,65 @@ L.MarkerCluster = L.Marker.extend({
 		}
 	},
 
-	//Expand our bounds and tell our parent to
-	_expandBounds: function (marker) {
-		var addedCount,
-		    addedLatLng = marker._wLatLng || marker._latlng;
+	/**
+	 * Makes sure the cluster center is set. If not, uses the child center if it is a cluster, or the marker position.
+	 * @param child L.MarkerCluster|L.Marker that will be used as cluster center if not defined yet.
+	 * @private
+	 */
+	_setClusterCenter: function (child) {
+		if (!this._cLatLng) {
+			// when clustering, take position of the first point as the cluster center
+			this._cLatLng = child._cLatLng || child._latlng;
+		}
+	},
 
-		if (marker instanceof L.MarkerCluster) {
-			this._bounds.extend(marker._bounds);
-			addedCount = marker._childCount;
-		} else {
-			this._bounds.extend(addedLatLng);
-			addedCount = 1;
+	_recalculateBounds: function () {
+		var markers = this._markers,
+		    childClusters = this._childClusters,
+		    latSum = 0,
+		    lngSum = 0,
+		    totalCount = this._childCount,
+		    i, child, childLatLng, childCount;
+
+		this._bounds = new L.LatLngBounds();
+
+		// Case where all markers are removed from the map and we are left with just an empty _topClusterLevel.
+		if (totalCount === 0) {
+			return;
 		}
 
-		if (!this._cLatLng) {
-			// when clustering, take position of the first point as the cluster center
-			this._cLatLng = marker._cLatLng || addedLatLng;
+		// Child markers.
+		for (i = 0; i < markers.length; i++) {
+			childLatLng = markers[i]._latlng;
+
+			this._bounds.extend(childLatLng);
+
+			latSum += childLatLng.lat;
+			lngSum += childLatLng.lng;
 		}
 
-		// when showing clusters, take weighted average of all points as cluster center
-		var totalCount = this._childCount + addedCount;
+		// Child clusters.
+		for (i = 0; i < childClusters.length; i++) {
+			child = childClusters[i];
 
-		//Calculate weighted latlng for display
-		if (!this._wLatLng) {
-			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;
+			// Re-compute child bounds and weighted position first if necessary.
+			if (child._boundsNeedUpdate) {
+				child._recalculateBounds();
+			}
+
+			this._bounds.extend(child._bounds);
+
+			childLatLng = child._wLatLng;
+			childCount = child._childCount;
+
+			latSum += childLatLng.lat * childCount;
+			lngSum += childLatLng.lng * childCount;
 		}
+
+		this._latlng = this._wLatLng = new L.LatLng(latSum / totalCount, lngSum / totalCount);
+
+		// Reset dirty flag.
+		this._boundsNeedUpdate = false;
 	},
 
 	//Set our markers position as given and add it to the map
@@ -344,20 +378,20 @@ L.MarkerCluster = L.Marker.extend({
 		}
 	},
 
-	_recalculateBounds: function () {
-		var markers = this._markers,
-			childClusters = this._childClusters,
-			i;
-
-		this._bounds = new L.LatLngBounds();
-		delete this._wLatLng;
+	/**
+	 * Runs a function recursively on every child cluster, then on THIS cluster.
+	 * @param runAtEveryLevel function to be called on each cluster. Takes as single argument the cluster to be processed.
+	 * @private
+	 */
+	_recursivelySimple: function (runAtEveryLevel) {
+		var childClusters = this._childClusters,
+		    i = 0;
 
-		for (i = markers.length - 1; i >= 0; i--) {
-			this._expandBounds(markers[i]);
-		}
-		for (i = childClusters.length - 1; i >= 0; i--) {
-			this._expandBounds(childClusters[i]);
+		for (; i < childClusters.length; i++) {
+			childClusters[i]._recursivelySimple(runAtEveryLevel);
 		}
+
+		return runAtEveryLevel(this);
 	},
 
 
diff --git a/src/MarkerClusterGroup.js b/src/MarkerClusterGroup.js
index f801547..492736e 100644
--- a/src/MarkerClusterGroup.js
+++ b/src/MarkerClusterGroup.js
@@ -105,6 +105,9 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
 
 		this._addLayer(layer, this._maxZoom);
 
+		// Re-calculate bounds must be done manually now.
+		this._topClusterLevel._recalculateBounds();
+
 		//Work out what is visible
 		var visibleLayer = layer,
 			currentZoom = this._map.getZoom();
@@ -160,6 +163,9 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
 		//Remove the marker from clusters
 		this._removeLayer(layer, true);
 
+		// Bounds and weighted position must be done manually now.
+		this._topClusterLevel._recalculateBounds();
+
 		if (this._featureGroup.hasLayer(layer)) {
 			this._featureGroup.removeLayer(layer);
 			if (layer.clusterShow) {
@@ -222,7 +228,12 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
 					chunkProgress(offset, layersArray.length, (new Date()).getTime() - started);
 				}
 
+				// Completed processing all markers.
 				if (offset === layersArray.length) {
+
+					// Refresh bounds and weighted positions.
+					this._topClusterLevel._recalculateBounds();
+
 					//Update the icons of all those visible clusters that were affected
 					this._featureGroup.eachLayer(function (c) {
 						if (c instanceof L.MarkerCluster && c._iconNeedsUpdate) {
@@ -303,6 +314,9 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
 			}
 		}
 
+		// Re-compute bounds and weighted positions.
+		this._topClusterLevel._recalculateBounds();
+
 		//Fix up the clusters and markers on the map
 		this._topClusterLevel._recursivelyAddChildrenToMap(null, this._zoom, this._currentShownBounds);
 
@@ -512,6 +526,9 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
 		l = this._needsClustering;
 		this._needsClustering = [];
 		this.addLayers(l);
+
+		// Re-compute bounds and weighted positions.
+		this._topClusterLevel._recalculateBounds();
 	},
 
 	//Overrides FeatureGroup.onRemove
@@ -558,6 +575,23 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
 		}
 	},
 
+	/**
+	 * 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) {
+		var map = this._map,
+		    gridUnclustered = this._gridUnclustered;
+
+		for (; z >= 0; z--) {
+			if (!gridUnclustered[z].removeObject(marker, map.project(marker.getLatLng(), z))) {
+				break;
+			}
+		}
+	},
+
 	//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) {
@@ -568,11 +602,7 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
 
 		//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;
-				}
-			}
+			this._removeFromGridUnclustered(marker, this._maxZoom);
 		}
 
 		//Work our way up the clusters removing them as we go if required
@@ -585,6 +615,7 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
 
 		while (cluster) {
 			cluster._childCount--;
+			cluster._boundsNeedUpdate = true;
 
 			if (cluster._zoom < 0) {
 				//Top level, do nothing
@@ -610,7 +641,7 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
 					}
 				}
 			} else {
-				cluster._recalculateBounds();
+				//cluster._recalculateBounds();
 				if (!dontUpdateMap || !cluster._icon) {
 					cluster._updateIcon();
 				}
@@ -842,11 +873,7 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
 				parent._addChild(lastParent);
 
 				//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;
-					}
-				}
+				this._removeFromGridUnclustered(closest, zoom);
 
 				return;
 			}

-- 
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