From 1820aef3fb5c926664de1d4d484f64a5c9ba7099 Mon Sep 17 00:00:00 2001
From: YANGDL <114714267@qq.com>
Date: 星期二, 05 一月 2021 17:06:08 +0800
Subject: [PATCH] 优化逻辑

---
 src/components/plugin/cluster-layer/leaflet.markercluster-src.js | 4503 +++++++++++++++++++++++++++++-----------------------------
 1 files changed, 2,245 insertions(+), 2,258 deletions(-)

diff --git a/src/components/plugin/cluster-layer/leaflet.markercluster-src.js b/src/components/plugin/cluster-layer/leaflet.markercluster-src.js
index 85e3882..e0cfa31 100644
--- a/src/components/plugin/cluster-layer/leaflet.markercluster-src.js
+++ b/src/components/plugin/cluster-layer/leaflet.markercluster-src.js
@@ -1,1095 +1,1086 @@
-'use strict';
-function init(L) {
-    /*
+'use strict'
+function init (L) {
+  /*
      * L.MarkerClusterGroup extends L.FeatureGroup by clustering the markers contained within
      */
 
-    var MarkerClusterGroup = L.MarkerClusterGroup = L.FeatureGroup.extend({
+  var MarkerClusterGroup = L.MarkerClusterGroup = L.FeatureGroup.extend({
 
-        options: {
-            maxClusterRadius: 80, // A cluster will cover at most this many pixels from its center
-            iconCreateFunction: null,
-            clusterPane: L.Marker.prototype.options.pane,
+    options: {
+      maxClusterRadius: 80, // A cluster will cover at most this many pixels from its center
+      iconCreateFunction: null,
+      clusterPane: L.Marker.prototype.options.pane,
 
-            spiderfyOnMaxZoom: true,
-            showCoverageOnHover: true,
-            zoomToBoundsOnClick: true,
-            singleMarkerMode: false,
+      spiderfyOnMaxZoom: true,
+      showCoverageOnHover: true,
+      zoomToBoundsOnClick: true,
+      singleMarkerMode: false,
 
-            disableClusteringAtZoom: null,
+      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,
+      //  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,
+      //  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,
+      // 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 center
-            spiderfyDistanceMultiplier: 1,
+      // Increase to increase the distance away that spiderfied markers appear from the center
+      spiderfyDistanceMultiplier: 1,
 
-            //  Make it possible to specify a polyline options on a spider leg
-            spiderLegPolylineOptions: {weight: 1.5, color: '#222', opacity: 0.5},
+      //  Make it possible to specify a polyline options on a spider leg
+      spiderLegPolylineOptions: { 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 setTimeouts
-            chunkedLoading: 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/browser
-            chunkProgress: null, //  progress callback: function(processed, total, elapsed) (e.g. for a progress indicator)
+      //  When bulk adding layers, adds markers in chunks. Means addLayers may not add all the layers in the call, others will be loaded during setTimeouts
+      chunkedLoading: 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/browser
+      chunkProgress: null, //  progress callback: function(processed, total, elapsed) (e.g. for a progress indicator)
 
-            // Options to pass to the L.Polygon constructor
-            polygonOptions: {}
-        },
+      // Options to pass to the L.Polygon constructor
+      polygonOptions: {}
+    },
 
-        initialize: function(options) {
-            L.Util.setOptions(this, options);
-            if (!this.options.iconCreateFunction) {
-                this.options.iconCreateFunction = this._defaultIconCreateFunction;
+    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/move
+      this._currentShownBounds = null
+
+      this._queue = []
+
+      this._childMarkerEventHandlers = {
+        dragstart: this._childMarkerDragStart,
+        move: this._childMarkerMoved,
+        dragend: this._childMarkerDragEnd
+      }
+
+      //  Hook the appropriate animation methods.
+      var animate = 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 (layer instanceof L.LayerGroup) {
+        return this.addLayers([layer])
+      }
+
+      // Don't cluster non point data
+      if (!layer.getLatLng) {
+        this._nonPointGroup.addLayer(layer)
+        this.fire('layeradd', { layer: layer })
+        return this
+      }
+
+      if (!this._map) {
+        this._needsClustering.push(layer)
+        this.fire('layeradd', { layer: layer })
+        return this
+      }
+
+      if (this.hasLayer(layer)) {
+        return this
+      }
+
+      // If we have already clustered we'll need to add this one to a cluster
+
+      if (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 visible
+      var visibleLayer = layer
+      var 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)
+        }
+      }
+      return this
+    },
+
+    removeLayer: function (layer) {
+      if (layer instanceof L.LayerGroup) {
+        return this.removeLayers([layer])
+      }
+
+      // Non point layers
+      if (!layer.getLatLng) {
+        this._nonPointGroup.removeLayer(layer)
+        this.fire('layerremove', { layer: layer })
+        return this
+      }
+
+      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 })
+        return this
+      }
+
+      if (!layer.__parent) {
+        return this
+      }
+
+      if (this._unspiderfy) {
+        this._unspiderfy()
+        this._unspiderfyLayer(layer)
+      }
+
+      // Remove the marker from clusters
+      this._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()
+        }
+      }
+
+      return this
+    },
+
+    // Takes an array of markers and adds them in bulk
+    addLayers: function (layersArray, skipLayerAddEvent) {
+      if (!L.Util.isArray(layersArray)) {
+        return this.addLayer(layersArray)
+      }
+
+      var fg = this._featureGroup
+      var npg = this._nonPointGroup
+      var chunked = this.options.chunkedLoading
+      var chunkInterval = this.options.chunkInterval
+      var chunkProgress = this.options.chunkProgress
+      var l = layersArray.length
+      var offset = 0
+      var originalArray = true
+      var m
+
+      if (this._map) {
+        var started = (new Date()).getTime()
+        var process = L.bind(function () {
+          var start = (new Date()).getTime()
+          for (; offset < l; offset++) {
+            if (chunked && offset % 200 === 0) {
+              //  every couple hundred markers, instrument the time elapsed since processing started:
+              var elapsed = (new Date()).getTime() - start
+              if (elapsed > chunkInterval) {
+                break //  been working too hard, time to take a break :-)
+              }
             }
 
-            this._featureGroup = L.featureGroup();
-            this._featureGroup.addEventParent(this);
+            m = layersArray[offset]
 
-            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/move
-            this._currentShownBounds = null;
-
-            this._queue = [];
-
-            this._childMarkerEventHandlers = {
-                'dragstart': this._childMarkerDragStart,
-                'move': this._childMarkerMoved,
-                'dragend': this._childMarkerDragEnd,
-            };
-
-            //  Hook the appropriate animation methods.
-            var animate = 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 (layer instanceof L.LayerGroup) {
-                return this.addLayers([layer]);
+            //  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/6
+            if (m instanceof L.LayerGroup) {
+              if (originalArray) {
+                layersArray = layersArray.slice()
+                originalArray = false
+              }
+              this._extractNonGroupLayers(m, layersArray)
+              l = layersArray.length
+              continue
             }
 
-            // Don't cluster non point data
-            if (!layer.getLatLng) {
-                this._nonPointGroup.addLayer(layer);
-                this.fire('layeradd', {layer: layer});
-                return this;
+            // Not point data, can't be clustered
+            if (!m.getLatLng) {
+              npg.addLayer(m)
+              if (!skipLayerAddEvent) {
+                this.fire('layeradd', { layer: m })
+              }
+              continue
             }
 
-            if (!this._map) {
-                this._needsClustering.push(layer);
-                this.fire('layeradd', {layer: layer});
-                return this;
+            if (this.hasLayer(m)) {
+              continue
             }
 
-            if (this.hasLayer(layer)) {
-                return this;
+            this._addLayer(m, this._maxZoom)
+            if (!skipLayerAddEvent) {
+              this.fire('layeradd', { layer: m })
             }
 
-
-            // If we have already clustered we'll need to add this one to a cluster
-
-            if (this._unspiderfy) {
-                this._unspiderfy();
+            // 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 will
+            if (m.__parent) {
+              if (m.__parent.getChildCount() === 2) {
+                var markers = m.__parent.getAllChildMarkers()
+                var otherMarker = markers[0] === m ? markers[1] : markers[0]
+                fg.removeLayer(otherMarker)
+              }
             }
+          }
 
-            this._addLayer(layer, this._maxZoom);
-            this.fire('layeradd', {layer: layer});
+          if (chunkProgress) {
+            //  report progress and time elapsed:
+            chunkProgress(offset, l, (new Date()).getTime() - started)
+          }
 
+          //  Completed processing all markers.
+          if (offset === l) {
             //  Refresh bounds and weighted positions.
-            this._topClusterLevel._recalculateBounds();
+            this._topClusterLevel._recalculateBounds()
 
-            this._refreshClustersIcons();
+            this._refreshClustersIcons()
 
-            // Work out what is visible
-            var visibleLayer = layer,
-                currentZoom = this._zoom;
-            if (layer.__parent) {
-                while (visibleLayer.__parent._zoom >= currentZoom) {
-                    visibleLayer = visibleLayer.__parent;
-                }
+            this._topClusterLevel._recursivelyAddChildrenToMap(null, this._zoom, this._currentShownBounds)
+          } else {
+            setTimeout(process, this.options.chunkDelay)
+          }
+        }, this)
+
+        process()
+      } else {
+        var needsClustering = this._needsClustering
+
+        for (; offset < l; offset++) {
+          m = layersArray[offset]
+
+          //  Group of layers, append children to layersArray and skip.
+          if (m instanceof L.LayerGroup) {
+            if (originalArray) {
+              layersArray = layersArray.slice()
+              originalArray = false
             }
+            this._extractNonGroupLayers(m, layersArray)
+            l = layersArray.length
+            continue
+          }
 
-            if (this._currentShownBounds.contains(visibleLayer.getLatLng())) {
-                if (this.options.animateAddingMarkers) {
-                    this._animationAddLayer(layer, visibleLayer);
-                } else {
-                    this._animationAddLayerNonAnimated(layer, visibleLayer);
-                }
+          // Not point data, can't be clustered
+          if (!m.getLatLng) {
+            npg.addLayer(m)
+            continue
+          }
+
+          if (this.hasLayer(m)) {
+            continue
+          }
+
+          needsClustering.push(m)
+        }
+      }
+      return this
+    },
+
+    // Takes an array of markers and removes them in bulk
+    removeLayers: function (layersArray) {
+      var i; var m
+      var l = layersArray.length
+      var fg = this._featureGroup
+      var npg = this._nonPointGroup
+      var originalArray = true
+
+      if (!this._map) {
+        for (i = 0; i < l; i++) {
+          m = layersArray[i]
+
+          //  Group of layers, append children to layersArray and skip.
+          if (m instanceof L.LayerGroup) {
+            if (originalArray) {
+              layersArray = layersArray.slice()
+              originalArray = false
             }
-            return this;
-        },
+            this._extractNonGroupLayers(m, layersArray)
+            l = layersArray.length
+            continue
+          }
 
-        removeLayer: function(layer) {
+          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 })
+        }
+        return this
+      }
 
-            if (layer instanceof L.LayerGroup) {
-                return this.removeLayers([layer]);
-            }
+      if (this._unspiderfy) {
+        this._unspiderfy()
 
-            // Non point layers
-            if (!layer.getLatLng) {
-                this._nonPointGroup.removeLayer(layer);
-                this.fire('layerremove', {layer: layer});
-                return this;
-            }
+        //  Work on a copy of the array, so that next loop is not affected.
+        var layersArray2 = layersArray.slice()
+        var l2 = l
+        for (i = 0; i < l2; i++) {
+          m = layersArray2[i]
 
-            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});
-                return this;
-            }
+          //  Group of layers, append children to layersArray and skip.
+          if (m instanceof L.LayerGroup) {
+            this._extractNonGroupLayers(m, layersArray2)
+            l2 = layersArray2.length
+            continue
+          }
 
-            if (!layer.__parent) {
-                return this;
-            }
+          this._unspiderfyLayer(m)
+        }
+      }
 
-            if (this._unspiderfy) {
-                this._unspiderfy();
-                this._unspiderfyLayer(layer);
-            }
+      for (i = 0; i < l; i++) {
+        m = layersArray[i]
 
-            // Remove the marker from clusters
-            this._removeLayer(layer, true);
-            this.fire('layerremove', {layer: layer});
+        //  Group of layers, append children to layersArray and skip.
+        if (m instanceof L.LayerGroup) {
+          if (originalArray) {
+            layersArray = layersArray.slice()
+            originalArray = false
+          }
+          this._extractNonGroupLayers(m, layersArray)
+          l = layersArray.length
+          continue
+        }
 
-            //  Refresh bounds and weighted positions.
-            this._topClusterLevel._recalculateBounds();
+        if (!m.__parent) {
+          npg.removeLayer(m)
+          this.fire('layerremove', { layer: m })
+          continue
+        }
 
-            this._refreshClustersIcons();
+        this._removeLayer(m, true, true)
+        this.fire('layerremove', { layer: m })
 
-            layer.off(this._childMarkerEventHandlers, this);
+        if (fg.hasLayer(m)) {
+          fg.removeLayer(m)
+          if (m.clusterShow) {
+            m.clusterShow()
+          }
+        }
+      }
 
-            if (this._featureGroup.hasLayer(layer)) {
-                this._featureGroup.removeLayer(layer);
-                if (layer.clusterShow) {
-                    layer.clusterShow();
-                }
-            }
+      //  Refresh bounds and weighted positions.
+      this._topClusterLevel._recalculateBounds()
 
-            return this;
-        },
+      this._refreshClustersIcons()
 
-        // Takes an array of markers and adds them in bulk
-        addLayers: function(layersArray, skipLayerAddEvent) {
-            if (!L.Util.isArray(layersArray)) {
-                return this.addLayer(layersArray);
-            }
+      // Fix up the clusters and markers on the map
+      this._topClusterLevel._recursivelyAddChildrenToMap(null, this._zoom, this._currentShownBounds)
 
-            var fg = 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;
+      return this
+    },
 
-            if (this._map) {
-                var started = (new Date()).getTime();
-                var process = L.bind(function() {
-                    var start = (new Date()).getTime();
-                    for (; offset < l; offset++) {
-                        if (chunked && offset % 200 === 0) {
-                            //  every couple hundred markers, instrument the time elapsed since processing started:
-                            var elapsed = (new Date()).getTime() - start;
-                            if (elapsed > chunkInterval) {
-                                break; //  been working too hard, time to take a break :-)
-                            }
-                        }
+    // Removes all layers from the MarkerClusterGroup
+    clearLayers: function () {
+      // Need our own special implementation as the LayerGroup one doesn't work for us
 
-                        m = layersArray[offset];
+      // If we aren't on the map (yet), blow away the markers we know of
+      if (!this._map) {
+        this._needsClustering = []
+        this._needsRemoving = []
+        delete this._gridClusters
+        delete this._gridUnclustered
+      }
 
-                        //  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/6
-                        if (m instanceof L.LayerGroup) {
-                            if (originalArray) {
-                                layersArray = layersArray.slice();
-                                originalArray = false;
-                            }
-                            this._extractNonGroupLayers(m, layersArray);
-                            l = layersArray.length;
-                            continue;
-                        }
+      if (this._noanimationUnspiderfy) {
+        this._noanimationUnspiderfy()
+      }
 
-                        // Not point data, can't be clustered
-                        if (!m.getLatLng) {
-                            npg.addLayer(m);
-                            if (!skipLayerAddEvent) {
-                                this.fire('layeradd', {layer: m});
-                            }
-                            continue;
-                        }
+      // Remove all the visible layers
+      this._featureGroup.clearLayers()
+      this._nonPointGroup.clearLayers()
 
-                        if (this.hasLayer(m)) {
-                            continue;
-                        }
+      this.eachLayer(function (marker) {
+        marker.off(this._childMarkerEventHandlers, this)
+        delete marker.__parent
+      }, this)
 
-                        this._addLayer(m, this._maxZoom);
-                        if (!skipLayerAddEvent) {
-                            this.fire('layeradd', {layer: m});
-                        }
+      if (this._map) {
+        // Reset _topClusterLevel and the DistanceGrids
+        this._generateInitialClusters()
+      }
 
-                        // 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 will
-                        if (m.__parent) {
-                            if (m.__parent.getChildCount() === 2) {
-                                var markers = m.__parent.getAllChildMarkers(),
-                                    otherMarker = markers[0] === m ? markers[1] : markers[0];
-                                fg.removeLayer(otherMarker);
-                            }
-                        }
-                    }
+      return this
+    },
 
-                    if (chunkProgress) {
-                        //  report progress and time elapsed:
-                        chunkProgress(offset, l, (new Date()).getTime() - started);
-                    }
+    // Override FeatureGroup.getBounds as it doesn't work
+    getBounds: function () {
+      var bounds = new L.LatLngBounds()
 
-                    //  Completed processing all markers.
-                    if (offset === l) {
+      if (this._topClusterLevel) {
+        bounds.extend(this._topClusterLevel._bounds)
+      }
 
-                        //  Refresh bounds and weighted positions.
-                        this._topClusterLevel._recalculateBounds();
+      for (var i = this._needsClustering.length - 1; i >= 0; i--) {
+        bounds.extend(this._needsClustering[i].getLatLng())
+      }
 
-                        this._refreshClustersIcons();
+      bounds.extend(this._nonPointGroup.getBounds())
 
-                        this._topClusterLevel._recursivelyAddChildrenToMap(null, this._zoom, this._currentShownBounds);
-                    } else {
-                        setTimeout(process, this.options.chunkDelay);
-                    }
-                }, this);
+      return bounds
+    },
 
-                process();
-            } else {
-                var needsClustering = this._needsClustering;
+    // Overrides LayerGroup.eachLayer
+    eachLayer: function (method, context) {
+      var markers = this._needsClustering.slice()
+      var needsRemoving = this._needsRemoving
+      var thisNeedsRemoving; var i; var j
 
-                for (; offset < l; offset++) {
-                    m = layersArray[offset];
+      if (this._topClusterLevel) {
+        this._topClusterLevel.getAllChildMarkers(markers)
+      }
 
-                    //  Group of layers, append children to layersArray and skip.
-                    if (m instanceof L.LayerGroup) {
-                        if (originalArray) {
-                            layersArray = layersArray.slice();
-                            originalArray = false;
-                        }
-                        this._extractNonGroupLayers(m, layersArray);
-                        l = layersArray.length;
-                        continue;
-                    }
+      for (i = markers.length - 1; i >= 0; i--) {
+        thisNeedsRemoving = true
 
-                    // Not point data, can't be clustered
-                    if (!m.getLatLng) {
-                        npg.addLayer(m);
-                        continue;
-                    }
+        for (j = needsRemoving.length - 1; j >= 0; j--) {
+          if (needsRemoving[j].layer === markers[i]) {
+            thisNeedsRemoving = false
+            break
+          }
+        }
 
-                    if (this.hasLayer(m)) {
-                        continue;
-                    }
+        if (thisNeedsRemoving) {
+          method.call(context, markers[i])
+        }
+      }
 
-                    needsClustering.push(m);
-                }
-            }
-            return this;
-        },
+      this._nonPointGroup.eachLayer(method, context)
+    },
 
-        // Takes an array of markers and removes them in bulk
-        removeLayers: function(layersArray) {
-            var i, m,
-                l = layersArray.length,
-                fg = this._featureGroup,
-                npg = this._nonPointGroup,
-                originalArray = true;
+    // Overrides LayerGroup.getLayers
+    getLayers: function () {
+      var layers = []
+      this.eachLayer(function (l) {
+        layers.push(l)
+      })
+      return layers
+    },
 
-            if (!this._map) {
-                for (i = 0; i < l; i++) {
-                    m = layersArray[i];
+    // Overrides LayerGroup.getLayer, WARNING: Really bad performance
+    getLayer: function (id) {
+      var result = null
 
-                    //  Group of layers, append children to layersArray and skip.
-                    if (m instanceof L.LayerGroup) {
-                        if (originalArray) {
-                            layersArray = layersArray.slice();
-                            originalArray = false;
-                        }
-                        this._extractNonGroupLayers(m, layersArray);
-                        l = layersArray.length;
-                        continue;
-                    }
+      id = parseInt(id, 10)
 
-                    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});
-                }
-                return this;
-            }
+      this.eachLayer(function (l) {
+        if (L.stamp(l) === id) {
+          result = l
+        }
+      })
 
-            if (this._unspiderfy) {
-                this._unspiderfy();
+      return result
+    },
 
-                //  Work on a copy of the array, so that next loop is not affected.
-                var layersArray2 = layersArray.slice(),
-                    l2 = l;
-                for (i = 0; i < l2; i++) {
-                    m = layersArray2[i];
+    // Returns true if the given layer is in this MarkerClusterGroup
+    hasLayer: function (layer) {
+      if (!layer) {
+        return false
+      }
 
-                    //  Group of layers, append children to layersArray and skip.
-                    if (m instanceof L.LayerGroup) {
-                        this._extractNonGroupLayers(m, layersArray2);
-                        l2 = layersArray2.length;
-                        continue;
-                    }
+      var i; var anArray = this._needsClustering
 
-                    this._unspiderfyLayer(m);
-                }
-            }
+      for (i = anArray.length - 1; i >= 0; i--) {
+        if (anArray[i] === layer) {
+          return true
+        }
+      }
 
-            for (i = 0; i < l; i++) {
-                m = layersArray[i];
+      anArray = this._needsRemoving
+      for (i = anArray.length - 1; i >= 0; i--) {
+        if (anArray[i].layer === layer) {
+          return false
+        }
+      }
 
-                //  Group of layers, append children to layersArray and skip.
-                if (m instanceof L.LayerGroup) {
-                    if (originalArray) {
-                        layersArray = layersArray.slice();
-                        originalArray = false;
-                    }
-                    this._extractNonGroupLayers(m, layersArray);
-                    l = layersArray.length;
-                    continue;
-                }
+      return !!(layer.__parent && layer.__parent._group === this) || this._nonPointGroup.hasLayer(layer)
+    },
 
-                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 map
-            this._topClusterLevel._recursivelyAddChildrenToMap(null, this._zoom, this._currentShownBounds);
-
-            return this;
-        },
-
-        // Removes all layers from the MarkerClusterGroup
-        clearLayers: 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 of
-            if (!this._map) {
-                this._needsClustering = [];
-                this._needsRemoving = [];
-                delete this._gridClusters;
-                delete this._gridUnclustered;
-            }
-
-            if (this._noanimationUnspiderfy) {
-                this._noanimationUnspiderfy();
-            }
-
-            // Remove all the visible layers
-            this._featureGroup.clearLayers();
-            this._nonPointGroup.clearLayers();
-
-            this.eachLayer(function(marker) {
-                marker.off(this._childMarkerEventHandlers, this);
-                delete marker.__parent;
-            }, this);
-
-            if (this._map) {
-                // Reset _topClusterLevel and the DistanceGrids
-                this._generateInitialClusters();
-            }
-
-            return this;
-        },
-
-        // Override FeatureGroup.getBounds as it doesn't work
-        getBounds: function() {
-            var bounds = new L.LatLngBounds();
-
-            if (this._topClusterLevel) {
-                bounds.extend(this._topClusterLevel._bounds);
-            }
-
-            for (var i = this._needsClustering.length - 1; i >= 0; i--) {
-                bounds.extend(this._needsClustering[i].getLatLng());
-            }
-
-            bounds.extend(this._nonPointGroup.getBounds());
-
-            return bounds;
-        },
-
-        // Overrides LayerGroup.eachLayer
-        eachLayer: function(method, context) {
-            var markers = 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.getLayers
-        getLayers: function() {
-            var layers = [];
-            this.eachLayer(function(l) {
-                layers.push(l);
-            });
-            return layers;
-        },
-
-        // Overrides LayerGroup.getLayer, WARNING: Really bad performance
-        getLayer: function(id) {
-            var result = null;
-
-            id = parseInt(id, 10);
-
-            this.eachLayer(function(l) {
-                if (L.stamp(l) === id) {
-                    result = l;
-                }
-            });
-
-            return result;
-        },
-
-        // Returns true if the given layer is in this MarkerClusterGroup
-        hasLayer: function(layer) {
-            if (!layer) {
-                return false;
-            }
-
-            var i, anArray = this._needsClustering;
-
-            for (i = anArray.length - 1; i >= 0; i--) {
-                if (anArray[i] === layer) {
-                    return true;
-                }
-            }
-
-            anArray = this._needsRemoving;
-            for (i = anArray.length - 1; i >= 0; i--) {
-                if (anArray[i].layer === layer) {
-                    return false;
-                }
-            }
-
-            return !!(layer.__parent && layer.__parent._group === this) || this._nonPointGroup.hasLayer(layer);
-        },
-
-        // Zoom down to show the given layer (spiderfying if necessary) then calls the callback
-        zoomToShowLayer: function(layer, callback) {
-
-            if (typeof callback !== 'function') {
-                callback = function() {
-                };
-            }
+    // Zoom down to show the given layer (spiderfying if necessary) then calls the callback
+    zoomToShowLayer: function (layer, callback) {
+      if (typeof callback !== 'function') {
+        callback = function () {
+        }
+      }
 
-            var showMarker = function() {
-                if ((layer._icon || layer.__parent._icon) && !this._inZoomAnimation) {
-                    this._map.off('moveend', showMarker, this);
-                    this.off('animationend', showMarker, this);
+      var showMarker = function () {
+        if ((layer._icon || layer.__parent._icon) && !this._inZoomAnimation) {
+          this._map.off('moveend', showMarker, this)
+          this.off('animationend', showMarker, this)
 
-                    if (layer._icon) {
-                        callback();
-                    } else if (layer.__parent._icon) {
-                        this.once('spiderfied', callback, this);
-                        layer.__parent.spiderfy();
-                    }
-                }
-            };
+          if (layer._icon) {
+            callback()
+          } else if (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 return
-                callback();
-            } else if (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 it
-                this._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();
-            }
-        },
+      if (layer._icon && this._map.getBounds().contains(layer.getLatLng())) {
+        // Layer is visible ond on screen, immediate return
+        callback()
+      } else if (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 it
+        this._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.onAdd
-        onAdd: function(map) {
-            this._map = map;
-            var i, l, layer;
+    // Overrides FeatureGroup.onAdd
+    onAdd: function (map) {
+      this._map = map
+      var i, l, layer
 
-            if (!isFinite(this._map.getMaxZoom())) {
-                throw "Map has no maxZoom specified";
-            }
+      if (!isFinite(this._map.getMaxZoom())) {
+          // eslint-disable-next-line no-throw-literal
+        throw 'Map has no maxZoom specified'
+      }
 
-            this._featureGroup.addTo(map);
-            this._nonPointGroup.addTo(map);
+      this._featureGroup.addTo(map)
+      this._nonPointGroup.addTo(map)
 
-            if (!this._gridClusters) {
-                this._generateInitialClusters();
-            }
+      if (!this._gridClusters) {
+        this._generateInitialClusters()
+      }
 
-            this._maxLat = map.options.crs.projection.MAX_LATITUDE;
+      this._maxLat = map.options.crs.projection.MAX_LATITUDE
 
-            // Restore all the positions as they are in the MCG before removing them
-            for (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 positions
-            for (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 = [];
+      // Restore all the positions as they are in the MCG before removing them
+      for (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 positions
+      for (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 bounds
-            this._zoom = Math.round(this._map._zoom);
-            this._currentShownBounds = this._getExpandedVisibleBounds();
+      // Remember the current zoom level and bounds
+      this._zoom = Math.round(this._map._zoom)
+      this._currentShownBounds = this._getExpandedVisibleBounds()
 
-            this._map.on('zoomend', this._zoomEnd, this);
-            this._map.on('moveend', this._moveEnd, this);
+      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();
-            }
+      if (this._spiderfierOnAdd) { // TODO FIXME: Not sure how to have spiderfier add something on here nicely
+        this._spiderfierOnAdd()
+      }
 
-            this._bindEvents();
+      this._bindEvents()
 
-            // Actually add our markers to the map:
-            l = this._needsClustering;
-            this._needsClustering = [];
-            this.addLayers(l, true);
-        },
+      // Actually add our markers to the map:
+      l = this._needsClustering
+      this._needsClustering = []
+      this.addLayers(l, true)
+    },
 
-        // Overrides FeatureGroup.onRemove
-        onRemove: function(map) {
-            map.off('zoomend', this._zoomEnd, this);
-            map.off('moveend', this._moveEnd, this);
+    // Overrides FeatureGroup.onRemove
+    onRemove: function (map) {
+      map.off('zoomend', this._zoomEnd, this)
+      map.off('moveend', this._moveEnd, this)
 
-            this._unbindEvents();
+      this._unbindEvents()
 
-            // In case we are in a cluster animation
-            this._map._mapPane.className = this._map._mapPane.className.replace(' leaflet-cluster-anim', '');
+      // In case we are in a cluster animation
+      this._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 nicely
-                this._spiderfierOnRemove();
-            }
+      if (this._spiderfierOnRemove) { // TODO FIXME: Not sure how to have spiderfier add something on here nicely
+        this._spiderfierOnRemove()
+      }
 
-            delete this._maxLat;
+      delete this._maxLat
 
-            // Clean up all the layers we added to the map
-            this._hideCoverage();
-            this._featureGroup.remove();
-            this._nonPointGroup.remove();
+      // Clean up all the layers we added to the map
+      this._hideCoverage()
+      this._featureGroup.remove()
+      this._nonPointGroup.remove()
 
-            this._featureGroup.clearLayers();
+      this._featureGroup.clearLayers()
 
-            this._map = null;
-        },
+      this._map = null
+    },
 
-        getVisibleParent: function(marker) {
-            var vMarker = marker;
-            while (vMarker && !vMarker._icon) {
-                vMarker = vMarker.__parent;
-            }
-            return vMarker || null;
-        },
+    getVisibleParent: function (marker) {
+      var vMarker = marker
+      while (vMarker && !vMarker._icon) {
+        vMarker = vMarker.__parent
+      }
+      return vMarker || null
+    },
 
-        // 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 true;
-                }
-            }
-        },
+    // 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 true
+        }
+      }
+    },
 
-        /**
+    /**
          * 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,
-                minZoom = Math.floor(this._map.getMinZoom());
+    _removeFromGridUnclustered: function (marker, z) {
+      var map = this._map
+      var gridUnclustered = this._gridUnclustered
+      var minZoom = Math.floor(this._map.getMinZoom())
 
-            for (; z >= minZoom; z--) {
-                if (!gridUnclustered[z].removeObject(marker, map.project(marker.getLatLng(), z))) {
-                    break;
-                }
+      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) {
+        var isPopupOpen = 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) {
+      var dragStart = e.target.__dragStart
+      delete e.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) {
+      var gridClusters = this._gridClusters
+      var gridUnclustered = this._gridUnclustered
+      var fg = this._featureGroup
+      var map = this._map
+      var minZoom = Math.floor(this._map.getMinZoom())
+
+      // Remove the marker from distance clusters it might be in
+      if (removeFromDistanceGrid) {
+        this._removeFromGridUnclustered(marker, this._maxZoom)
+      }
+
+      // Work our way up the clusters removing them as we go if required
+      var cluster = marker.__parent
+      var markers = cluster._markers
+      var otherMarker
+
+      // Remove the marker from the immediate parents marker list
+      this._arraySplice(markers, marker)
+
+      while (cluster) {
+        cluster._childCount--
+        cluster._boundsNeedUpdate = true
+
+        if (cluster._zoom < minZoom) {
+          // 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
+            fg.removeLayer(cluster)
+            if (!dontUpdateMap) {
+              fg.addLayer(otherMarker)
             }
-        },
+          }
+        } else {
+          cluster._iconNeedsUpdate = true
+        }
 
-        _childMarkerDragStart: function(e) {
-            e.target.__dragStart = e.target._latlng;
-        },
+        cluster = cluster.__parent
+      }
 
-        _childMarkerMoved: function(e) {
-            if (!this._ignoreMove && !e.target.__dragStart) {
-                var isPopupOpen = e.target._popup && e.target._popup.isOpen();
+      delete marker.__parent
+    },
 
-                this._moveChild(e.target, e.oldLatLng, e.latlng);
+    _isOrIsParent: function (el, oel) {
+      while (oel) {
+        if (el === oel) {
+          return true
+        }
+        oel = oel.parentNode
+      }
+      return false
+    },
 
-                if (isPopupOpen) {
-                    e.target.openPopup();
-                }
-            }
-        },
+    // Override L.Evented.fire
+    fire: function (type, data, propagate) {
+      if (data && data.layer instanceof L.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
+      }
 
-        _moveChild: function(layer, from, to) {
-            layer._latlng = from;
-            this.removeLayer(layer);
+      L.FeatureGroup.prototype.fire.call(this, type, data, propagate)
+    },
 
-            layer._latlng = to;
-            this.addLayer(layer);
-        },
+    // Override L.Evented.listens
+    listens: function (type, propagate) {
+      return L.FeatureGroup.prototype.listens.call(this, type, propagate) || L.FeatureGroup.prototype.listens.call(this, 'cluster' + type, propagate)
+    },
 
-        _childMarkerDragEnd: function(e) {
-            var dragStart = e.target.__dragStart;
-            delete e.target.__dragStart;
-            if (dragStart) {
-                this._moveChild(e.target, dragStart, e.target._latlng);
-            }
-        },
+    // Default functionality
+    _defaultIconCreateFunction: function (cluster) {
+      var childCount = cluster.getChildCount()
 
+      var c = ' marker-cluster-'
+      if (childCount < 10) {
+        c += 'small'
+      } else if (childCount < 100) {
+        c += 'medium'
+      } else {
+        c += 'large'
+      }
 
-        // 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) {
-            var gridClusters = this._gridClusters,
-                gridUnclustered = this._gridUnclustered,
-                fg = this._featureGroup,
-                map = this._map,
-                minZoom = Math.floor(this._map.getMinZoom());
+      return new L.DivIcon({
+        html: '<div><span>' + childCount + '</span></div>',
+        className: 'marker-cluster' + c,
+        iconSize: new L.Point(40, 40)
+      })
+    },
 
-            // Remove the marker from distance clusters it might be in
-            if (removeFromDistanceGrid) {
-                this._removeFromGridUnclustered(marker, this._maxZoom);
-            }
+    _bindEvents: function () {
+      var map = this._map
+      var spiderfyOnMaxZoom = this.options.spiderfyOnMaxZoom
+      var showCoverageOnHover = this.options.showCoverageOnHover
+      var zoomToBoundsOnClick = this.options.zoomToBoundsOnClick
 
-            // Work our way up the clusters removing them as we go if required
-            var cluster = marker.__parent,
-                markers = cluster._markers,
-                otherMarker;
+      // Zoom on cluster click or spiderfy if we are at the lowest level
+      if (spiderfyOnMaxZoom || zoomToBoundsOnClick) {
+        this.on('clusterclick', this._zoomOrSpiderfy, this)
+      }
 
-            // Remove the marker from the immediate parents marker list
-            this._arraySplice(markers, marker);
+      // Show convex hull (boundary) polygon on mouse over
+      if (showCoverageOnHover) {
+        this.on('clustermouseover', this._showCoverage, this)
+        this.on('clustermouseout', this._hideCoverage, this)
+        map.on('zoomend', this._hideCoverage, this)
+      }
+    },
 
-            while (cluster) {
-                cluster._childCount--;
-                cluster._boundsNeedUpdate = true;
+    _zoomOrSpiderfy: function (e) {
+      var cluster = e.layer
+      var bottomCluster = cluster
 
-                if (cluster._zoom < minZoom) {
-                    // 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];
+      while (bottomCluster._childClusters.length === 1) {
+        bottomCluster = bottomCluster._childClusters[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
-                        fg.removeLayer(cluster);
-                        if (!dontUpdateMap) {
-                            fg.addLayer(otherMarker);
-                        }
-                    }
-                } else {
-                    cluster._iconNeedsUpdate = true;
-                }
-
-                cluster = cluster.__parent;
-            }
-
-            delete marker.__parent;
-        },
-
-        _isOrIsParent: function(el, oel) {
-            while (oel) {
-                if (el === oel) {
-                    return true;
-                }
-                oel = oel.parentNode;
-            }
-            return false;
-        },
-
-        // Override L.Evented.fire
-        fire: function(type, data, propagate) {
-            if (data && data.layer instanceof L.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.listens
-        listens: function(type, propagate) {
-            return L.FeatureGroup.prototype.listens.call(this, type, propagate) || L.FeatureGroup.prototype.listens.call(this, 'cluster' + type, propagate);
-        },
-
-        // Default functionality
-        _defaultIconCreateFunction: function(cluster) {
-            var childCount = cluster.getChildCount();
-
-            var c = ' marker-cluster-';
-            if (childCount < 10) {
-                c += 'small';
-            } else if (childCount < 100) {
-                c += 'medium';
-            } else {
-                c += 'large';
-            }
-
-            return new L.DivIcon({
-                html: '<div><span>' + childCount + '</span></div>',
-                className: 'marker-cluster' + c,
-                iconSize: new L.Point(40, 40)
-            });
-        },
-
-        _bindEvents: function() {
-            var 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', this._zoomOrSpiderfy, this);
-            }
-
-            // Show convex hull (boundary) polygon on mouse over
-            if (showCoverageOnHover) {
-                this.on('clustermouseover', this._showCoverage, this);
-                this.on('clustermouseout', this._hideCoverage, this);
-                map.on('zoomend', this._hideCoverage, this);
-            }
-        },
-
-        _zoomOrSpiderfy: function(e) {
-            var cluster = e.layer,
-                bottomCluster = cluster;
-
-            while (bottomCluster._childClusters.length === 1) {
-                bottomCluster = bottomCluster._childClusters[0];
-            }
-
-            if (bottomCluster._zoom === this._maxZoom &&
+      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()
+      } else if (this.options.zoomToBoundsOnClick) {
+        cluster.zoomToBounds()
+      }
 
-                //  All child markers are contained in a single cluster from this._maxZoom to this cluster.
-                cluster.spiderfy();
-            } else if (this.options.zoomToBoundsOnClick) {
-                cluster.zoomToBounds();
-            }
+      //  Focus the map again for keyboard users.
+      if (e.originalEvent && e.originalEvent.keyCode === 13) {
+        this._map._container.focus()
+      }
+    },
 
-            //  Focus the map again for keyboard users.
-            if (e.originalEvent && e.originalEvent.keyCode === 13) {
-                this._map._container.focus();
-            }
-        },
+    _showCoverage: function (e) {
+      var map = this._map
+      if (this._inZoomAnimation) {
+        return
+      }
+      if (this._shownPolygon) {
+        map.removeLayer(this._shownPolygon)
+      }
+      if (e.layer.getChildCount() > 2 && e.layer !== this._spiderfied) {
+        this._shownPolygon = new L.Polygon(e.layer.getConvexHull(), this.options.polygonOptions)
+        map.addLayer(this._shownPolygon)
+      }
+    },
 
-        _showCoverage: function(e) {
-            var map = this._map;
-            if (this._inZoomAnimation) {
-                return;
-            }
-            if (this._shownPolygon) {
-                map.removeLayer(this._shownPolygon);
-            }
-            if (e.layer.getChildCount() > 2 && e.layer !== this._spiderfied) {
-                this._shownPolygon = new L.Polygon(e.layer.getConvexHull(), this.options.polygonOptions);
-                map.addLayer(this._shownPolygon);
-            }
-        },
+    _hideCoverage: function () {
+      if (this._shownPolygon) {
+        this._map.removeLayer(this._shownPolygon)
+        this._shownPolygon = null
+      }
+    },
 
-        _hideCoverage: function() {
-            if (this._shownPolygon) {
-                this._map.removeLayer(this._shownPolygon);
-                this._shownPolygon = null;
-            }
-        },
+    _unbindEvents: function () {
+      var spiderfyOnMaxZoom = this.options.spiderfyOnMaxZoom
+      var showCoverageOnHover = this.options.showCoverageOnHover
+      var zoomToBoundsOnClick = this.options.zoomToBoundsOnClick
+      var map = this._map
 
-        _unbindEvents: function() {
-            var spiderfyOnMaxZoom = 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)
+      }
+    },
 
-            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 handler
+        return
+      }
+      this._mergeSplitClusters()
 
-        _zoomEnd: function() {
-            if (!this._map) { // May have been removed from the map by a zoomEnd handler
-                return;
-            }
-            this._mergeSplitClusters();
+      this._zoom = Math.round(this._map._zoom)
+      this._currentShownBounds = this._getExpandedVisibleBounds()
+    },
 
-            this._zoom = Math.round(this._map._zoom);
-            this._currentShownBounds = this._getExpandedVisibleBounds();
-        },
+    _moveEnd: function () {
+      if (this._inZoomAnimation) {
+        return
+      }
 
-        _moveEnd: function() {
-            if (this._inZoomAnimation) {
-                return;
-            }
+      var newBounds = this._getExpandedVisibleBounds()
 
-            var newBounds = 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._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
+    },
 
-            this._currentShownBounds = newBounds;
-            return;
-        },
+    _generateInitialClusters: function () {
+      var maxZoom = Math.ceil(this._map.getMaxZoom())
+      var minZoom = Math.floor(this._map.getMinZoom())
+      var radius = this.options.maxClusterRadius
+      var radiusFn = radius
 
-        _generateInitialClusters: function() {
-            var maxZoom = 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 (typeof radius !== 'function') {
+        radiusFn = function () {
+          return 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 (typeof radius !== "function") {
-                radiusFn = function() {
-                    return radius;
-                };
-            }
+      if (this.options.disableClusteringAtZoom !== null) {
+        maxZoom = this.options.disableClusteringAtZoom - 1
+      }
+      this._maxZoom = maxZoom
+      this._gridClusters = {}
+      this._gridUnclustered = {}
 
-            if (this.options.disableClusteringAtZoom !== null) {
-                maxZoom = this.options.disableClusteringAtZoom - 1;
-            }
-            this._maxZoom = maxZoom;
-            this._gridClusters = {};
-            this._gridUnclustered = {};
+      // Set up DistanceGrids for each zoom
+      for (var zoom = maxZoom; zoom >= minZoom; zoom--) {
+        this._gridClusters[zoom] = new L.DistanceGrid(radiusFn(zoom))
+        this._gridUnclustered[zoom] = new L.DistanceGrid(radiusFn(zoom))
+      }
 
-            // Set up DistanceGrids for each zoom
-            for (var zoom = maxZoom; zoom >= minZoom; zoom--) {
-                this._gridClusters[zoom] = new L.DistanceGrid(radiusFn(zoom));
-                this._gridUnclustered[zoom] = new L.DistanceGrid(radiusFn(zoom));
-            }
+      //  Instantiate the appropriate L.MarkerCluster class (animated or not).
+      this._topClusterLevel = new this._markerCluster(this, minZoom - 1)
+    },
 
-            //  Instantiate the appropriate L.MarkerCluster class (animated or not).
-            this._topClusterLevel = new this._markerCluster(this, minZoom - 1);
-        },
+    // Zoom: Zoom to start adding at (Pass this._maxZoom to start at the bottom)
+    _addLayer: function (layer, zoom) {
+      var gridClusters = this._gridClusters
+      var gridUnclustered = this._gridUnclustered
+      var minZoom = Math.floor(this._map.getMinZoom())
+      var markerPoint; var z
 
-        // 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,
-                minZoom = Math.floor(this._map.getMinZoom()),
-                markerPoint, z;
+      if (this.options.singleMarkerMode) {
+        this._overrideMarkerIcon(layer)
+      }
 
-            if (this.options.singleMarkerMode) {
-                this._overrideMarkerIcon(layer);
-            }
+      layer.on(this._childMarkerEventHandlers, this)
 
-            layer.on(this._childMarkerEventHandlers, this);
+      // Find the lowest zoom level to slot this one in
+      for (; zoom >= minZoom; zoom--) {
+        markerPoint = this._map.project(layer.getLatLng(), zoom) //  calculate pixel position
 
-            // Find the lowest zoom level to slot this one in
-            for (; zoom >= minZoom; zoom--) {
-                markerPoint = this._map.project(layer.getLatLng(), zoom); //  calculate pixel position
+        // Try find a cluster close by
+        var closest = gridClusters[zoom].getNearObject(markerPoint)
+        if (closest) {
+          closest._addChild(layer)
+          layer.__parent = closest
+          return
+        }
 
-                // Try find a cluster close by
-                var closest = gridClusters[zoom].getNearObject(markerPoint);
-                if (closest) {
-                    closest._addChild(layer);
-                    layer.__parent = closest;
-                    return;
-                }
+        // Try find a marker close by to form a new cluster with
+        closest = gridUnclustered[zoom].getNearObject(markerPoint)
+        if (closest) {
+          var parent = closest.__parent
+          if (parent) {
+            this._removeLayer(closest, false)
+          }
 
-                // Try find a marker close by to form a new cluster with
-                closest = gridUnclustered[zoom].getNearObject(markerPoint);
-                if (closest) {
-                    var parent = closest.__parent;
-                    if (parent) {
-                        this._removeLayer(closest, false);
-                    }
+          // Create new cluster with these 2 in it
 
-                    // Create new cluster with these 2 in it
+          var newCluster = new this._markerCluster(this, zoom, closest, layer)
+          gridClusters[zoom].addObject(newCluster, this._map.project(newCluster._cLatLng, zoom))
+          closest.__parent = newCluster
+          layer.__parent = newCluster
 
-                    var newCluster = new this._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 exist
+          var lastParent = newCluster
+          for (z = zoom - 1; z > parent._zoom; z--) {
+            lastParent = new this._markerCluster(this, z, lastParent)
+            gridClusters[z].addObject(lastParent, this._map.project(closest.getLatLng(), z))
+          }
+          parent._addChild(lastParent)
 
-                    // First create any new intermediate parent clusters that don't exist
-                    var lastParent = newCluster;
-                    for (z = zoom - 1; z > parent._zoom; z--) {
-                        lastParent = new this._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 newCluster
+          this._removeFromGridUnclustered(closest, zoom)
 
-                    // Remove closest from this zoom level and any above that it is in, replace with newCluster
-                    this._removeFromGridUnclustered(closest, zoom);
+          return
+        }
 
-                    return;
-                }
+        // Didn't manage to cluster in at this zoom, record us as a marker here and continue upwards
+        gridUnclustered[zoom].addObject(layer, markerPoint)
+      }
 
-                // Didn't manage to cluster in at this zoom, record us as a marker here and continue upwards
-                gridUnclustered[zoom].addObject(layer, markerPoint);
-            }
+      // Didn't get in anything, add us to the top
+      this._topClusterLevel._addChild(layer)
+      layer.__parent = this._topClusterLevel
+    },
 
-            // Didn't get in anything, add us to the top
-            this._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 (c instanceof L.MarkerCluster && c._iconNeedsUpdate) {
-                    c._updateIcon();
-                }
-            });
-        },
+    _refreshClustersIcons: function () {
+      this._featureGroup.eachLayer(function (c) {
+        if (c instanceof L.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 (var i = 0; i < this._queue.length; i++) {
-                this._queue[i].call(this);
-            }
-            this._queue.length = 0;
-            clearTimeout(this._queueTimeout);
-            this._queueTimeout = null;
-        },
+    // 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 (var i = 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() {
-            var mapZoom = Math.round(this._map._zoom);
+    // Merge and split any existing clusters that are too big or small
+    _mergeSplitClusters: function () {
+      var mapZoom = Math.round(this._map._zoom)
 
-            // In case we are starting to split before the animation finished
-            this._processQueue();
+      // In case we are starting to split before the animation finished
+      this._processQueue()
 
-            if (this._zoom < mapZoom && this._currentShownBounds.intersects(this._getExpandedVisibleBounds())) { // Zoom in, split
-                this._animationStart();
-                // Remove clusters now off screen
-                this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds, Math.floor(this._map.getMinZoom()), this._zoom, this._getExpandedVisibleBounds());
+      if (this._zoom < mapZoom && this._currentShownBounds.intersects(this._getExpandedVisibleBounds())) { // Zoom in, split
+        this._animationStart()
+        // Remove clusters now off screen
+        this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds, Math.floor(this._map.getMinZoom()), this._zoom, this._getExpandedVisibleBounds())
 
-                this._animationZoomIn(this._zoom, mapZoom);
+        this._animationZoomIn(this._zoom, mapZoom)
+      } else if (this._zoom > mapZoom) { // Zoom out, merge
+        this._animationStart()
 
-            } else if (this._zoom > mapZoom) { // Zoom out, merge
-                this._animationStart();
+        this._animationZoomOut(this._zoom, mapZoom)
+      } else {
+        this._moveEnd()
+      }
+    },
 
-                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) {
+        return this._mapBoundsInfinite
+      } else if (L.Browser.mobile) {
+        return this._checkBoundsMaxLat(this._map.getBounds())
+      }
 
-        // 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) {
-                return this._mapBoundsInfinite
-            } else if (L.Browser.mobile) {
-                return this._checkBoundsMaxLat(this._map.getBounds())
-            }
+      return this._checkBoundsMaxLat(this._map.getBounds().pad(1)) //  Padding expands the bounds by its own dimensions but scaled with the given factor.
+    },
 
-            return this._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
@@ -1099,691 +1090,689 @@
          * @returns {L.LatLngBounds}
          * @private
          */
-        _checkBoundsMaxLat: function(bounds) {
-            var maxLat = this._maxLat
+    _checkBoundsMaxLat: function (bounds) {
+      var maxLat = this._maxLat
 
-            if (maxLat !== undefined) {
-                if (bounds.getNorth() >= maxLat) {
-                    bounds._northEast.lat = Infinity
-                }
-                if (bounds.getSouth() <= -maxLat) {
-                    bounds._southWest.lat = -Infinity
-                }
-            }
+      if (maxLat !== undefined) {
+        if (bounds.getNorth() >= maxLat) {
+          bounds._northEast.lat = Infinity
+        }
+        if (bounds.getSouth() <= -maxLat) {
+          bounds._southWest.lat = -Infinity
+        }
+      }
 
-            return bounds
-        },
+      return bounds
+    },
 
-        // Shared animation code
-        _animationAddLayerNonAnimated: function(layer, newCluster) {
-            if (newCluster === layer) {
-                this._featureGroup.addLayer(layer)
-            } else if (newCluster._childCount === 2) {
-                newCluster._addToMap()
+    // Shared animation code
+    _animationAddLayerNonAnimated: function (layer, newCluster) {
+      if (newCluster === layer) {
+        this._featureGroup.addLayer(layer)
+      } else if (newCluster._childCount === 2) {
+        newCluster._addToMap()
 
-                var markers = newCluster.getAllChildMarkers()
-                this._featureGroup.removeLayer(markers[0])
-                this._featureGroup.removeLayer(markers[1])
-            } else {
-                newCluster._updateIcon()
-            }
-        },
+        var markers = 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) {
-            var layers = group.getLayers(),
-                i = 0,
-                layer
+    _extractNonGroupLayers: function (group, output) {
+      var layers = group.getLayers()
+      var i = 0
+      var layer
 
-            output = output || []
+      output = output || []
 
-            for (; i < layers.length; i++) {
-                layer = layers[i]
+      for (; i < layers.length; i++) {
+        layer = layers[i]
 
-                if (layer instanceof L.LayerGroup) {
-                    this._extractNonGroupLayers(layer, output)
-                    continue
-                }
+        if (layer instanceof L.LayerGroup) {
+          this._extractNonGroupLayers(layer, output)
+          continue
+        }
 
-                output.push(layer)
-            }
+        output.push(layer)
+      }
 
-            return output
-        },
+      return output
+    },
 
-        /**
+    /**
          * 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) {
-            var icon = layer.options.icon = this.options.iconCreateFunction({
-                getChildCount: function() {
-                    return 1
-                },
-                getAllChildMarkers: function() {
-                    return [layer]
-                }
+    _overrideMarkerIcon: function (layer) {
+      var icon = layer.options.icon = this.options.iconCreateFunction({
+        getChildCount: function () {
+          return 1
+        },
+        getAllChildMarkers: function () {
+          return [layer]
+        }
+      })
+
+      return icon
+    }
+  })
+
+  //  Constant bounds used in case option "removeOutsideVisibleBounds" is set to false.
+  L.MarkerClusterGroup.include({
+    _mapBoundsInfinite: new L.LatLngBounds(new L.LatLng(-Infinity, -Infinity), new L.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) {
+        var bounds = this._getExpandedVisibleBounds()
+        var fg = this._featureGroup
+        var minZoom = Math.floor(this._map.getMinZoom())
+        var i
+
+        this._ignoreMove = true
+
+        // Add all children of current clusters to map and remove those clusters from map
+        this._topClusterLevel._recursively(bounds, previousZoomLevel, minZoom, function (c) {
+          var startPos = c._latlng
+          var markers = c._markers
+          var m
+
+          if (!bounds.contains(startPos)) {
+            startPos = null
+          }
+
+          if (c._isSingleParent() && previousZoomLevel + 1 === newZoomLevel) { // Immediately add the new child and remove us
+            fg.removeLayer(c)
+            c._recursivelyAddChildrenToMap(null, newZoomLevel, bounds)
+          } else {
+            // Fade out old cluster
+            c.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 opacities
+        this._topClusterLevel._recursivelyBecomeVisible(bounds, newZoomLevel)
+        // TODO Maybe? Update markers in _recursivelyBecomeVisible
+        fg.eachLayer(function (n) {
+          if (!(n instanceof L.MarkerCluster) && n._icon) {
+            n.clusterShow()
+          }
+        })
+
+        // update the positions of the just added clusters/markers
+        this._topClusterLevel._recursively(bounds, previousZoomLevel, newZoomLevel, function (c) {
+          c._recursivelyRestoreChildPositions(newZoomLevel)
+        })
+
+        this._ignoreMove = false
+
+        // Remove the old clusters and close the zoom animation
+        this._enqueue(function () {
+          // update the positions of the just added clusters/markers
+          this._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 now
+        this._topClusterLevel._recursivelyAddChildrenToMap(null, newZoomLevel, this._getExpandedVisibleBounds())
+        // Remove markers that were on the map before but won't be now
+        this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds, Math.floor(this._map.getMinZoom()), previousZoomLevel, this._getExpandedVisibleBounds())
+      },
+
+      _animationAddLayer: function (layer, newCluster) {
+        var me = this
+        var fg = this._featureGroup
+
+        fg.addLayer(layer)
+        if (newCluster !== layer) {
+          if (newCluster._childCount > 2) { // Was already a cluster
+            newCluster._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 cluster
+            this._forceLayout()
 
-            return icon
+            me._animationStart()
+            me._animationZoomOutSingle(newCluster, this._map.getMaxZoom(), this._zoom)
+          }
         }
-    })
+      }
+    },
 
-//  Constant bounds used in case option "removeOutsideVisibleBounds" is set to false.
-    L.MarkerClusterGroup.include({
-        _mapBoundsInfinite: new L.LatLngBounds(new L.LatLng(-Infinity, -Infinity), new L.LatLng(Infinity, Infinity))
-    })
+    //  Private methods for animated versions.
+    _animationZoomOutSingle: function (cluster, previousZoomLevel, newZoomLevel) {
+      var bounds = this._getExpandedVisibleBounds()
+      var minZoom = Math.floor(this._map.getMinZoom())
 
-    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())
+      // Animate all of the markers in the clusters to move to their cluster center point
+      cluster._recursivelyAnimateChildrenInAndAddSelfToMap(bounds, minZoom, previousZoomLevel + 1, newZoomLevel)
 
-                // 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())
+      var me = this
 
-                // 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)
-            }
-        },
+      // Update the opacity (If we immediately set it they won't animate)
+      this._forceLayout()
+      cluster._recursivelyBecomeVisible(bounds, newZoomLevel)
 
-        _withAnimation: {
-            // Animated versions here
-            _animationStart: function() {
-                this._map._mapPane.className += ' leaflet-cluster-anim'
-                this._inZoomAnimation++
-            },
-
-            _animationZoomIn: function(previousZoomLevel, newZoomLevel) {
-                var bounds = 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 map
-                this._topClusterLevel._recursively(bounds, previousZoomLevel, minZoom, function(c) {
-                    var startPos = 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 us
-                        fg.removeLayer(c)
-                        c._recursivelyAddChildrenToMap(null, newZoomLevel, bounds)
-                    } else {
-                        // Fade out old cluster
-                        c.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 opacities
-                this._topClusterLevel._recursivelyBecomeVisible(bounds, newZoomLevel);
-                // TODO Maybe? Update markers in _recursivelyBecomeVisible
-                fg.eachLayer(function(n) {
-                    if (!(n instanceof L.MarkerCluster) && n._icon) {
-                        n.clusterShow()
-                    }
-                });
-
-                // update the positions of the just added clusters/markers
-                this._topClusterLevel._recursively(bounds, previousZoomLevel, newZoomLevel, function(c) {
-                    c._recursivelyRestoreChildPositions(newZoomLevel);
-                });
-
-                this._ignoreMove = false;
-
-                // Remove the old clusters and close the zoom animation
-                this._enqueue(function() {
-                    // update the positions of the just added clusters/markers
-                    this._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 now
-                this._topClusterLevel._recursivelyAddChildrenToMap(null, newZoomLevel, this._getExpandedVisibleBounds())
-                // Remove markers that were on the map before but won't be now
-                this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds, Math.floor(this._map.getMinZoom()), previousZoomLevel, this._getExpandedVisibleBounds());
-            },
-
-            _animationAddLayer: function(layer, newCluster) {
-                var me = this,
-                    fg = this._featureGroup
-
-                fg.addLayer(layer)
-                if (newCluster !== layer) {
-                    if (newCluster._childCount > 2) { // Was already a cluster
-                        newCluster._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 cluster
-                        this._forceLayout()
-
-                        me._animationStart()
-                        me._animationZoomOutSingle(newCluster, this._map.getMaxZoom(), this._zoom)
-                    }
-                }
-            }
-        },
-
-        //  Private methods for animated versions.
-        _animationZoomOutSingle: function(cluster, previousZoomLevel, newZoomLevel) {
-            var bounds = this._getExpandedVisibleBounds(),
-                minZoom = Math.floor(this._map.getMinZoom())
-
-            // Animate all of the markers in the clusters to move to their cluster center point
-            cluster._recursivelyAnimateChildrenInAndAddSelfToMap(bounds, minZoom, previousZoomLevel + 1, newZoomLevel)
-
-            var me = 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 up
-            this._enqueue(function() {
-                // This cluster stopped being a cluster before the timeout fired
-                if (cluster._childCount === 1) {
-                    var m = 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 it
-                    this._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 working
-
-            L.Util.falseFn(document.body.offsetWidth)
+      // TODO: Maybe use the transition timing stuff to make this more reliable
+      // When the animations are done, tidy up
+      this._enqueue(function () {
+        // This cluster stopped being a cluster before the timeout fired
+        if (cluster._childCount === 1) {
+          var m = 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 it
+          this._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()
+      })
+    },
 
-    L.markerClusterGroup = function(options) {
-        return new L.MarkerClusterGroup(options)
-    };
+    _animationEnd: function () {
+      if (this._map) {
+        this._map._mapPane.className = this._map._mapPane.className.replace(' leaflet-cluster-anim', '')
+      }
+      this._inZoomAnimation--
+      this.fire('animationend')
+    },
 
-    var MarkerCluster = L.MarkerCluster = L.Marker.extend({
-        options: L.Icon.prototype.options,
+    // 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 working
 
-        initialize: function(group, zoom, a, b) {
-            L.Marker.prototype.initialize.call(this, a ? (a._cLatLng || a.getLatLng()) : new L.LatLng(0, 0),
-                { icon: this, pane: group.options.clusterPane })
+      L.Util.falseFn(document.body.offsetWidth)
+    }
+  })
 
-            this._group = group
-            this._zoom = zoom
+  L.markerClusterGroup = function (options) {
+    return new L.MarkerClusterGroup(options)
+  }
 
-            this._markers = []
-            this._childClusters = []
-            this._childCount = 0
-            this._iconNeedsUpdate = true
-            this._boundsNeedUpdate = true
+  var MarkerCluster = L.MarkerCluster = L.Marker.extend({
+    options: L.Icon.prototype.options,
 
-            this._bounds = new L.LatLngBounds()
+    initialize: function (group, zoom, a, b) {
+      L.Marker.prototype.initialize.call(this, a ? (a._cLatLng || a.getLatLng()) : new L.LatLng(0, 0),
+        { icon: this, pane: group.options.clusterPane })
 
-            if (a) {
-                this._addChild(a);
-            }
-            if (b) {
-                this._addChild(b);
-            }
-        },
+      this._group = group
+      this._zoom = zoom
 
-        // Recursively retrieve all child markers of this cluster
-        getAllChildMarkers: function(storageArray, ignoreDraggedMarker) {
-            storageArray = storageArray || []
+      this._markers = []
+      this._childClusters = []
+      this._childCount = 0
+      this._iconNeedsUpdate = true
+      this._boundsNeedUpdate = true
 
-            for (var i = this._childClusters.length - 1; i >= 0; i--) {
-                this._childClusters[i].getAllChildMarkers(storageArray)
-            }
+      this._bounds = new L.LatLngBounds()
 
-            for (var j = this._markers.length - 1; j >= 0; j--) {
-                if (ignoreDraggedMarker && this._markers[j].__dragStart) {
-                    continue
-                }
-                storageArray.push(this._markers[j])
-            }
+      if (a) {
+        this._addChild(a)
+      }
+      if (b) {
+        this._addChild(b)
+      }
+    },
 
-            return storageArray
-        },
+    // Recursively retrieve all child markers of this cluster
+    getAllChildMarkers: function (storageArray, ignoreDraggedMarker) {
+      storageArray = storageArray || []
 
-        // Returns the count of how many child markers we have
-        getChildCount: function() {
-            return this._childCount;
-        },
+      for (var i = this._childClusters.length - 1; i >= 0; i--) {
+        this._childClusters[i].getAllChildMarkers(storageArray)
+      }
 
-        // Zoom to the minimum of showing all of the child markers, or the extents of this cluster
-        zoomToBounds: function(fitBoundsOptions) {
-            var childClusters = this._childClusters.slice(),
-                map = this._group._map,
-                boundsZoom = map.getBoundsZoom(this._bounds),
-                zoom = this._zoom + 1,
-                mapZoom = map.getZoom(),
-                i;
+      for (var j = this._markers.length - 1; j >= 0; j--) {
+        if (ignoreDraggedMarker && this._markers[j].__dragStart) {
+          continue
+        }
+        storageArray.push(this._markers[j])
+      }
 
-            // calculate how far we need to zoom down to see all of the markers
-            while (childClusters.length > 0 && boundsZoom > zoom) {
-                zoom++;
-                var newClusters = [];
-                for (i = 0; i < childClusters.length; i++) {
-                    newClusters = newClusters.concat(childClusters[i]._childClusters);
-                }
-                childClusters = newClusters;
-            }
+      return storageArray
+    },
 
-            if (boundsZoom > zoom) {
-                this._group._map.setView(this._latlng, zoom);
-            } else if (boundsZoom <= mapZoom) { // If fitBounds wouldn't zoom us down, zoom us down instead
-                this._group._map.setView(this._latlng, mapZoom + 1);
-            } else {
-                this._group._map.fitBounds(this._bounds, fitBoundsOptions)
-            }
-        },
+    // Returns the count of how many child markers we have
+    getChildCount: function () {
+      return this._childCount
+    },
 
-        getBounds: function() {
-            var bounds = new L.LatLngBounds()
-            bounds.extend(this._bounds)
-            return bounds
-        },
+    // Zoom to the minimum of showing all of the child markers, or the extents of this cluster
+    zoomToBounds: function (fitBoundsOptions) {
+      var childClusters = this._childClusters.slice()
+      var map = this._group._map
+      var boundsZoom = map.getBoundsZoom(this._bounds)
+      var zoom = this._zoom + 1
+      var mapZoom = map.getZoom()
+      var i
 
-        _updateIcon: function() {
-            this._iconNeedsUpdate = true
-            if (this._icon) {
-                this.setIcon(this)
-            }
-        },
+      // calculate how far we need to zoom down to see all of the markers
+      while (childClusters.length > 0 && boundsZoom > zoom) {
+        zoom++
+        var newClusters = []
+        for (i = 0; i < childClusters.length; i++) {
+          newClusters = newClusters.concat(childClusters[i]._childClusters)
+        }
+        childClusters = newClusters
+      }
 
-        //  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()
-        },
+      if (boundsZoom > zoom) {
+        this._group._map.setView(this._latlng, zoom)
+      } else if (boundsZoom <= mapZoom) { // If fitBounds wouldn't zoom us down, zoom us down instead
+        this._group._map.setView(this._latlng, mapZoom + 1)
+      } else {
+        this._group._map.fitBounds(this._bounds, fitBoundsOptions)
+      }
+    },
 
-        _addChild: function(new1, isNotificationFromChild) {
-            this._iconNeedsUpdate = true
+    getBounds: function () {
+      var bounds = new L.LatLngBounds()
+      bounds.extend(this._bounds)
+      return bounds
+    },
 
-            this._boundsNeedUpdate = true
-            this._setClusterCenter(new1)
+    _updateIcon: function () {
+      this._iconNeedsUpdate = true
+      if (this._icon) {
+        this.setIcon(this)
+      }
+    },
 
-            if (new1 instanceof L.MarkerCluster) {
-                if (!isNotificationFromChild) {
-                    this._childClusters.push(new1)
-                    new1.__parent = this
-                }
-                this._childCount += new1._childCount
-            } else {
-                if (!isNotificationFromChild) {
-                    this._markers.push(new1)
-                }
-                this._childCount++
-            }
+    //  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()
+    },
 
-            if (this.__parent) {
-                this.__parent._addChild(new1, true)
-            }
-        },
+    _addChild: function (new1, isNotificationFromChild) {
+      this._iconNeedsUpdate = true
 
-        /**
+      this._boundsNeedUpdate = true
+      this._setClusterCenter(new1)
+
+      if (new1 instanceof L.MarkerCluster) {
+        if (!isNotificationFromChild) {
+          this._childClusters.push(new1)
+          new1.__parent = this
+        }
+        this._childCount += new1._childCount
+      } else {
+        if (!isNotificationFromChild) {
+          this._markers.push(new1)
+        }
+        this._childCount++
+      }
+
+      if (this.__parent) {
+        this.__parent._addChild(new1, true)
+      }
+    },
+
+    /**
          * 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
-            }
-        },
+    _setClusterCenter: function (child) {
+      if (!this._cLatLng) {
+        //  when clustering, take position of the first point as the cluster center
+        this._cLatLng = child._cLatLng || child._latlng
+      }
+    },
 
-        /**
+    /**
          * Assigns impossible bounding values so that the next extend entirely determines the new bounds.
          * This method avoids having to trash the previous L.LatLngBounds object and to create a new one, which is much slower for this class.
          * As long as the bounds are not extended, most other methods would probably fail, as they would with bounds initialized but not extended.
          * @private
          */
-        _resetBounds: function() {
-            var bounds = this._bounds
+    _resetBounds: function () {
+      var bounds = this._bounds
 
-            if (bounds._southWest) {
-                bounds._southWest.lat = Infinity
-                bounds._southWest.lng = Infinity
-            }
-            if (bounds._northEast) {
-                bounds._northEast.lat = -Infinity
-                bounds._northEast.lng = -Infinity
-            }
-        },
+      if (bounds._southWest) {
+        bounds._southWest.lat = Infinity
+        bounds._southWest.lng = Infinity
+      }
+      if (bounds._northEast) {
+        bounds._northEast.lat = -Infinity
+        bounds._northEast.lng = -Infinity
+      }
+    },
 
-        _recalculateBounds: function() {
-            var markers = this._markers,
-                childClusters = this._childClusters,
-                latSum = 0,
-                lngSum = 0,
-                totalCount = this._childCount,
-                i, child, childLatLng, childCount
+    _recalculateBounds: function () {
+      var markers = this._markers
+      var childClusters = this._childClusters
+      var latSum = 0
+      var lngSum = 0
+      var totalCount = this._childCount
+      var i; var child; var childLatLng; var childCount
 
-            //  Case where all markers are removed from the map and we are left with just an empty _topClusterLevel.
-            if (totalCount === 0) {
-                return
-            }
+      //  Case where all markers are removed from the map and we are left with just an empty _topClusterLevel.
+      if (totalCount === 0) {
+        return
+      }
 
-            //  Reset rather than creating a new object, for performance.
-            this._resetBounds()
+      //  Reset rather than creating a new object, for performance.
+      this._resetBounds()
 
-            //  Child markers.
-            for (i = 0; i < markers.length; i++) {
-                childLatLng = markers[i]._latlng
+      //  Child markers.
+      for (i = 0; i < markers.length; i++) {
+        childLatLng = markers[i]._latlng
 
-                this._bounds.extend(childLatLng)
+        this._bounds.extend(childLatLng)
 
-                latSum += childLatLng.lat
-                lngSum += childLatLng.lng
-            }
+        latSum += childLatLng.lat
+        lngSum += childLatLng.lng
+      }
 
-            //  Child clusters.
-            for (i = 0; i < childClusters.length; i++) {
-                child = childClusters[i]
+      //  Child clusters.
+      for (i = 0; i < childClusters.length; i++) {
+        child = childClusters[i]
 
-                //  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
-        _addToMap: function(startPos) {
-            if (startPos) {
-                this._backupLatlng = this._latlng
-                this.setLatLng(startPos)
-            }
-            this._group._featureGroup.addLayer(this)
-        },
-
-        _recursivelyAnimateChildrenIn: function(bounds, center, maxZoom) {
-            this._recursively(bounds, this._group._map.getMinZoom(), maxZoom - 1,
-                function(c) {
-                    var markers = c._markers,
-                        i, m
-                    for (i = markers.length - 1; i >= 0; i--) {
-                        m = markers[i]
-
-                        //  Only do it if the icon is still on the map
-                        if (m._icon) {
-                            m._setPos(center)
-                            m.clusterHide()
-                        }
-                    }
-                },
-                function(c) {
-                    var childClusters = c._childClusters,
-                        j, cm
-                    for (j = childClusters.length - 1; j >= 0; j--) {
-                        cm = childClusters[j]
-                        if (cm._icon) {
-                            cm._setPos(center)
-                            cm.clusterHide()
-                        }
-                    }
-                }
-            );
-        },
-
-        _recursivelyAnimateChildrenInAndAddSelfToMap: function(bounds, mapMinZoom, previousZoomLevel, newZoomLevel) {
-            this._recursively(bounds, newZoomLevel, mapMinZoom,
-                function(c) {
-                    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() && previousZoomLevel - 1 === newZoomLevel) {
-                        c.clusterShow()
-                        c._recursivelyRemoveChildrenFromMap(bounds, mapMinZoom, previousZoomLevel) //  Immediately remove our children as we are replacing them. TODO previousBounds not bounds
-                    } else {
-                        c.clusterHide()
-                    }
-
-                    c._addToMap()
-                }
-            )
-        },
-
-        _recursivelyBecomeVisible: function(bounds, zoomLevel) {
-            this._recursively(bounds, this._group._map.getMinZoom(), zoomLevel, null, function(c) {
-                c.clusterShow()
-            })
-        },
-
-        _recursivelyAddChildrenToMap: function(startPos, zoomLevel, bounds) {
-            this._recursively(bounds, this._group._map.getMinZoom() - 1, zoomLevel,
-                function(c) {
-                    if (zoomLevel === c._zoom) {
-                        return
-                    }
-
-                    //  Add our child markers at startPos (so they can be animated out)
-                    for (var i = c._markers.length - 1; i >= 0; i--) {
-                        var nm = c._markers[i]
-
-                        if (!bounds.contains(nm._latlng)) {
-                            continue
-                        }
-
-                        if (startPos) {
-                            nm._backupLatlng = nm.getLatLng()
-
-                            nm.setLatLng(startPos)
-                            if (nm.clusterHide) {
-                                nm.clusterHide()
-                            }
-                        }
-
-                        c._group._featureGroup.addLayer(nm)
-                    }
-                },
-                function(c) {
-                    c._addToMap(startPos)
-                }
-            )
-        },
-
-        _recursivelyRestoreChildPositions: function(zoomLevel) {
-            //  Fix positions of child markers
-            for (var i = this._markers.length - 1; i >= 0; i--) {
-                var nm = this._markers[i]
-                if (nm._backupLatlng) {
-                    nm.setLatLng(nm._backupLatlng)
-                    delete nm._backupLatlng
-                }
-            }
-
-            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(zoomLevel)
-                }
-            }
-        },
-
-        _restorePosition: function() {
-            if (this._backupLatlng) {
-                this.setLatLng(this._backupLatlng)
-                delete this._backupLatlng
-            }
-        },
-
-        //  exceptBounds: If set, don't remove any markers/clusters in it
-        _recursivelyRemoveChildrenFromMap: function(previousBounds, mapMinZoom, zoomLevel, exceptBounds) {
-            var m, i
-            this._recursively(previousBounds, mapMinZoom - 1, zoomLevel - 1,
-                function(c) {
-                    //  Remove markers at every level
-                    for (i = c._markers.length - 1; i >= 0; i--) {
-                        m = c._markers[i]
-                        if (!exceptBounds || !exceptBounds.contains(m._latlng)) {
-                            c._group._featureGroup.removeLayer(m)
-                            if (m.clusterShow) {
-                                m.clusterShow()
-                            }
-                        }
-                    }
-                },
-                function(c) {
-                    //  Remove child clusters at just the bottom level
-                    for (i = c._childClusters.length - 1; i >= 0; i--) {
-                        m = c._childClusters[i]
-                        if (!exceptBounds || !exceptBounds.contains(m._latlng)) {
-                            c._group._featureGroup.removeLayer(m)
-                            if (m.clusterShow) {
-                                m.clusterShow()
-                            }
-                        }
-                    }
-                }
-            )
-        },
-
-        //  Run the given functions recursively to this and child clusters
-        //  boundsToApplyTo: a L.LatLngBounds representing the bounds of what clusters to recurse in to
-        //  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, zoomLevelToStart, zoomLevelToStop, runAtEveryLevel, runAtBottomLevel) {
-            var childClusters = this._childClusters,
-                zoom = this._zoom,
-                i, c
-
-            if (zoomLevelToStart <= zoom) {
-                if (runAtEveryLevel) {
-                    runAtEveryLevel(this)
-                }
-                if (runAtBottomLevel && zoom === zoomLevelToStop) {
-                    runAtBottomLevel(this)
-                }
-            }
-
-            if (zoom < zoomLevelToStart || zoom < zoomLevelToStop) {
-                for (i = childClusters.length - 1; i >= 0; i--) {
-                    c = childClusters[i]
-                    if (c._boundsNeedUpdate) {
-                        c._recalculateBounds()
-                    }
-                    if (boundsToApplyTo.intersects(c._bounds)) {
-                        c._recursively(boundsToApplyTo, zoomLevelToStart, zoomLevelToStop, runAtEveryLevel, runAtBottomLevel)
-                    }
-                }
-            }
-        },
-
-        //  Returns true if we are the parent of only one cluster and that cluster is the same as us
-        _isSingleParent: function() {
-            //  Don't need to check this._markers as the rest won't work if there are any
-            return this._childClusters.length > 0 && this._childClusters[0]._childCount === this._childCount
+        //  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
+    _addToMap: function (startPos) {
+      if (startPos) {
+        this._backupLatlng = this._latlng
+        this.setLatLng(startPos)
+      }
+      this._group._featureGroup.addLayer(this)
+    },
+
+    _recursivelyAnimateChildrenIn: function (bounds, center, maxZoom) {
+      this._recursively(bounds, this._group._map.getMinZoom(), maxZoom - 1,
+        function (c) {
+          var markers = c._markers
+          var i; var m
+          for (i = markers.length - 1; i >= 0; i--) {
+            m = markers[i]
+
+            //  Only do it if the icon is still on the map
+            if (m._icon) {
+              m._setPos(center)
+              m.clusterHide()
+            }
+          }
+        },
+        function (c) {
+          var childClusters = c._childClusters
+          var j; var cm
+          for (j = childClusters.length - 1; j >= 0; j--) {
+            cm = childClusters[j]
+            if (cm._icon) {
+              cm._setPos(center)
+              cm.clusterHide()
+            }
+          }
+        }
+      )
+    },
+
+    _recursivelyAnimateChildrenInAndAddSelfToMap: function (bounds, mapMinZoom, previousZoomLevel, newZoomLevel) {
+      this._recursively(bounds, newZoomLevel, mapMinZoom,
+        function (c) {
+          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() && previousZoomLevel - 1 === newZoomLevel) {
+            c.clusterShow()
+            c._recursivelyRemoveChildrenFromMap(bounds, mapMinZoom, previousZoomLevel) //  Immediately remove our children as we are replacing them. TODO previousBounds not bounds
+          } else {
+            c.clusterHide()
+          }
+
+          c._addToMap()
+        }
+      )
+    },
+
+    _recursivelyBecomeVisible: function (bounds, zoomLevel) {
+      this._recursively(bounds, this._group._map.getMinZoom(), zoomLevel, null, function (c) {
+        c.clusterShow()
+      })
+    },
+
+    _recursivelyAddChildrenToMap: function (startPos, zoomLevel, bounds) {
+      this._recursively(bounds, this._group._map.getMinZoom() - 1, zoomLevel,
+        function (c) {
+          if (zoomLevel === c._zoom) {
+            return
+          }
+
+          //  Add our child markers at startPos (so they can be animated out)
+          for (var i = c._markers.length - 1; i >= 0; i--) {
+            var nm = c._markers[i]
+
+            if (!bounds.contains(nm._latlng)) {
+              continue
+            }
+
+            if (startPos) {
+              nm._backupLatlng = nm.getLatLng()
+
+              nm.setLatLng(startPos)
+              if (nm.clusterHide) {
+                nm.clusterHide()
+              }
+            }
+
+            c._group._featureGroup.addLayer(nm)
+          }
+        },
+        function (c) {
+          c._addToMap(startPos)
+        }
+      )
+    },
+
+    _recursivelyRestoreChildPositions: function (zoomLevel) {
+      //  Fix positions of child markers
+      for (var i = this._markers.length - 1; i >= 0; i--) {
+        var nm = this._markers[i]
+        if (nm._backupLatlng) {
+          nm.setLatLng(nm._backupLatlng)
+          delete nm._backupLatlng
+        }
+      }
+
+      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(zoomLevel)
+        }
+      }
+    },
+
+    _restorePosition: function () {
+      if (this._backupLatlng) {
+        this.setLatLng(this._backupLatlng)
+        delete this._backupLatlng
+      }
+    },
+
+    //  exceptBounds: If set, don't remove any markers/clusters in it
+    _recursivelyRemoveChildrenFromMap: function (previousBounds, mapMinZoom, zoomLevel, exceptBounds) {
+      var m, i
+      this._recursively(previousBounds, mapMinZoom - 1, zoomLevel - 1,
+        function (c) {
+          //  Remove markers at every level
+          for (i = c._markers.length - 1; i >= 0; i--) {
+            m = c._markers[i]
+            if (!exceptBounds || !exceptBounds.contains(m._latlng)) {
+              c._group._featureGroup.removeLayer(m)
+              if (m.clusterShow) {
+                m.clusterShow()
+              }
+            }
+          }
+        },
+        function (c) {
+          //  Remove child clusters at just the bottom level
+          for (i = c._childClusters.length - 1; i >= 0; i--) {
+            m = c._childClusters[i]
+            if (!exceptBounds || !exceptBounds.contains(m._latlng)) {
+              c._group._featureGroup.removeLayer(m)
+              if (m.clusterShow) {
+                m.clusterShow()
+              }
+            }
+          }
+        }
+      )
+    },
+
+    //  Run the given functions recursively to this and child clusters
+    //  boundsToApplyTo: a L.LatLngBounds representing the bounds of what clusters to recurse in to
+    //  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, zoomLevelToStart, zoomLevelToStop, runAtEveryLevel, runAtBottomLevel) {
+      var childClusters = this._childClusters
+      var zoom = this._zoom
+      var i; var c
+
+      if (zoomLevelToStart <= zoom) {
+        if (runAtEveryLevel) {
+          runAtEveryLevel(this)
+        }
+        if (runAtBottomLevel && zoom === zoomLevelToStop) {
+          runAtBottomLevel(this)
+        }
+      }
+
+      if (zoom < zoomLevelToStart || zoom < zoomLevelToStop) {
+        for (i = childClusters.length - 1; i >= 0; i--) {
+          c = childClusters[i]
+          if (c._boundsNeedUpdate) {
+            c._recalculateBounds()
+          }
+          if (boundsToApplyTo.intersects(c._bounds)) {
+            c._recursively(boundsToApplyTo, zoomLevelToStart, zoomLevelToStop, runAtEveryLevel, runAtBottomLevel)
+          }
+        }
+      }
+    },
+
+    //  Returns true if we are the parent of only one cluster and that cluster is the same as us
+    _isSingleParent: function () {
+      //  Don't need to check this._markers as the rest won't work if there are any
+      return this._childClusters.length > 0 && this._childClusters[0]._childCount === this._childCount
+    }
+  })
+
+  /*
     * Extends L.Marker to include two extra methods: clusterHide and clusterShow.
     *
     * They work as setOpacity(0) and setOpacity(1) respectively, but
@@ -1791,134 +1780,134 @@
     *
     */
 
-    L.Marker.include({
-        clusterHide: function() {
-            var backup = this.options.opacity
-            this.setOpacity(0)
-            this.options.opacity = backup
-            return this
-        },
+  L.Marker.include({
+    clusterHide: function () {
+      var backup = this.options.opacity
+      this.setOpacity(0)
+      this.options.opacity = backup
+      return this
+    },
 
-        clusterShow: function() {
-            return this.setOpacity(this.options.opacity)
-        }
-    })
-
-    L.DistanceGrid = function(cellSize) {
-        this._cellSize = cellSize
-        this._sqCellSize = cellSize * cellSize
-        this._grid = {}
-        this._objectPoint = {}
+    clusterShow: function () {
+      return this.setOpacity(this.options.opacity)
     }
+  })
 
-    L.DistanceGrid.prototype = {
+  L.DistanceGrid = function (cellSize) {
+    this._cellSize = cellSize
+    this._sqCellSize = cellSize * cellSize
+    this._grid = {}
+    this._objectPoint = {}
+  }
 
-        addObject: 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] || [],
-                stamp = L.Util.stamp(obj)
+  L.DistanceGrid.prototype = {
 
-            this._objectPoint[stamp] = point
+    addObject: function (obj, point) {
+      var x = this._getCoord(point.x)
+      var y = this._getCoord(point.y)
+      var grid = this._grid
+      var row = grid[y] = grid[y] || {}
+      var cell = row[x] = row[x] || []
+      var stamp = L.Util.stamp(obj)
 
-            cell.push(obj)
-        },
+      this._objectPoint[stamp] = point
 
-        updateObject: function(obj, point) {
-            this.removeObject(obj)
-            this.addObject(obj, point)
-        },
+      cell.push(obj)
+    },
 
-        //  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;
+    updateObject: function (obj, point) {
+      this.removeObject(obj)
+      this.addObject(obj, point)
+    },
 
-            delete this._objectPoint[L.Util.stamp(obj)];
+    //  Returns true if the object was found
+    removeObject: function (obj, point) {
+      var x = this._getCoord(point.x)
+      var y = this._getCoord(point.y)
+      var grid = this._grid
+      var row = grid[y] = grid[y] || {}
+      var cell = row[x] = row[x] || []
+      var i; var len
 
-            for (i = 0, len = cell.length; i < len; i++) {
-                if (cell[i] === obj) {
-                    cell.splice(i, 1)
+      delete this._objectPoint[L.Util.stamp(obj)]
 
-                    if (len === 1) {
-                        delete row[x]
-                    }
+      for (i = 0, len = cell.length; i < len; i++) {
+        if (cell[i] === obj) {
+          cell.splice(i, 1)
 
-                    return true
-                }
-            }
-        },
+          if (len === 1) {
+            delete row[x]
+          }
 
-        eachObject: function(fn, context) {
-            var i, j, k, len, row, cell, removed,
-                grid = this._grid
-
-            for (i in grid) {
-                row = grid[i]
-
-                for (j in row) {
-                    cell = row[j]
-
-                    for (k = 0, len = cell.length; k < len; k++) {
-                        removed = fn.call(context, cell[k]);
-                        if (removed) {
-                            k--
-                            len--
-                        }
-                    }
-                }
-            }
-        },
-
-        getNearObject: function(point) {
-            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
-
-            for (i = y - 1; i <= y + 1; i++) {
-                row = this._grid[i]
-                if (row) {
-                    for (j = x - 1; j <= x + 1; j++) {
-                        cell = row[j]
-                        if (cell) {
-                            for (k = 0, len = cell.length; k < len; k++) {
-                                obj = cell[k]
-                                dist = this._sqDist(objectPoint[L.Util.stamp(obj)], point);
-                                if (dist < closestDistSq ||
-                                    dist <= closestDistSq && closest === null) {
-                                    closestDistSq = dist
-                                    closest = obj
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-            return closest
-        },
-
-        _getCoord: function(x) {
-            var coord = Math.floor(x / this._cellSize)
-            return isFinite(coord) ? coord : x
-        },
-
-        _sqDist: function(p, p2) {
-            var dx = p2.x - p.x,
-                dy = p2.y - p.y
-            return dx * dx + dy * dy
+          return true
         }
-    };
+      }
+    },
 
-    /* Copyright (c) 2012 the authors listed at the following URL, and/or
+    eachObject: function (fn, context) {
+      var i; var j; var k; var len; var row; var cell; var removed
+      var grid = this._grid
+
+      for (i in grid) {
+        row = grid[i]
+
+        for (j in row) {
+          cell = row[j]
+
+          for (k = 0, len = cell.length; k < len; k++) {
+            removed = fn.call(context, cell[k])
+            if (removed) {
+              k--
+              len--
+            }
+          }
+        }
+      }
+    },
+
+    getNearObject: function (point) {
+      var x = this._getCoord(point.x)
+      var y = this._getCoord(point.y)
+      var i; var j; var k; var row; var cell; var len; var obj; var dist
+      var objectPoint = this._objectPoint
+      var closestDistSq = this._sqCellSize
+      var closest = null
+
+      for (i = y - 1; i <= y + 1; i++) {
+        row = this._grid[i]
+        if (row) {
+          for (j = x - 1; j <= x + 1; j++) {
+            cell = row[j]
+            if (cell) {
+              for (k = 0, len = cell.length; k < len; k++) {
+                obj = cell[k]
+                dist = this._sqDist(objectPoint[L.Util.stamp(obj)], point)
+                if (dist < closestDistSq ||
+                                    dist <= closestDistSq && closest === null) {
+                  closestDistSq = dist
+                  closest = obj
+                }
+              }
+            }
+          }
+        }
+      }
+      return closest
+    },
+
+    _getCoord: function (x) {
+      var coord = Math.floor(x / this._cellSize)
+      return isFinite(coord) ? coord : x
+    },
+
+    _sqDist: function (p, p2) {
+      var dx = p2.x - p.x
+      var dy = p2.y - p.y
+      return dx * dx + dy * dy
+    }
+  };
+
+  /* Copyright (c) 2012 the authors listed at the following URL, and/or
     the authors of referenced articles or incorporated external code:
     http:// en.literateprograms.org/Quickhull_(Javascript)?action=history&offset=20120410175256
 
@@ -1944,629 +1933,628 @@
     Retrieved from: http:// en.literateprograms.org/Quickhull_(Javascript)?oldid=18434
     */
 
-    (function() {
-        L.QuickHull = {
+  (function () {
+    L.QuickHull = {
 
-            /*
+      /*
              * @param {Object} cpt a point to be measured from the baseline
              * @param {Array} bl the baseline, as represented by a two-element
              *   array of latlng objects.
              * @returns {Number} an approximate distance measure
              */
-            getDistant: function(cpt, bl) {
-                var vY = bl[1].lat - bl[0].lat,
-                    vX = bl[0].lng - bl[1].lng
-                return (vX * (cpt.lat - bl[0].lat) + vY * (cpt.lng - bl[0].lng))
-            },
+      getDistant: function (cpt, bl) {
+        var vY = bl[1].lat - bl[0].lat
+        var vX = bl[0].lng - bl[1].lng
+        return (vX * (cpt.lat - bl[0].lat) + vY * (cpt.lng - bl[0].lng))
+      },
 
-            /*
+      /*
              * @param {Array} baseLine a two-element array of latlng objects
              *   representing the baseline to project from
              * @param {Array} latLngs an array of latlng objects
              * @returns {Object} the maximum point and all new points to stay
              *   in consideration for the hull.
              */
-            findMostDistantPointFromBaseLine: function(baseLine, latLngs) {
-                var maxD = 0,
-                    maxPt = null,
-                    newPoints = [],
-                    i, pt, d
+      findMostDistantPointFromBaseLine: function (baseLine, latLngs) {
+        var maxD = 0
+        var maxPt = null
+        var newPoints = []
+        var i; var pt; var d
 
-                for (i = latLngs.length - 1; i >= 0; i--) {
-                    pt = latLngs[i]
-                    d = this.getDistant(pt, baseLine)
+        for (i = latLngs.length - 1; i >= 0; i--) {
+          pt = latLngs[i]
+          d = this.getDistant(pt, baseLine)
 
-                    if (d > 0) {
-                        newPoints.push(pt)
-                    } else {
-                        continue
-                    }
+          if (d > 0) {
+            newPoints.push(pt)
+          } else {
+            continue
+          }
 
-                    if (d > maxD) {
-                        maxD = d
-                        maxPt = pt
-                    }
-                }
+          if (d > maxD) {
+            maxD = d
+            maxPt = pt
+          }
+        }
 
-                return { maxPoint: maxPt, newPoints: newPoints }
-            },
+        return { maxPoint: maxPt, newPoints: newPoints }
+      },
 
-            /*
+      /*
              * Given a baseline, compute the convex hull of latLngs as an array
              * of latLngs.
              *
              * @param {Array} latLngs
              * @returns {Array}
              */
-            buildConvexHull: function(baseLine, latLngs) {
-                var convexHullBaseLines = [],
-                    t = this.findMostDistantPointFromBaseLine(baseLine, latLngs);
+      buildConvexHull: function (baseLine, latLngs) {
+        var convexHullBaseLines = []
+        var t = this.findMostDistantPointFromBaseLine(baseLine, latLngs)
 
-                if (t.maxPoint) { //  if there is still a point "outside" the base line
-                    convexHullBaseLines =
+        if (t.maxPoint) { //  if there is still a point "outside" the base line
+          convexHullBaseLines =
                         convexHullBaseLines.concat(
-                            this.buildConvexHull([baseLine[0], t.maxPoint], t.newPoints)
-                        );
-                    convexHullBaseLines =
-                        convexHullBaseLines.concat(
-                            this.buildConvexHull([t.maxPoint, baseLine[1]], t.newPoints)
+                          this.buildConvexHull([baseLine[0], t.maxPoint], t.newPoints)
                         )
-                    return convexHullBaseLines
-                } else { //  if there is no more point "outside" the base line, the current base line is part of the convex hull
-                    return [baseLine[0]]
-                }
-            },
+          convexHullBaseLines =
+                        convexHullBaseLines.concat(
+                          this.buildConvexHull([t.maxPoint, baseLine[1]], t.newPoints)
+                        )
+          return convexHullBaseLines
+        } else { //  if there is no more point "outside" the base line, the current base line is part of the convex hull
+          return [baseLine[0]]
+        }
+      },
 
-            /*
+      /*
              * Given an array of latlngs, compute a convex hull as an array
              * of latlngs
              *
              * @param {Array} latLngs
              * @returns {Array}
              */
-            getConvexHull: function(latLngs) {
-                //  find first baseline
-                var maxLat = false, minLat = false,
-                    maxLng = false, minLng = false,
-                    maxLatPt = null, minLatPt = null,
-                    maxLngPt = null, minLngPt = null,
-                    maxPt = null, minPt = null,
-                    i
+      getConvexHull: function (latLngs) {
+        //  find first baseline
+        var maxLat = false; var minLat = false
+        var maxLng = false; var minLng = false
+        var maxLatPt = null; var minLatPt = null
+        var maxLngPt = null; var minLngPt = null
+        var maxPt = null; var minPt = null
+        var i
 
-                for (i = latLngs.length - 1; i >= 0; i--) {
-                    var pt = latLngs[i]
-                    if (maxLat === false || pt.lat > maxLat) {
-                        maxLatPt = pt
-                        maxLat = pt.lat
-                    }
-                    if (minLat === false || pt.lat < minLat) {
-                        minLatPt = pt
-                        minLat = pt.lat
-                    }
-                    if (maxLng === false || pt.lng > maxLng) {
-                        maxLngPt = pt
-                        maxLng = pt.lng
-                    }
-                    if (minLng === false || pt.lng < minLng) {
-                        minLngPt = pt
-                        minLng = pt.lng
-                    }
-                }
-
-                if (minLat !== maxLat) {
-                    minPt = minLatPt
-                    maxPt = maxLatPt
-                } else {
-                    minPt = minLngPt
-                    maxPt = maxLngPt
-                }
-
-                var ch = [].concat(this.buildConvexHull([minPt, maxPt], latLngs),
-                    this.buildConvexHull([maxPt, minPt], latLngs))
-                return ch
-            }
+        for (i = latLngs.length - 1; i >= 0; i--) {
+          var pt = latLngs[i]
+          if (maxLat === false || pt.lat > maxLat) {
+            maxLatPt = pt
+            maxLat = pt.lat
+          }
+          if (minLat === false || pt.lat < minLat) {
+            minLatPt = pt
+            minLat = pt.lat
+          }
+          if (maxLng === false || pt.lng > maxLng) {
+            maxLngPt = pt
+            maxLng = pt.lng
+          }
+          if (minLng === false || pt.lng < minLng) {
+            minLngPt = pt
+            minLng = pt.lng
+          }
         }
-    }())
 
-    L.MarkerCluster.include({
-        getConvexHull: function() {
-            var childMarkers = this.getAllChildMarkers(),
-                points = [],
-                p, i
-
-            for (i = childMarkers.length - 1; i >= 0; i--) {
-                p = childMarkers[i].getLatLng()
-                points.push(p)
-            }
-
-            return L.QuickHull.getConvexHull(points);
+        if (minLat !== maxLat) {
+          minPt = minLatPt
+          maxPt = maxLatPt
+        } else {
+          minPt = minLngPt
+          maxPt = maxLngPt
         }
-    })
 
-//  This code is 100% based on https:// github.com/jawj/OverlappingMarkerSpiderfier-Leaflet
-//  Huge thanks to jawj for implementing it first to make my job easy :-)
+        var ch = [].concat(this.buildConvexHull([minPt, maxPt], latLngs),
+          this.buildConvexHull([maxPt, minPt], latLngs))
+        return ch
+      }
+    }
+  }())
 
-    L.MarkerCluster.include({
+  L.MarkerCluster.include({
+    getConvexHull: function () {
+      var childMarkers = this.getAllChildMarkers()
+      var points = []
+      var p; var i
 
-        _2PI: Math.PI * 2,
-        _circleFootSeparation: 25, //  related to circumference of circle
-        _circleStartAngle: 0,
+      for (i = childMarkers.length - 1; i >= 0; i--) {
+        p = childMarkers[i].getLatLng()
+        points.push(p)
+      }
 
-        _spiralFootSeparation: 28, //  related to size of spiral (experiment!)
-        _spiralLengthStart: 11,
-        _spiralLengthFactor: 5,
+      return L.QuickHull.getConvexHull(points)
+    }
+  })
 
-        _circleSpiralSwitchover: 9, //  show spiral instead of circle from this marker count upwards.
-                                    //  0 -> always spiral; Infinity -> always circle
+  //  This code is 100% based on https:// github.com/jawj/OverlappingMarkerSpiderfier-Leaflet
+  //  Huge thanks to jawj for implementing it first to make my job easy :-)
 
-        spiderfy: function() {
-            if (this._group._spiderfied === this || this._group._inZoomAnimation) {
-                return
-            }
+  L.MarkerCluster.include({
 
-            var childMarkers = this.getAllChildMarkers(null, true),
-                group = this._group,
-                map = group._map,
-                center = map.latLngToLayerPoint(this._latlng),
-                positions;
+    _2PI: Math.PI * 2,
+    _circleFootSeparation: 25, //  related to circumference of circle
+    _circleStartAngle: 0,
 
-            this._group._unspiderfy();
-            this._group._spiderfied = this;
+    _spiralFootSeparation: 28, //  related to size of spiral (experiment!)
+    _spiralLengthStart: 11,
+    _spiralLengthFactor: 5,
 
-            //  TODO Maybe: childMarkers order by distance to center
+    _circleSpiralSwitchover: 9, //  show spiral instead of circle from this marker count upwards.
+    //  0 -> always spiral; Infinity -> always circle
 
-            if (childMarkers.length >= this._circleSpiralSwitchover) {
-                positions = this._generatePointsSpiral(childMarkers.length, center)
-            } else {
-                center.y += 10 //  Otherwise circles look wrong => hack for standard blue icon, renders differently for other icons.
-                positions = this._generatePointsCircle(childMarkers.length, center)
-            }
+    spiderfy: function () {
+      if (this._group._spiderfied === this || this._group._inZoomAnimation) {
+        return
+      }
 
-            this._animationSpiderfy(childMarkers, positions)
-        },
+      var childMarkers = this.getAllChildMarkers(null, true)
+      var group = this._group
+      var map = group._map
+      var center = map.latLngToLayerPoint(this._latlng)
+      var positions
 
-        unspiderfy: function(zoomDetails) {
-            //  <param Name="zoomDetails">Argument from zoomanim if being called in a zoom animation or null otherwise</param>
-            if (this._group._inZoomAnimation) {
-                return
-            }
-            this._animationUnspiderfy(zoomDetails)
+      this._group._unspiderfy()
+      this._group._spiderfied = this
 
-            this._group._spiderfied = null
-        },
+      //  TODO Maybe: childMarkers order by distance to center
 
-        _generatePointsCircle: function(count, centerPt) {
-            var circumference = this._group.options.spiderfyDistanceMultiplier * this._circleFootSeparation * (2 + count),
-                legLength = circumference / this._2PI, //  radius from circumference
-                angleStep = this._2PI / count,
-                res = [],
-                i, angle
+      if (childMarkers.length >= this._circleSpiralSwitchover) {
+        positions = this._generatePointsSpiral(childMarkers.length, center)
+      } else {
+        center.y += 10 //  Otherwise circles look wrong => hack for standard blue icon, renders differently for other icons.
+        positions = this._generatePointsCircle(childMarkers.length, center)
+      }
 
-            legLength = Math.max(legLength, 35) //  Minimum distance to get outside the cluster icon.
+      this._animationSpiderfy(childMarkers, positions)
+    },
 
-            res.length = count
+    unspiderfy: function (zoomDetails) {
+      //  <param Name="zoomDetails">Argument from zoomanim if being called in a zoom animation or null otherwise</param>
+      if (this._group._inZoomAnimation) {
+        return
+      }
+      this._animationUnspiderfy(zoomDetails)
 
-            for (i = 0; i < count; i++) { //  Clockwise, like spiral.
-                angle = this._circleStartAngle + i * angleStep;
-                res[i] = new L.Point(centerPt.x + legLength * Math.cos(angle), centerPt.y + legLength * Math.sin(angle))._round();
-            }
+      this._group._spiderfied = null
+    },
 
-            return res
-        },
+    _generatePointsCircle: function (count, centerPt) {
+      var circumference = this._group.options.spiderfyDistanceMultiplier * this._circleFootSeparation * (2 + count)
+      var legLength = circumference / this._2PI //  radius from circumference
+      var angleStep = this._2PI / count
+      var res = []
+      var i; var angle
 
-        _generatePointsSpiral: function(count, centerPt) {
-            var spiderfyDistanceMultiplier = this._group.options.spiderfyDistanceMultiplier,
-                legLength = spiderfyDistanceMultiplier * this._spiralLengthStart,
-                separation = spiderfyDistanceMultiplier * this._spiralFootSeparation,
-                lengthFactor = spiderfyDistanceMultiplier * this._spiralLengthFactor * this._2PI,
-                angle = 0,
-                res = [],
-                i
+      legLength = Math.max(legLength, 35) //  Minimum distance to get outside the cluster icon.
 
-            res.length = count
+      res.length = count
 
-            //  Higher index, closer position to cluster center.
-            for (i = count; i >= 0; i--) {
-                //  Skip the first position, so that we are already farther from center and we avoid
-                //  being under the default cluster icon (especially important for Circle Markers).
-                if (i < count) {
-                    res[i] = new L.Point(centerPt.x + legLength * Math.cos(angle), centerPt.y + legLength * Math.sin(angle))._round()
-                }
-                angle += separation / legLength + i * 0.0005
-                legLength += lengthFactor / angle
-            }
-            return res;
-        },
+      for (i = 0; i < count; i++) { //  Clockwise, like spiral.
+        angle = this._circleStartAngle + i * angleStep
+        res[i] = new L.Point(centerPt.x + legLength * Math.cos(angle), centerPt.y + legLength * Math.sin(angle))._round()
+      }
 
-        _noanimationUnspiderfy: function() {
-            var group = this._group,
-                map = group._map,
-                fg = group._featureGroup,
-                childMarkers = this.getAllChildMarkers(null, true),
-                m, i
+      return res
+    },
 
-            group._ignoreMove = true
+    _generatePointsSpiral: function (count, centerPt) {
+      var spiderfyDistanceMultiplier = this._group.options.spiderfyDistanceMultiplier
+      var legLength = spiderfyDistanceMultiplier * this._spiralLengthStart
+      var separation = spiderfyDistanceMultiplier * this._spiralFootSeparation
+      var lengthFactor = spiderfyDistanceMultiplier * this._spiralLengthFactor * this._2PI
+      var angle = 0
+      var res = []
+      var i
 
-            this.setOpacity(1)
-            for (i = childMarkers.length - 1; i >= 0; i--) {
-                m = childMarkers[i]
+      res.length = count
 
-                fg.removeLayer(m)
-
-                if (m._preSpiderfyLatlng) {
-                    m.setLatLng(m._preSpiderfyLatlng)
-                    delete m._preSpiderfyLatlng
-                }
-                if (m.setZIndexOffset) {
-                    m.setZIndexOffset(0)
-                }
-
-                if (m._spiderLeg) {
-                    map.removeLayer(m._spiderLeg)
-                    delete m._spiderLeg
-                }
-            }
-
-            group.fire('unspiderfied', {
-                cluster: this,
-                markers: childMarkers
-            })
-            group._ignoreMove = false
-            group._spiderfied = null
+      //  Higher index, closer position to cluster center.
+      for (i = count; i >= 0; i--) {
+        //  Skip the first position, so that we are already farther from center and we avoid
+        //  being under the default cluster icon (especially important for Circle Markers).
+        if (i < count) {
+          res[i] = new L.Point(centerPt.x + legLength * Math.cos(angle), centerPt.y + legLength * Math.sin(angle))._round()
         }
-    })
+        angle += separation / legLength + i * 0.0005
+        legLength += lengthFactor / angle
+      }
+      return res
+    },
 
-//  Non Animated versions of everything
-    L.MarkerClusterNonAnimated = L.MarkerCluster.extend({
-        _animationSpiderfy: function(childMarkers, positions) {
-            var group = this._group,
-                map = group._map,
-                fg = group._featureGroup,
-                legOptions = this._group.options.spiderLegPolylineOptions,
-                i, m, leg, newPos
+    _noanimationUnspiderfy: function () {
+      var group = this._group
+      var map = group._map
+      var fg = group._featureGroup
+      var childMarkers = this.getAllChildMarkers(null, true)
+      var m; var i
 
-            group._ignoreMove = true
+      group._ignoreMove = true
 
-            //  Traverse in ascending order to make sure that inner circleMarkers are on top of further legs. Normal markers are re-ordered by newPosition.
-            //  The reverse order trick no longer improves performance on modern browsers.
-            for (i = 0; i < childMarkers.length; i++) {
-                newPos = map.layerPointToLatLng(positions[i])
-                m = childMarkers[i]
+      this.setOpacity(1)
+      for (i = childMarkers.length - 1; i >= 0; i--) {
+        m = childMarkers[i]
 
-                //  Add the leg before the marker, so that in case the latter is a circleMarker, the leg is behind it.
-                leg = new L.Polyline([this._latlng, newPos], legOptions)
-                map.addLayer(leg)
-                m._spiderLeg = leg
+        fg.removeLayer(m)
 
-                //  Now add the marker.
-                m._preSpiderfyLatlng = m._latlng
-                m.setLatLng(newPos)
-                if (m.setZIndexOffset) {
-                    m.setZIndexOffset(1000000) //  Make these appear on top of EVERYTHING
-                }
-
-                fg.addLayer(m)
-            }
-            this.setOpacity(0.3)
-
-            group._ignoreMove = false
-            group.fire('spiderfied', {
-                cluster: this,
-                markers: childMarkers
-            })
-        },
-
-        _animationUnspiderfy: function() {
-            this._noanimationUnspiderfy()
+        if (m._preSpiderfyLatlng) {
+          m.setLatLng(m._preSpiderfyLatlng)
+          delete m._preSpiderfyLatlng
         }
-    })
-
-//  Animated versions here
-    L.MarkerCluster.include({
-
-        _animationSpiderfy: function(childMarkers, positions) {
-            var me = this,
-                group = this._group,
-                map = group._map,
-                fg = group._featureGroup,
-                thisLayerLatLng = this._latlng,
-                thisLayerPos = map.latLngToLayerPoint(thisLayerLatLng),
-                svg = L.Path.SVG,
-                legOptions = L.extend({}, this._group.options.spiderLegPolylineOptions), //  Copy the options so that we can modify them for animation.
-                finalLegOpacity = legOptions.opacity,
-                i, m, leg, legPath, legLength, newPos
-
-            if (finalLegOpacity === undefined) {
-                finalLegOpacity = L.MarkerClusterGroup.prototype.options.spiderLegPolylineOptions.opacity;
-            }
-
-            if (svg) {
-                //  If the initial opacity of the spider leg is not 0 then it appears before the animation starts.
-                legOptions.opacity = 0
-
-                //  Add the class for CSS transitions.
-                legOptions.className = (legOptions.className || '') + ' leaflet-cluster-spider-leg'
-            } else {
-                //  Make sure we have a defined opacity.
-                legOptions.opacity = finalLegOpacity
-            }
-
-            group._ignoreMove = true
-
-            //  Add markers and spider legs to map, hidden at our center point.
-            //  Traverse in ascending order to make sure that inner circleMarkers are on top of further legs. Normal markers are re-ordered by newPosition.
-            //  The reverse order trick no longer improves performance on modern browsers.
-            for (i = 0; i < childMarkers.length; i++) {
-                m = childMarkers[i]
-
-                newPos = map.layerPointToLatLng(positions[i])
-
-                //  Add the leg before the marker, so that in case the latter is a circleMarker, the leg is behind it.
-                leg = new L.Polyline([thisLayerLatLng, newPos], legOptions)
-                map.addLayer(leg)
-                m._spiderLeg = leg
-
-                //  Explanations: https:// jakearchibald.com/2013/animated-line-drawing-svg/
-                //  In our case the transition property is declared in the CSS file.
-                if (svg) {
-                    legPath = leg._path
-                    legLength = legPath.getTotalLength() + 0.1 //  Need a small extra length to avoid remaining dot in Firefox.
-                    legPath.style.strokeDasharray = legLength //  Just 1 length is enough, it will be duplicated.
-                    legPath.style.strokeDashoffset = legLength
-                }
-
-                //  If it is a marker, add it now and we'll animate it out
-                if (m.setZIndexOffset) {
-                    m.setZIndexOffset(1000000) //  Make normal markers appear on top of EVERYTHING
-                }
-                if (m.clusterHide) {
-                    m.clusterHide()
-                }
-
-                //  Vectors just get immediately added
-                fg.addLayer(m)
-
-                if (m._setPos) {
-                    m._setPos(thisLayerPos)
-                }
-            }
-
-            group._forceLayout()
-            group._animationStart()
-
-            //  Reveal markers and spider legs.
-            for (i = childMarkers.length - 1; i >= 0; i--) {
-                newPos = map.layerPointToLatLng(positions[i])
-                m = childMarkers[i]
-
-                //  Move marker to new position
-                m._preSpiderfyLatlng = m._latlng
-                m.setLatLng(newPos)
-
-                if (m.clusterShow) {
-                    m.clusterShow()
-                }
-
-                //  Animate leg (animation is actually delegated to CSS transition).
-                if (svg) {
-                    leg = m._spiderLeg
-                    legPath = leg._path
-                    legPath.style.strokeDashoffset = 0
-                    //  legPath.style.strokeOpacity = finalLegOpacity;
-                    leg.setStyle({ opacity: finalLegOpacity })
-                }
-            }
-            this.setOpacity(0.3)
-
-            group._ignoreMove = false
-
-            setTimeout(function() {
-                group._animationEnd()
-                group.fire('spiderfied', {
-                    cluster: me,
-                    markers: childMarkers
-                })
-            }, 200)
-        },
-
-        _animationUnspiderfy: function(zoomDetails) {
-            var me = this,
-                group = this._group,
-                map = group._map,
-                fg = group._featureGroup,
-                thisLayerPos = zoomDetails ? map._latLngToNewLayerPoint(this._latlng, zoomDetails.zoom, zoomDetails.center) : map.latLngToLayerPoint(this._latlng),
-                childMarkers = this.getAllChildMarkers(null, true),
-                svg = L.Path.SVG,
-                m, i, leg, legPath, legLength, nonAnimatable
-
-            group._ignoreMove = true
-            group._animationStart()
-
-            //  Make us visible and bring the child markers back in
-            this.setOpacity(1)
-            for (i = childMarkers.length - 1; i >= 0; i--) {
-                m = childMarkers[i]
-
-                //  Marker was added to us after we were spiderfied
-                if (!m._preSpiderfyLatlng) {
-                    continue
-                }
-
-                //  Close any popup on the marker first, otherwise setting the location of the marker will make the map scroll
-                m.closePopup()
-
-                //  Fix up the location to the real one
-                m.setLatLng(m._preSpiderfyLatlng)
-                delete m._preSpiderfyLatlng
-
-                //  Hack override the location to be our center
-                nonAnimatable = true
-                if (m._setPos) {
-                    m._setPos(thisLayerPos)
-                    nonAnimatable = false
-                }
-                if (m.clusterHide) {
-                    m.clusterHide()
-                    nonAnimatable = false
-                }
-                if (nonAnimatable) {
-                    fg.removeLayer(m)
-                }
-
-                //  Animate the spider leg back in (animation is actually delegated to CSS transition).
-                if (svg) {
-                    leg = m._spiderLeg
-                    legPath = leg._path
-                    legLength = legPath.getTotalLength() + 0.1
-                    legPath.style.strokeDashoffset = legLength
-                    leg.setStyle({ opacity: 0 })
-                }
-            }
-
-            group._ignoreMove = false
-
-            setTimeout(function() {
-                //  If we have only <= one child left then that marker will be shown on the map so don't remove it!
-                var stillThereChildCount = 0;
-                for (i = childMarkers.length - 1; i >= 0; i--) {
-                    m = childMarkers[i]
-                    if (m._spiderLeg) {
-                        stillThereChildCount++
-                    }
-                }
-
-                for (i = childMarkers.length - 1; i >= 0; i--) {
-                    m = childMarkers[i]
-
-                    if (!m._spiderLeg) { //  Has already been unspiderfied
-                        continue
-                    }
-
-                    if (m.clusterShow) {
-                        m.clusterShow()
-                    }
-                    if (m.setZIndexOffset) {
-                        m.setZIndexOffset(0)
-                    }
-
-                    if (stillThereChildCount > 1) {
-                        fg.removeLayer(m)
-                    }
-
-                    map.removeLayer(m._spiderLeg)
-                    delete m._spiderLeg
-                }
-                group._animationEnd()
-                group.fire('unspiderfied', {
-                    cluster: me,
-                    markers: childMarkers
-                })
-            }, 200)
+        if (m.setZIndexOffset) {
+          m.setZIndexOffset(0)
         }
-    })
 
-    L.MarkerClusterGroup.include({
-        //  The MarkerCluster currently spiderfied (if any)
-        _spiderfied: null,
-
-        unspiderfy: function() {
-            this._unspiderfy.apply(this, arguments);
-        },
-
-        _spiderfierOnAdd: function() {
-            this._map.on('click', this._unspiderfyWrapper, this)
-
-            if (this._map.options.zoomAnimation) {
-                this._map.on('zoomstart', this._unspiderfyZoomStart, this)
-            }
-            //  Browsers without zoomAnimation or a big zoom don't fire zoomstart
-            this._map.on('zoomend', this._noanimationUnspiderfy, this)
-
-            if (!L.Browser.touch) {
-                this._map.getRenderer(this);
-                //  Needs to happen in the pageload, not after, or animations don't work in webkit
-                //  http:// stackoverflow.com/questions/8455200/svg-animate-with-dynamically-added-elements
-                //  Disable on touch browsers as the animation messes up on a touch zoom and isn't very noticable
-            }
-        },
-
-        _spiderfierOnRemove: function() {
-            this._map.off('click', this._unspiderfyWrapper, this)
-            this._map.off('zoomstart', this._unspiderfyZoomStart, this)
-            this._map.off('zoomanim', this._unspiderfyZoomAnim, this)
-            this._map.off('zoomend', this._noanimationUnspiderfy, this)
-
-            //  Ensure that markers are back where they should be
-            //  Use no animation to avoid a sticky leaflet-cluster-anim class on mapPane
-            this._noanimationUnspiderfy()
-        },
-
-        //  On zoom start we add a zoomanim handler so that we are guaranteed to be last (after markers are animated)
-        //  This means we can define the animation they do rather than Markers doing an animation to their actual location
-        _unspiderfyZoomStart: function() {
-            if (!this._map) { //  May have been removed from the map by a zoomEnd handler
-                return
-            }
-
-            this._map.on('zoomanim', this._unspiderfyZoomAnim, this);
-        },
-
-        _unspiderfyZoomAnim: function(zoomDetails) {
-            //  Wait until the first zoomanim after the user has finished touch-zooming before running the animation
-            if (L.DomUtil.hasClass(this._map._mapPane, 'leaflet-touching')) {
-                return
-            }
-
-            this._map.off('zoomanim', this._unspiderfyZoomAnim, this)
-            this._unspiderfy(zoomDetails)
-        },
-
-        _unspiderfyWrapper: function() {
-            //  <summary>_unspiderfy but passes no arguments</summary>
-            this._unspiderfy()
-        },
-
-        _unspiderfy: function(zoomDetails) {
-            if (this._spiderfied) {
-                this._spiderfied.unspiderfy(zoomDetails)
-            }
-        },
-
-        _noanimationUnspiderfy: function() {
-            if (this._spiderfied) {
-                this._spiderfied._noanimationUnspiderfy()
-            }
-        },
-
-        //  If the given layer is currently being spiderfied then we unspiderfy it so it isn't on the map anymore etc
-        _unspiderfyLayer: function(layer) {
-            if (layer._spiderLeg) {
-                this._featureGroup.removeLayer(layer)
-
-                if (layer.clusterShow) {
-                    layer.clusterShow()
-                }
-                //  Position will be fixed up immediately in _animationUnspiderfy
-                if (layer.setZIndexOffset) {
-                    layer.setZIndexOffset(0)
-                }
-
-                this._map.removeLayer(layer._spiderLeg)
-                delete layer._spiderLeg
-            }
+        if (m._spiderLeg) {
+          map.removeLayer(m._spiderLeg)
+          delete m._spiderLeg
         }
-    });
+      }
 
-    /**
+      group.fire('unspiderfied', {
+        cluster: this,
+        markers: childMarkers
+      })
+      group._ignoreMove = false
+      group._spiderfied = null
+    }
+  })
+
+  //  Non Animated versions of everything
+  L.MarkerClusterNonAnimated = L.MarkerCluster.extend({
+    _animationSpiderfy: function (childMarkers, positions) {
+      var group = this._group
+      var map = group._map
+      var fg = group._featureGroup
+      var legOptions = this._group.options.spiderLegPolylineOptions
+      var i; var m; var leg; var newPos
+
+      group._ignoreMove = true
+
+      //  Traverse in ascending order to make sure that inner circleMarkers are on top of further legs. Normal markers are re-ordered by newPosition.
+      //  The reverse order trick no longer improves performance on modern browsers.
+      for (i = 0; i < childMarkers.length; i++) {
+        newPos = map.layerPointToLatLng(positions[i])
+        m = childMarkers[i]
+
+        //  Add the leg before the marker, so that in case the latter is a circleMarker, the leg is behind it.
+        leg = new L.Polyline([this._latlng, newPos], legOptions)
+        map.addLayer(leg)
+        m._spiderLeg = leg
+
+        //  Now add the marker.
+        m._preSpiderfyLatlng = m._latlng
+        m.setLatLng(newPos)
+        if (m.setZIndexOffset) {
+          m.setZIndexOffset(1000000) //  Make these appear on top of EVERYTHING
+        }
+
+        fg.addLayer(m)
+      }
+      this.setOpacity(0.3)
+
+      group._ignoreMove = false
+      group.fire('spiderfied', {
+        cluster: this,
+        markers: childMarkers
+      })
+    },
+
+    _animationUnspiderfy: function () {
+      this._noanimationUnspiderfy()
+    }
+  })
+
+  //  Animated versions here
+  L.MarkerCluster.include({
+
+    _animationSpiderfy: function (childMarkers, positions) {
+      var me = this
+      var group = this._group
+      var map = group._map
+      var fg = group._featureGroup
+      var thisLayerLatLng = this._latlng
+      var thisLayerPos = map.latLngToLayerPoint(thisLayerLatLng)
+      var svg = L.Path.SVG
+      var legOptions = L.extend({}, this._group.options.spiderLegPolylineOptions) //  Copy the options so that we can modify them for animation.
+      var finalLegOpacity = legOptions.opacity
+      var i; var m; var leg; var legPath; var legLength; var newPos
+
+      if (finalLegOpacity === undefined) {
+        finalLegOpacity = L.MarkerClusterGroup.prototype.options.spiderLegPolylineOptions.opacity
+      }
+
+      if (svg) {
+        //  If the initial opacity of the spider leg is not 0 then it appears before the animation starts.
+        legOptions.opacity = 0
+
+        //  Add the class for CSS transitions.
+        legOptions.className = (legOptions.className || '') + ' leaflet-cluster-spider-leg'
+      } else {
+        //  Make sure we have a defined opacity.
+        legOptions.opacity = finalLegOpacity
+      }
+
+      group._ignoreMove = true
+
+      //  Add markers and spider legs to map, hidden at our center point.
+      //  Traverse in ascending order to make sure that inner circleMarkers are on top of further legs. Normal markers are re-ordered by newPosition.
+      //  The reverse order trick no longer improves performance on modern browsers.
+      for (i = 0; i < childMarkers.length; i++) {
+        m = childMarkers[i]
+
+        newPos = map.layerPointToLatLng(positions[i])
+
+        //  Add the leg before the marker, so that in case the latter is a circleMarker, the leg is behind it.
+        leg = new L.Polyline([thisLayerLatLng, newPos], legOptions)
+        map.addLayer(leg)
+        m._spiderLeg = leg
+
+        //  Explanations: https:// jakearchibald.com/2013/animated-line-drawing-svg/
+        //  In our case the transition property is declared in the CSS file.
+        if (svg) {
+          legPath = leg._path
+          legLength = legPath.getTotalLength() + 0.1 //  Need a small extra length to avoid remaining dot in Firefox.
+          legPath.style.strokeDasharray = legLength //  Just 1 length is enough, it will be duplicated.
+          legPath.style.strokeDashoffset = legLength
+        }
+
+        //  If it is a marker, add it now and we'll animate it out
+        if (m.setZIndexOffset) {
+          m.setZIndexOffset(1000000) //  Make normal markers appear on top of EVERYTHING
+        }
+        if (m.clusterHide) {
+          m.clusterHide()
+        }
+
+        //  Vectors just get immediately added
+        fg.addLayer(m)
+
+        if (m._setPos) {
+          m._setPos(thisLayerPos)
+        }
+      }
+
+      group._forceLayout()
+      group._animationStart()
+
+      //  Reveal markers and spider legs.
+      for (i = childMarkers.length - 1; i >= 0; i--) {
+        newPos = map.layerPointToLatLng(positions[i])
+        m = childMarkers[i]
+
+        //  Move marker to new position
+        m._preSpiderfyLatlng = m._latlng
+        m.setLatLng(newPos)
+
+        if (m.clusterShow) {
+          m.clusterShow()
+        }
+
+        //  Animate leg (animation is actually delegated to CSS transition).
+        if (svg) {
+          leg = m._spiderLeg
+          legPath = leg._path
+          legPath.style.strokeDashoffset = 0
+          //  legPath.style.strokeOpacity = finalLegOpacity;
+          leg.setStyle({ opacity: finalLegOpacity })
+        }
+      }
+      this.setOpacity(0.3)
+
+      group._ignoreMove = false
+
+      setTimeout(function () {
+        group._animationEnd()
+        group.fire('spiderfied', {
+          cluster: me,
+          markers: childMarkers
+        })
+      }, 200)
+    },
+
+    _animationUnspiderfy: function (zoomDetails) {
+      var me = this
+      var group = this._group
+      var map = group._map
+      var fg = group._featureGroup
+      var thisLayerPos = zoomDetails ? map._latLngToNewLayerPoint(this._latlng, zoomDetails.zoom, zoomDetails.center) : map.latLngToLayerPoint(this._latlng)
+      var childMarkers = this.getAllChildMarkers(null, true)
+      var svg = L.Path.SVG
+      var m; var i; var leg; var legPath; var legLength; var nonAnimatable
+
+      group._ignoreMove = true
+      group._animationStart()
+
+      //  Make us visible and bring the child markers back in
+      this.setOpacity(1)
+      for (i = childMarkers.length - 1; i >= 0; i--) {
+        m = childMarkers[i]
+
+        //  Marker was added to us after we were spiderfied
+        if (!m._preSpiderfyLatlng) {
+          continue
+        }
+
+        //  Close any popup on the marker first, otherwise setting the location of the marker will make the map scroll
+        m.closePopup()
+
+        //  Fix up the location to the real one
+        m.setLatLng(m._preSpiderfyLatlng)
+        delete m._preSpiderfyLatlng
+
+        //  Hack override the location to be our center
+        nonAnimatable = true
+        if (m._setPos) {
+          m._setPos(thisLayerPos)
+          nonAnimatable = false
+        }
+        if (m.clusterHide) {
+          m.clusterHide()
+          nonAnimatable = false
+        }
+        if (nonAnimatable) {
+          fg.removeLayer(m)
+        }
+
+        //  Animate the spider leg back in (animation is actually delegated to CSS transition).
+        if (svg) {
+          leg = m._spiderLeg
+          legPath = leg._path
+          legLength = legPath.getTotalLength() + 0.1
+          legPath.style.strokeDashoffset = legLength
+          leg.setStyle({ opacity: 0 })
+        }
+      }
+
+      group._ignoreMove = false
+
+      setTimeout(function () {
+        //  If we have only <= one child left then that marker will be shown on the map so don't remove it!
+        var stillThereChildCount = 0
+        for (i = childMarkers.length - 1; i >= 0; i--) {
+          m = childMarkers[i]
+          if (m._spiderLeg) {
+            stillThereChildCount++
+          }
+        }
+
+        for (i = childMarkers.length - 1; i >= 0; i--) {
+          m = childMarkers[i]
+
+          if (!m._spiderLeg) { //  Has already been unspiderfied
+            continue
+          }
+
+          if (m.clusterShow) {
+            m.clusterShow()
+          }
+          if (m.setZIndexOffset) {
+            m.setZIndexOffset(0)
+          }
+
+          if (stillThereChildCount > 1) {
+            fg.removeLayer(m)
+          }
+
+          map.removeLayer(m._spiderLeg)
+          delete m._spiderLeg
+        }
+        group._animationEnd()
+        group.fire('unspiderfied', {
+          cluster: me,
+          markers: childMarkers
+        })
+      }, 200)
+    }
+  })
+
+  L.MarkerClusterGroup.include({
+    //  The MarkerCluster currently spiderfied (if any)
+    _spiderfied: null,
+
+    unspiderfy: function () {
+      this._unspiderfy.apply(this, arguments)
+    },
+
+    _spiderfierOnAdd: function () {
+      this._map.on('click', this._unspiderfyWrapper, this)
+
+      if (this._map.options.zoomAnimation) {
+        this._map.on('zoomstart', this._unspiderfyZoomStart, this)
+      }
+      //  Browsers without zoomAnimation or a big zoom don't fire zoomstart
+      this._map.on('zoomend', this._noanimationUnspiderfy, this)
+
+      if (!L.Browser.touch) {
+        this._map.getRenderer(this)
+        //  Needs to happen in the pageload, not after, or animations don't work in webkit
+        //  http:// stackoverflow.com/questions/8455200/svg-animate-with-dynamically-added-elements
+        //  Disable on touch browsers as the animation messes up on a touch zoom and isn't very noticable
+      }
+    },
+
+    _spiderfierOnRemove: function () {
+      this._map.off('click', this._unspiderfyWrapper, this)
+      this._map.off('zoomstart', this._unspiderfyZoomStart, this)
+      this._map.off('zoomanim', this._unspiderfyZoomAnim, this)
+      this._map.off('zoomend', this._noanimationUnspiderfy, this)
+
+      //  Ensure that markers are back where they should be
+      //  Use no animation to avoid a sticky leaflet-cluster-anim class on mapPane
+      this._noanimationUnspiderfy()
+    },
+
+    //  On zoom start we add a zoomanim handler so that we are guaranteed to be last (after markers are animated)
+    //  This means we can define the animation they do rather than Markers doing an animation to their actual location
+    _unspiderfyZoomStart: function () {
+      if (!this._map) { //  May have been removed from the map by a zoomEnd handler
+        return
+      }
+
+      this._map.on('zoomanim', this._unspiderfyZoomAnim, this)
+    },
+
+    _unspiderfyZoomAnim: function (zoomDetails) {
+      //  Wait until the first zoomanim after the user has finished touch-zooming before running the animation
+      if (L.DomUtil.hasClass(this._map._mapPane, 'leaflet-touching')) {
+        return
+      }
+
+      this._map.off('zoomanim', this._unspiderfyZoomAnim, this)
+      this._unspiderfy(zoomDetails)
+    },
+
+    _unspiderfyWrapper: function () {
+      //  <summary>_unspiderfy but passes no arguments</summary>
+      this._unspiderfy()
+    },
+
+    _unspiderfy: function (zoomDetails) {
+      if (this._spiderfied) {
+        this._spiderfied.unspiderfy(zoomDetails)
+      }
+    },
+
+    _noanimationUnspiderfy: function () {
+      if (this._spiderfied) {
+        this._spiderfied._noanimationUnspiderfy()
+      }
+    },
+
+    //  If the given layer is currently being spiderfied then we unspiderfy it so it isn't on the map anymore etc
+    _unspiderfyLayer: function (layer) {
+      if (layer._spiderLeg) {
+        this._featureGroup.removeLayer(layer)
+
+        if (layer.clusterShow) {
+          layer.clusterShow()
+        }
+        //  Position will be fixed up immediately in _animationUnspiderfy
+        if (layer.setZIndexOffset) {
+          layer.setZIndexOffset(0)
+        }
+
+        this._map.removeLayer(layer._spiderLeg)
+        delete layer._spiderLeg
+      }
+    }
+  })
+
+  /**
      * Adds 1 public method to MCG and 1 to L.Marker to facilitate changing
      * markers' icon options and refreshing their icon and their parent clusters
      * accordingly (case where their iconCreateFunction uses data of childMarkers
      * to make up the cluster icon).
      */
 
-
-    L.MarkerClusterGroup.include({
-        /**
+  L.MarkerClusterGroup.include({
+    /**
          * Updates the icon of all clusters which are parents of the given marker(s).
          * In singleMarkerMode, also updates the given marker(s) icon.
          * @param layers L.MarkerClusterGroup|L.LayerGroup|Array(L.Marker)|Map(L.Marker)|
@@ -2574,105 +2562,104 @@
          * clusters need to be updated. If not provided, retrieves all child markers of this.
          * @returns {L.MarkerClusterGroup}
          */
-        refreshClusters: function(layers) {
-            if (!layers) {
-                layers = this._topClusterLevel.getAllChildMarkers()
-            } else if (layers instanceof L.MarkerClusterGroup) {
-                layers = layers._topClusterLevel.getAllChildMarkers()
-            } else if (layers instanceof L.LayerGroup) {
-                layers = layers._layers
-            } else if (layers instanceof L.MarkerCluster) {
-                layers = layers.getAllChildMarkers()
-            } else if (layers instanceof L.Marker) {
-                layers = [layers]
-            } //  else: must be an Array(L.Marker)|Map(L.Marker)
-            this._flagParentsIconsNeedUpdate(layers)
-            this._refreshClustersIcons()
+    refreshClusters: function (layers) {
+      if (!layers) {
+        layers = this._topClusterLevel.getAllChildMarkers()
+      } else if (layers instanceof L.MarkerClusterGroup) {
+        layers = layers._topClusterLevel.getAllChildMarkers()
+      } else if (layers instanceof L.LayerGroup) {
+        layers = layers._layers
+      } else if (layers instanceof L.MarkerCluster) {
+        layers = layers.getAllChildMarkers()
+      } else if (layers instanceof L.Marker) {
+        layers = [layers]
+      } //  else: must be an Array(L.Marker)|Map(L.Marker)
+      this._flagParentsIconsNeedUpdate(layers)
+      this._refreshClustersIcons()
 
-            //  In case of singleMarkerMode, also re-draw the markers.
-            if (this.options.singleMarkerMode) {
-                this._refreshSingleMarkerModeMarkers(layers)
-            }
+      //  In case of singleMarkerMode, also re-draw the markers.
+      if (this.options.singleMarkerMode) {
+        this._refreshSingleMarkerModeMarkers(layers)
+      }
 
-            return this
-        },
+      return this
+    },
 
-        /**
+    /**
          * Simply flags all parent clusters of the given markers as having a "dirty" icon.
          * @param layers Array(L.Marker)|Map(L.Marker) list of markers.
          * @private
          */
-        _flagParentsIconsNeedUpdate: function(layers) {
-            var id, parent
+    _flagParentsIconsNeedUpdate: function (layers) {
+      var id, parent
 
-            //  Assumes layers is an Array or an Object whose prototype is non-enumerable.
-            for (id in layers) {
-                //  Flag parent clusters' icon as "dirty", all the way up.
-                //  Dumb process that flags multiple times upper parents, but still
-                //  much more efficient than trying to be smart and make short lists,
-                //  at least in the case of a hierarchy following a power law:
-                //  http:// jsperf.com/flag-nodes-in-power-hierarchy/2
-                parent = layers[id].__parent
-                while (parent) {
-                    parent._iconNeedsUpdate = true
-                    parent = parent.__parent
-                }
-            }
-        },
+      //  Assumes layers is an Array or an Object whose prototype is non-enumerable.
+      for (id in layers) {
+        //  Flag parent clusters' icon as "dirty", all the way up.
+        //  Dumb process that flags multiple times upper parents, but still
+        //  much more efficient than trying to be smart and make short lists,
+        //  at least in the case of a hierarchy following a power law:
+        //  http:// jsperf.com/flag-nodes-in-power-hierarchy/2
+        parent = layers[id].__parent
+        while (parent) {
+          parent._iconNeedsUpdate = true
+          parent = parent.__parent
+        }
+      }
+    },
 
-        /**
+    /**
          * Re-draws the icon of the supplied markers.
          * To be used in singleMarkerMode only.
          * @param layers Array(L.Marker)|Map(L.Marker) list of markers.
          * @private
          */
-        _refreshSingleMarkerModeMarkers: function(layers) {
-            var id, layer
+    _refreshSingleMarkerModeMarkers: function (layers) {
+      var id, layer
 
-            for (id in layers) {
-                layer = layers[id]
+      for (id in layers) {
+        layer = layers[id]
 
-                //  Make sure we do not override markers that do not belong to THIS group.
-                if (this.hasLayer(layer)) {
-                    //  Need to re-create the icon first, then re-draw the marker.
-                    layer.setIcon(this._overrideMarkerIcon(layer))
-                }
-            }
+        //  Make sure we do not override markers that do not belong to THIS group.
+        if (this.hasLayer(layer)) {
+          //  Need to re-create the icon first, then re-draw the marker.
+          layer.setIcon(this._overrideMarkerIcon(layer))
         }
-    });
+      }
+    }
+  })
 
-    L.Marker.include({
-        /**
+  L.Marker.include({
+    /**
          * Updates the given options in the marker's icon and refreshes the marker.
          * @param options map object of icon options.
          * @param directlyRefreshClusters boolean (optional) true to trigger
          * MCG.refreshClustersOf() right away with this single marker.
          * @returns {L.Marker}
          */
-        refreshIconOptions: function(options, directlyRefreshClusters) {
-            var icon = this.options.icon
+    refreshIconOptions: function (options, directlyRefreshClusters) {
+      var icon = this.options.icon
 
-            L.setOptions(icon, options)
+      L.setOptions(icon, options)
 
-            this.setIcon(icon)
+      this.setIcon(icon)
 
-            //  Shortcut to refresh the associated MCG clusters right away.
-            //  To be used when refreshing a single marker.
-            //  Otherwise, better use MCG.refreshClusters() once at the end with
-            //  the list of modified markers.
-            if (directlyRefreshClusters && this.__parent) {
-                this.__parent._group.refreshClusters(this)
-            }
+      //  Shortcut to refresh the associated MCG clusters right away.
+      //  To be used when refreshing a single marker.
+      //  Otherwise, better use MCG.refreshClusters() once at the end with
+      //  the list of modified markers.
+      if (directlyRefreshClusters && this.__parent) {
+        this.__parent._group.refreshClusters(this)
+      }
 
-            return this
-        }
-    })
+      return this
+    }
+  })
 
-    exports.MarkerClusterGroup = MarkerClusterGroup
-    exports.MarkerCluster = MarkerCluster
-
+  exports.MarkerClusterGroup = MarkerClusterGroup
+  exports.MarkerCluster = MarkerCluster
 }
 
 export default {
-    init
+  init
 }

--
Gitblit v1.8.0