leaflet-markercluster-rails 0.2.2 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Engine wrapper for the Leaflet MarkerCluster library by @danzel.
4
4
 
5
- https://github.com/danzel/Leaflet.markercluster
5
+ https://github.com/Leaflet/Leaflet.markercluster
6
6
 
7
7
  ## Installation
8
8
 
@@ -20,9 +20,14 @@ Or install it yourself as:
20
20
 
21
21
  ## Usage
22
22
 
23
- Provides the follwoing:
23
+ Provides the following assets:
24
24
 
25
25
  leaflet.markercluster.js
26
26
  leaflet.markercluster.css
27
27
  leaflet.markercluster.default.css
28
28
  leaflet.markercluster.ie.css
29
+
30
+ ## License
31
+ MIT License, full text of license see [here][License]
32
+
33
+ [License]: https://github.com/scpike/leaflet-markercluster-rails/blob/master/LICENSE.txt "LICENSE"
@@ -1,7 +1,7 @@
1
1
  module Leaflet
2
2
  module Markercluster
3
3
  module Rails
4
- VERSION = "0.2.2"
4
+ VERSION = "0.6.0"
5
5
  end
6
6
  end
7
7
  end
@@ -1,11 +1,9 @@
1
1
  /*
2
- Copyright (c) 2012, Smartrak, David Leaver
3
- Leaflet.markercluster is an open-source JavaScript library for Marker Clustering on leaflet powered maps.
4
- https://github.com/danzel/Leaflet.markercluster
2
+ Leaflet.markercluster, Provides Beautiful Animated Marker Clustering functionality for Leaflet, a JS library for interactive maps.
3
+ https://github.com/Leaflet/Leaflet.markercluster
4
+ (c) 2012-2013, Dave Leaver, smartrak
5
5
  */
6
- (function (window, undefined) {
7
-
8
-
6
+ (function (window, document, undefined) {
9
7
  /*
10
8
  * L.MarkerClusterGroup extends L.FeatureGroup by clustering the markers contained within
11
9
  */
@@ -23,6 +21,10 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
23
21
 
24
22
  disableClusteringAtZoom: null,
25
23
 
24
+ // Setting this to false prevents the removal of any clusters outside of the viewpoint, which
25
+ // is the default behaviour for performance reasons.
26
+ removeOutsideVisibleBounds: true,
27
+
26
28
  //Whether to animate adding markers after adding the MarkerClusterGroup to the map
27
29
  // If you are adding individual markers set to true, if adding bulk markers leave false for massive performance gains.
28
30
  animateAddingMarkers: false,
@@ -40,10 +42,15 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
40
42
  this.options.iconCreateFunction = this._defaultIconCreateFunction;
41
43
  }
42
44
 
43
- L.FeatureGroup.prototype.initialize.call(this, []);
45
+ this._featureGroup = L.featureGroup();
46
+ this._featureGroup.on(L.FeatureGroup.EVENTS, this._propagateEvent, this);
47
+
48
+ this._nonPointGroup = L.featureGroup();
49
+ this._nonPointGroup.on(L.FeatureGroup.EVENTS, this._propagateEvent, this);
44
50
 
45
51
  this._inZoomAnimation = 0;
46
52
  this._needsClustering = [];
53
+ this._needsRemoving = []; //Markers removed while we aren't on the map need to be kept track of
47
54
  //The bounds of the currently shown area (from _getExpandedVisibleBounds) Updated on zoom/move
48
55
  this._currentShownBounds = null;
49
56
  },
@@ -53,13 +60,17 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
53
60
  if (layer instanceof L.LayerGroup) {
54
61
  var array = [];
55
62
  for (var i in layer._layers) {
56
- if (layer._layers.hasOwnProperty(i)) {
57
- array.push(layer._layers[i]);
58
- }
63
+ array.push(layer._layers[i]);
59
64
  }
60
65
  return this.addLayers(array);
61
66
  }
62
67
 
68
+ //Don't cluster non point data
69
+ if (!layer.getLatLng) {
70
+ this._nonPointGroup.addLayer(layer);
71
+ return this;
72
+ }
73
+
63
74
  if (!this._map) {
64
75
  this._needsClustering.push(layer);
65
76
  return this;
@@ -69,6 +80,7 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
69
80
  return this;
70
81
  }
71
82
 
83
+
72
84
  //If we have already clustered we'll need to add this one to a cluster
73
85
 
74
86
  if (this._unspiderfy) {
@@ -98,8 +110,16 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
98
110
 
99
111
  removeLayer: function (layer) {
100
112
 
113
+ //Non point layers
114
+ if (!layer.getLatLng) {
115
+ this._nonPointGroup.removeLayer(layer);
116
+ return this;
117
+ }
118
+
101
119
  if (!this._map) {
102
- this._arraySplice(this._needsClustering, layer);
120
+ if (!this._arraySplice(this._needsClustering, layer) && this.hasLayer(layer)) {
121
+ this._needsRemoving.push(layer);
122
+ }
103
123
  return this;
104
124
  }
105
125
 
@@ -115,9 +135,11 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
115
135
  //Remove the marker from clusters
116
136
  this._removeLayer(layer, true);
117
137
 
118
- if (layer._icon) {
119
- L.FeatureGroup.prototype.removeLayer.call(this, layer);
120
- layer.setOpacity(1);
138
+ if (this._featureGroup.hasLayer(layer)) {
139
+ this._featureGroup.removeLayer(layer);
140
+ if (layer.setOpacity) {
141
+ layer.setOpacity(1);
142
+ }
121
143
  }
122
144
 
123
145
  return this;
@@ -125,19 +147,29 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
125
147
 
126
148
  //Takes an array of markers and adds them in bulk
127
149
  addLayers: function (layersArray) {
128
- var i, l, m;
129
- if (!this._map) {
130
- this._needsClustering = this._needsClustering.concat(layersArray);
131
- return this;
132
- }
150
+ var i, l, m,
151
+ onMap = this._map,
152
+ fg = this._featureGroup,
153
+ npg = this._nonPointGroup;
133
154
 
134
155
  for (i = 0, l = layersArray.length; i < l; i++) {
135
156
  m = layersArray[i];
136
157
 
158
+ //Not point data, can't be clustered
159
+ if (!m.getLatLng) {
160
+ npg.addLayer(m);
161
+ continue;
162
+ }
163
+
137
164
  if (this.hasLayer(m)) {
138
165
  continue;
139
166
  }
140
167
 
168
+ if (!onMap) {
169
+ this._needsClustering.push(m);
170
+ continue;
171
+ }
172
+
141
173
  this._addLayer(m, this._maxZoom);
142
174
 
143
175
  //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
@@ -145,33 +177,36 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
145
177
  if (m.__parent.getChildCount() === 2) {
146
178
  var markers = m.__parent.getAllChildMarkers(),
147
179
  otherMarker = markers[0] === m ? markers[1] : markers[0];
148
- L.FeatureGroup.prototype.removeLayer.call(this, otherMarker);
180
+ fg.removeLayer(otherMarker);
149
181
  }
150
182
  }
151
183
  }
152
184
 
153
- //Update the icons of all those visible clusters that were affected
154
- for (i in this._layers) {
155
- if (this._layers.hasOwnProperty(i)) {
156
- m = this._layers[i];
157
- if (m instanceof L.MarkerCluster && m._iconNeedsUpdate) {
158
- m._updateIcon();
185
+ if (onMap) {
186
+ //Update the icons of all those visible clusters that were affected
187
+ fg.eachLayer(function (c) {
188
+ if (c instanceof L.MarkerCluster && c._iconNeedsUpdate) {
189
+ c._updateIcon();
159
190
  }
160
- }
161
- }
191
+ });
162
192
 
163
- this._topClusterLevel._recursivelyAddChildrenToMap(null, this._zoom, this._currentShownBounds);
193
+ this._topClusterLevel._recursivelyAddChildrenToMap(null, this._zoom, this._currentShownBounds);
194
+ }
164
195
 
165
196
  return this;
166
197
  },
167
198
 
168
199
  //Takes an array of markers and removes them in bulk
169
200
  removeLayers: function (layersArray) {
170
- var i, l, m;
201
+ var i, l, m,
202
+ fg = this._featureGroup,
203
+ npg = this._nonPointGroup;
171
204
 
172
205
  if (!this._map) {
173
206
  for (i = 0, l = layersArray.length; i < l; i++) {
174
- this._arraySplice(this._needsClustering, layersArray[i]);
207
+ m = layersArray[i];
208
+ this._arraySplice(this._needsClustering, m);
209
+ npg.removeLayer(m);
175
210
  }
176
211
  return this;
177
212
  }
@@ -180,28 +215,28 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
180
215
  m = layersArray[i];
181
216
 
182
217
  if (!m.__parent) {
218
+ npg.removeLayer(m);
183
219
  continue;
184
220
  }
185
221
 
186
222
  this._removeLayer(m, true, true);
187
223
 
188
- if (m._icon) {
189
- L.FeatureGroup.prototype.removeLayer.call(this, m);
190
- m.setOpacity(1);
224
+ if (fg.hasLayer(m)) {
225
+ fg.removeLayer(m);
226
+ if (m.setOpacity) {
227
+ m.setOpacity(1);
228
+ }
191
229
  }
192
230
  }
193
231
 
194
232
  //Fix up the clusters and markers on the map
195
233
  this._topClusterLevel._recursivelyAddChildrenToMap(null, this._zoom, this._currentShownBounds);
196
234
 
197
- for (i in this._layers) {
198
- if (this._layers.hasOwnProperty(i)) {
199
- m = this._layers[i];
200
- if (m instanceof L.MarkerCluster) {
201
- m._updateIcon();
202
- }
235
+ fg.eachLayer(function (c) {
236
+ if (c instanceof L.MarkerCluster) {
237
+ c._updateIcon();
203
238
  }
204
- }
239
+ });
205
240
 
206
241
  return this;
207
242
  },
@@ -217,16 +252,13 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
217
252
  delete this._gridUnclustered;
218
253
  }
219
254
 
220
- if (this._unspiderfy) {
221
- this._unspiderfy();
255
+ if (this._noanimationUnspiderfy) {
256
+ this._noanimationUnspiderfy();
222
257
  }
223
258
 
224
259
  //Remove all the visible layers
225
- for (var i in this._layers) {
226
- if (this._layers.hasOwnProperty(i)) {
227
- L.FeatureGroup.prototype.removeLayer.call(this, this._layers[i]);
228
- }
229
- }
260
+ this._featureGroup.clearLayers();
261
+ this._nonPointGroup.clearLayers();
230
262
 
231
263
  this.eachLayer(function (marker) {
232
264
  delete marker.__parent;
@@ -250,6 +282,13 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
250
282
  bounds.extend(this._needsClustering[i].getLatLng());
251
283
  }
252
284
  }
285
+
286
+ //TODO: Can remove this isValid test when leaflet 0.6 is released
287
+ var nonPointBounds = this._nonPointGroup.getBounds();
288
+ if (nonPointBounds.isValid()) {
289
+ bounds.extend(nonPointBounds);
290
+ }
291
+
253
292
  return bounds;
254
293
  },
255
294
 
@@ -265,20 +304,32 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
265
304
  for (i = markers.length - 1; i >= 0; i--) {
266
305
  method.call(context, markers[i]);
267
306
  }
307
+
308
+ this._nonPointGroup.eachLayer(method, context);
268
309
  },
269
310
 
270
311
  //Returns true if the given layer is in this MarkerClusterGroup
271
312
  hasLayer: function (layer) {
272
- if (this._needsClustering.length > 0) {
273
- var anArray = this._needsClustering;
274
- for (var i = anArray.length - 1; i >= 0; i--) {
275
- if (anArray[i] === layer) {
276
- return true;
277
- }
313
+ if (!layer) {
314
+ return false;
315
+ }
316
+
317
+ var i, anArray = this._needsClustering;
318
+
319
+ for (i = anArray.length - 1; i >= 0; i--) {
320
+ if (anArray[i] === layer) {
321
+ return true;
322
+ }
323
+ }
324
+
325
+ anArray = this._needsRemoving;
326
+ for (i = anArray.length - 1; i >= 0; i--) {
327
+ if (anArray[i] === layer) {
328
+ return false;
278
329
  }
279
330
  }
280
331
 
281
- return !!(layer.__parent && layer.__parent._group === this);
332
+ return !!(layer.__parent && layer.__parent._group === this) || this._nonPointGroup.hasLayer(layer);
282
333
  },
283
334
 
284
335
  //Zoom down to show the given layer (spiderfying if necessary) then calls the callback
@@ -322,13 +373,35 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
322
373
  //Overrides FeatureGroup.onAdd
323
374
  onAdd: function (map) {
324
375
  this._map = map;
376
+ var i, l, layer;
377
+
378
+ if (!isFinite(this._map.getMaxZoom())) {
379
+ throw "Map has no maxZoom specified";
380
+ }
381
+
382
+ this._featureGroup.onAdd(map);
383
+ this._nonPointGroup.onAdd(map);
325
384
 
326
385
  if (!this._gridClusters) {
327
386
  this._generateInitialClusters();
328
387
  }
329
388
 
330
- for (var i = 0, l = this._needsClustering.length; i < l; i++) {
331
- var layer = this._needsClustering[i];
389
+ for (i = 0, l = this._needsRemoving.length; i < l; i++) {
390
+ layer = this._needsRemoving[i];
391
+ this._removeLayer(layer, true);
392
+ }
393
+ this._needsRemoving = [];
394
+
395
+ for (i = 0, l = this._needsClustering.length; i < l; i++) {
396
+ layer = this._needsClustering[i];
397
+
398
+ //If the layer doesn't have a getLatLng then we can't cluster it, so add it to our child featureGroup
399
+ if (!layer.getLatLng) {
400
+ this._featureGroup.addLayer(layer);
401
+ continue;
402
+ }
403
+
404
+
332
405
  if (layer.__parent) {
333
406
  continue;
334
407
  }
@@ -336,6 +409,7 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
336
409
  }
337
410
  this._needsClustering = [];
338
411
 
412
+
339
413
  this._map.on('zoomend', this._zoomEnd, this);
340
414
  this._map.on('moveend', this._moveEnd, this);
341
415
 
@@ -358,8 +432,8 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
358
432
 
359
433
  //Overrides FeatureGroup.onRemove
360
434
  onRemove: function (map) {
361
- this._map.off('zoomend', this._zoomEnd, this);
362
- this._map.off('moveend', this._moveEnd, this);
435
+ map.off('zoomend', this._zoomEnd, this);
436
+ map.off('moveend', this._moveEnd, this);
363
437
 
364
438
  this._unbindEvents();
365
439
 
@@ -371,22 +445,28 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
371
445
  }
372
446
 
373
447
  //Clean up all the layers we added to the map
374
- for (var i in this._layers) {
375
- if (this._layers.hasOwnProperty(i)) {
376
- L.FeatureGroup.prototype.removeLayer.call(this, this._layers[i]);
377
- }
378
- }
448
+ this._featureGroup.onRemove(map);
449
+ this._nonPointGroup.onRemove(map);
450
+
451
+ this._featureGroup.clearLayers();
379
452
 
380
453
  this._map = null;
381
454
  },
382
455
 
456
+ getVisibleParent: function (marker) {
457
+ var vMarker = marker;
458
+ while (vMarker !== null && !vMarker._icon) {
459
+ vMarker = vMarker.__parent;
460
+ }
461
+ return vMarker;
462
+ },
383
463
 
384
464
  //Remove the given object from the given array
385
465
  _arraySplice: function (anArray, obj) {
386
466
  for (var i = anArray.length - 1; i >= 0; i--) {
387
467
  if (anArray[i] === obj) {
388
468
  anArray.splice(i, 1);
389
- return;
469
+ return true;
390
470
  }
391
471
  }
392
472
  },
@@ -396,6 +476,7 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
396
476
  _removeLayer: function (marker, removeFromDistanceGrid, dontUpdateMap) {
397
477
  var gridClusters = this._gridClusters,
398
478
  gridUnclustered = this._gridUnclustered,
479
+ fg = this._featureGroup,
399
480
  map = this._map;
400
481
 
401
482
  //Remove the marker from distance clusters it might be in
@@ -436,9 +517,9 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
436
517
 
437
518
  if (cluster._icon) {
438
519
  //Cluster is currently on the map, need to put the marker on the map instead
439
- L.FeatureGroup.prototype.removeLayer.call(this, cluster);
520
+ fg.removeLayer(cluster);
440
521
  if (!dontUpdateMap) {
441
- L.FeatureGroup.prototype.addLayer.call(this, otherMarker);
522
+ fg.addLayer(otherMarker);
442
523
  }
443
524
  }
444
525
  } else {
@@ -454,12 +535,12 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
454
535
  delete marker.__parent;
455
536
  },
456
537
 
457
- //Overrides FeatureGroup._propagateEvent
458
538
  _propagateEvent: function (e) {
459
- if (e.target instanceof L.MarkerCluster) {
539
+ if (e.layer instanceof L.MarkerCluster) {
460
540
  e.type = 'cluster' + e.type;
461
541
  }
462
- L.FeatureGroup.prototype._propagateEvent.call(this, e);
542
+
543
+ this.fire(e.type, e);
463
544
  },
464
545
 
465
546
  //Default functionality
@@ -479,58 +560,60 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
479
560
  },
480
561
 
481
562
  _bindEvents: function () {
482
- var shownPolygon = null,
483
- map = this._map,
484
-
485
- spiderfyOnMaxZoom = this.options.spiderfyOnMaxZoom,
486
- showCoverageOnHover = this.options.showCoverageOnHover,
487
- zoomToBoundsOnClick = this.options.zoomToBoundsOnClick;
563
+ var map = this._map,
564
+ spiderfyOnMaxZoom = this.options.spiderfyOnMaxZoom,
565
+ showCoverageOnHover = this.options.showCoverageOnHover,
566
+ zoomToBoundsOnClick = this.options.zoomToBoundsOnClick;
488
567
 
489
568
  //Zoom on cluster click or spiderfy if we are at the lowest level
490
569
  if (spiderfyOnMaxZoom || zoomToBoundsOnClick) {
491
- this.on('clusterclick', function (a) {
492
- if (map.getMaxZoom() === map.getZoom()) {
493
- if (spiderfyOnMaxZoom) {
494
- a.layer.spiderfy();
495
- }
496
- } else if (zoomToBoundsOnClick) {
497
- a.layer.zoomToBounds();
498
- }
499
- }, this);
570
+ this.on('clusterclick', this._zoomOrSpiderfy, this);
500
571
  }
501
572
 
502
573
  //Show convex hull (boundary) polygon on mouse over
503
574
  if (showCoverageOnHover) {
504
- this.on('clustermouseover', function (a) {
505
- if (this._inZoomAnimation) {
506
- return;
507
- }
508
- if (shownPolygon) {
509
- map.removeLayer(shownPolygon);
510
- }
511
- if (a.layer.getChildCount() > 2) {
512
- shownPolygon = new L.Polygon(a.layer.getConvexHull(), this.options.polygonOptions);
513
- map.addLayer(shownPolygon);
514
- }
515
- }, this);
516
- this.on('clustermouseout', function () {
517
- if (shownPolygon) {
518
- map.removeLayer(shownPolygon);
519
- shownPolygon = null;
520
- }
521
- }, this);
522
- map.on('zoomend', function () {
523
- if (shownPolygon) {
524
- map.removeLayer(shownPolygon);
525
- shownPolygon = null;
526
- }
527
- }, this);
528
- map.on('layerremove', function (opt) {
529
- if (shownPolygon && opt.layer === this) {
530
- map.removeLayer(shownPolygon);
531
- shownPolygon = null;
532
- }
533
- }, this);
575
+ this.on('clustermouseover', this._showCoverage, this);
576
+ this.on('clustermouseout', this._hideCoverage, this);
577
+ map.on('zoomend', this._hideCoverage, this);
578
+ map.on('layerremove', this._hideCoverageOnRemove, this);
579
+ }
580
+ },
581
+
582
+ _zoomOrSpiderfy: function (e) {
583
+ var map = this._map;
584
+ if (map.getMaxZoom() === map.getZoom()) {
585
+ if (this.options.spiderfyOnMaxZoom) {
586
+ e.layer.spiderfy();
587
+ }
588
+ } else if (this.options.zoomToBoundsOnClick) {
589
+ e.layer.zoomToBounds();
590
+ }
591
+ },
592
+
593
+ _showCoverage: function (e) {
594
+ var map = this._map;
595
+ if (this._inZoomAnimation) {
596
+ return;
597
+ }
598
+ if (this._shownPolygon) {
599
+ map.removeLayer(this._shownPolygon);
600
+ }
601
+ if (e.layer.getChildCount() > 2 && e.layer !== this._spiderfied) {
602
+ this._shownPolygon = new L.Polygon(e.layer.getConvexHull(), this.options.polygonOptions);
603
+ map.addLayer(this._shownPolygon);
604
+ }
605
+ },
606
+
607
+ _hideCoverage: function () {
608
+ if (this._shownPolygon) {
609
+ this._map.removeLayer(this._shownPolygon);
610
+ this._shownPolygon = null;
611
+ }
612
+ },
613
+
614
+ _hideCoverageOnRemove: function (e) {
615
+ if (e.layer === this) {
616
+ this._hideCoverage();
534
617
  }
535
618
  },
536
619
 
@@ -541,13 +624,13 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
541
624
  map = this._map;
542
625
 
543
626
  if (spiderfyOnMaxZoom || zoomToBoundsOnClick) {
544
- this.off('clusterclick', null, this);
627
+ this.off('clusterclick', this._zoomOrSpiderfy, this);
545
628
  }
546
629
  if (showCoverageOnHover) {
547
- this.off('clustermouseover', null, this);
548
- this.off('clustermouseout', null, this);
549
- map.off('zoomend', null, this);
550
- map.off('layerremove', null, this);
630
+ this.off('clustermouseover', this._showCoverage, this);
631
+ this.off('clustermouseout', this._hideCoverage, this);
632
+ map.off('zoomend', this._hideCoverage, this);
633
+ map.off('layerremove', this._hideCoverageOnRemove, this);
551
634
  }
552
635
  },
553
636
 
@@ -656,7 +739,7 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
656
739
 
657
740
  return;
658
741
  }
659
-
742
+
660
743
  //Didn't manage to cluster in at this zoom, record us as a marker here and continue upwards
661
744
  gridUnclustered[zoom].addObject(layer, markerPoint);
662
745
  }
@@ -684,9 +767,13 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
684
767
  this._moveEnd();
685
768
  }
686
769
  },
687
-
770
+
688
771
  //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)
689
772
  _getExpandedVisibleBounds: function () {
773
+ if (!this.options.removeOutsideVisibleBounds) {
774
+ return this.getBounds();
775
+ }
776
+
690
777
  var map = this._map,
691
778
  bounds = map.getBounds(),
692
779
  sw = bounds._southWest,
@@ -702,13 +789,13 @@ L.MarkerClusterGroup = L.FeatureGroup.extend({
702
789
  //Shared animation code
703
790
  _animationAddLayerNonAnimated: function (layer, newCluster) {
704
791
  if (newCluster === layer) {
705
- L.FeatureGroup.prototype.addLayer.call(this, layer);
792
+ this._featureGroup.addLayer(layer);
706
793
  } else if (newCluster._childCount === 2) {
707
794
  newCluster._addToMap();
708
795
 
709
796
  var markers = newCluster.getAllChildMarkers();
710
- L.FeatureGroup.prototype.removeLayer.call(this, markers[0]);
711
- L.FeatureGroup.prototype.removeLayer.call(this, markers[1]);
797
+ this._featureGroup.removeLayer(markers[0]);
798
+ this._featureGroup.removeLayer(markers[1]);
712
799
  } else {
713
800
  newCluster._updateIcon();
714
801
  }
@@ -749,6 +836,7 @@ L.MarkerClusterGroup.include(!L.DomUtil.TRANSITION ? {
749
836
  _animationZoomIn: function (previousZoomLevel, newZoomLevel) {
750
837
  var me = this,
751
838
  bounds = this._getExpandedVisibleBounds(),
839
+ fg = this._featureGroup,
752
840
  i;
753
841
 
754
842
  //Add all children of current clusters to map and remove those clusters from map
@@ -757,8 +845,12 @@ L.MarkerClusterGroup.include(!L.DomUtil.TRANSITION ? {
757
845
  markers = c._markers,
758
846
  m;
759
847
 
848
+ if (!bounds.contains(startPos)) {
849
+ startPos = null;
850
+ }
851
+
760
852
  if (c._isSingleParent() && previousZoomLevel + 1 === newZoomLevel) { //Immediately add the new child and remove us
761
- L.FeatureGroup.prototype.removeLayer.call(me, c);
853
+ fg.removeLayer(c);
762
854
  c._recursivelyAddChildrenToMap(null, newZoomLevel, bounds);
763
855
  } else {
764
856
  //Fade out old cluster
@@ -771,27 +863,22 @@ L.MarkerClusterGroup.include(!L.DomUtil.TRANSITION ? {
771
863
  for (i = markers.length - 1; i >= 0; i--) {
772
864
  m = markers[i];
773
865
  if (!bounds.contains(m._latlng)) {
774
- L.FeatureGroup.prototype.removeLayer.call(me, m);
866
+ fg.removeLayer(m);
775
867
  }
776
868
  }
777
869
 
778
870
  });
779
871
 
780
872
  this._forceLayout();
781
- var j, n;
782
873
 
783
874
  //Update opacities
784
875
  me._topClusterLevel._recursivelyBecomeVisible(bounds, newZoomLevel);
785
876
  //TODO Maybe? Update markers in _recursivelyBecomeVisible
786
- for (j in me._layers) {
787
- if (me._layers.hasOwnProperty(j)) {
788
- n = me._layers[j];
789
-
790
- if (!(n instanceof L.MarkerCluster) && n._icon) {
791
- n.setOpacity(1);
792
- }
877
+ fg.eachLayer(function (n) {
878
+ if (!(n instanceof L.MarkerCluster) && n._icon) {
879
+ n.setOpacity(1);
793
880
  }
794
- }
881
+ });
795
882
 
796
883
  //update the positions of the just added clusters/markers
797
884
  me._topClusterLevel._recursively(bounds, previousZoomLevel, newZoomLevel, function (c) {
@@ -803,12 +890,12 @@ L.MarkerClusterGroup.include(!L.DomUtil.TRANSITION ? {
803
890
  setTimeout(function () {
804
891
  //update the positions of the just added clusters/markers
805
892
  me._topClusterLevel._recursively(bounds, previousZoomLevel, 0, function (c) {
806
- L.FeatureGroup.prototype.removeLayer.call(me, c);
893
+ fg.removeLayer(c);
807
894
  c.setOpacity(1);
808
895
  });
809
896
 
810
897
  me._animationEnd();
811
- }, 250);
898
+ }, 200);
812
899
  },
813
900
 
814
901
  _animationZoomOut: function (previousZoomLevel, newZoomLevel) {
@@ -841,20 +928,19 @@ L.MarkerClusterGroup.include(!L.DomUtil.TRANSITION ? {
841
928
  //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
842
929
  m.setLatLng(m.getLatLng());
843
930
  m.setOpacity(1);
844
-
845
- return;
931
+ } else {
932
+ cluster._recursively(bounds, newZoomLevel, 0, function (c) {
933
+ c._recursivelyRemoveChildrenFromMap(bounds, previousZoomLevel + 1);
934
+ });
846
935
  }
847
-
848
- cluster._recursively(bounds, newZoomLevel, 0, function (c) {
849
- c._recursivelyRemoveChildrenFromMap(bounds, previousZoomLevel + 1);
850
- });
851
936
  me._animationEnd();
852
- }, 250);
937
+ }, 200);
853
938
  },
854
939
  _animationAddLayer: function (layer, newCluster) {
855
- var me = this;
940
+ var me = this,
941
+ fg = this._featureGroup;
856
942
 
857
- L.FeatureGroup.prototype.addLayer.call(this, layer);
943
+ fg.addLayer(layer);
858
944
  if (newCluster !== layer) {
859
945
  if (newCluster._childCount > 2) { //Was already a cluster
860
946
 
@@ -866,11 +952,11 @@ L.MarkerClusterGroup.include(!L.DomUtil.TRANSITION ? {
866
952
  layer.setOpacity(0);
867
953
 
868
954
  setTimeout(function () {
869
- L.FeatureGroup.prototype.removeLayer.call(me, layer);
955
+ fg.removeLayer(layer);
870
956
  layer.setOpacity(1);
871
957
 
872
958
  me._animationEnd();
873
- }, 250);
959
+ }, 200);
874
960
 
875
961
  } else { //Just became a cluster
876
962
  this._forceLayout();
@@ -891,6 +977,10 @@ L.MarkerClusterGroup.include(!L.DomUtil.TRANSITION ? {
891
977
  }
892
978
  });
893
979
 
980
+ L.markerClusterGroup = function (options) {
981
+ return new L.MarkerClusterGroup(options);
982
+ };
983
+
894
984
 
895
985
  L.MarkerCluster = L.Marker.extend({
896
986
  initialize: function (group, zoom, a, b) {
@@ -941,6 +1031,11 @@ L.MarkerCluster = L.Marker.extend({
941
1031
  this._group._map.fitBounds(this._bounds);
942
1032
  },
943
1033
 
1034
+ getBounds: function () {
1035
+ var bounds = new L.LatLngBounds();
1036
+ bounds.extend(this._bounds);
1037
+ return bounds;
1038
+ },
944
1039
 
945
1040
  _updateIcon: function () {
946
1041
  this._iconNeedsUpdate = true;
@@ -1021,9 +1116,9 @@ L.MarkerCluster = L.Marker.extend({
1021
1116
  this._backupLatlng = this._latlng;
1022
1117
  this.setLatLng(startPos);
1023
1118
  }
1024
- L.FeatureGroup.prototype.addLayer.call(this._group, this);
1119
+ this._group._featureGroup.addLayer(this);
1025
1120
  },
1026
-
1121
+
1027
1122
  _recursivelyAnimateChildrenIn: function (bounds, center, maxZoom) {
1028
1123
  this._recursively(bounds, 0, maxZoom - 1,
1029
1124
  function (c) {
@@ -1097,10 +1192,12 @@ L.MarkerCluster = L.Marker.extend({
1097
1192
  nm._backupLatlng = nm.getLatLng();
1098
1193
 
1099
1194
  nm.setLatLng(startPos);
1100
- nm.setOpacity(0);
1195
+ if (nm.setOpacity) {
1196
+ nm.setOpacity(0);
1197
+ }
1101
1198
  }
1102
1199
 
1103
- L.FeatureGroup.prototype.addLayer.call(c._group, nm);
1200
+ c._group._featureGroup.addLayer(nm);
1104
1201
  }
1105
1202
  },
1106
1203
  function (c) {
@@ -1147,8 +1244,10 @@ L.MarkerCluster = L.Marker.extend({
1147
1244
  for (i = c._markers.length - 1; i >= 0; i--) {
1148
1245
  m = c._markers[i];
1149
1246
  if (!exceptBounds || !exceptBounds.contains(m._latlng)) {
1150
- L.FeatureGroup.prototype.removeLayer.call(c._group, m);
1151
- m.setOpacity(1);
1247
+ c._group._featureGroup.removeLayer(m);
1248
+ if (m.setOpacity) {
1249
+ m.setOpacity(1);
1250
+ }
1152
1251
  }
1153
1252
  }
1154
1253
  },
@@ -1157,8 +1256,10 @@ L.MarkerCluster = L.Marker.extend({
1157
1256
  for (i = c._childClusters.length - 1; i >= 0; i--) {
1158
1257
  m = c._childClusters[i];
1159
1258
  if (!exceptBounds || !exceptBounds.contains(m._latlng)) {
1160
- L.FeatureGroup.prototype.removeLayer.call(c._group, m);
1161
- m.setOpacity(1);
1259
+ c._group._featureGroup.removeLayer(m);
1260
+ if (m.setOpacity) {
1261
+ m.setOpacity(1);
1262
+ }
1162
1263
  }
1163
1264
  }
1164
1265
  }
@@ -1288,20 +1389,16 @@ L.DistanceGrid.prototype = {
1288
1389
  grid = this._grid;
1289
1390
 
1290
1391
  for (i in grid) {
1291
- if (grid.hasOwnProperty(i)) {
1292
- row = grid[i];
1392
+ row = grid[i];
1293
1393
 
1294
- for (j in row) {
1295
- if (row.hasOwnProperty(j)) {
1296
- cell = row[j];
1394
+ for (j in row) {
1395
+ cell = row[j];
1297
1396
 
1298
- for (k = 0, len = cell.length; k < len; k++) {
1299
- removed = fn.call(context, cell[k]);
1300
- if (removed) {
1301
- k--;
1302
- len--;
1303
- }
1304
- }
1397
+ for (k = 0, len = cell.length; k < len; k++) {
1398
+ removed = fn.call(context, cell[k]);
1399
+ if (removed) {
1400
+ k--;
1401
+ len--;
1305
1402
  }
1306
1403
  }
1307
1404
  }
@@ -1561,6 +1658,34 @@ L.MarkerCluster.include({
1561
1658
  legLength += this._2PI * lengthFactor / angle;
1562
1659
  }
1563
1660
  return res;
1661
+ },
1662
+
1663
+ _noanimationUnspiderfy: function () {
1664
+ var group = this._group,
1665
+ map = group._map,
1666
+ fg = group._featureGroup,
1667
+ childMarkers = this.getAllChildMarkers(),
1668
+ m, i;
1669
+
1670
+ this.setOpacity(1);
1671
+ for (i = childMarkers.length - 1; i >= 0; i--) {
1672
+ m = childMarkers[i];
1673
+
1674
+ fg.removeLayer(m);
1675
+
1676
+ if (m._preSpiderfyLatlng) {
1677
+ m.setLatLng(m._preSpiderfyLatlng);
1678
+ delete m._preSpiderfyLatlng;
1679
+ }
1680
+ if (m.setZIndexOffset) {
1681
+ m.setZIndexOffset(0);
1682
+ }
1683
+
1684
+ if (m._spiderLeg) {
1685
+ map.removeLayer(m._spiderLeg);
1686
+ delete m._spiderLeg;
1687
+ }
1688
+ }
1564
1689
  }
1565
1690
  });
1566
1691
 
@@ -1569,6 +1694,7 @@ L.MarkerCluster.include(!L.DomUtil.TRANSITION ? {
1569
1694
  _animationSpiderfy: function (childMarkers, positions) {
1570
1695
  var group = this._group,
1571
1696
  map = group._map,
1697
+ fg = group._featureGroup,
1572
1698
  i, m, leg, newPos;
1573
1699
 
1574
1700
  for (i = childMarkers.length - 1; i >= 0; i--) {
@@ -1577,9 +1703,11 @@ L.MarkerCluster.include(!L.DomUtil.TRANSITION ? {
1577
1703
 
1578
1704
  m._preSpiderfyLatlng = m._latlng;
1579
1705
  m.setLatLng(newPos);
1580
- m.setZIndexOffset(1000000); //Make these appear on top of EVERYTHING
1706
+ if (m.setZIndexOffset) {
1707
+ m.setZIndexOffset(1000000); //Make these appear on top of EVERYTHING
1708
+ }
1581
1709
 
1582
- L.FeatureGroup.prototype.addLayer.call(group, m);
1710
+ fg.addLayer(m);
1583
1711
 
1584
1712
 
1585
1713
  leg = new L.Polyline([this._latlng, newPos], { weight: 1.5, color: '#222' });
@@ -1591,24 +1719,7 @@ L.MarkerCluster.include(!L.DomUtil.TRANSITION ? {
1591
1719
  },
1592
1720
 
1593
1721
  _animationUnspiderfy: function () {
1594
- var group = this._group,
1595
- map = group._map,
1596
- childMarkers = this.getAllChildMarkers(),
1597
- m, i;
1598
-
1599
- this.setOpacity(1);
1600
- for (i = childMarkers.length - 1; i >= 0; i--) {
1601
- m = childMarkers[i];
1602
-
1603
- L.FeatureGroup.prototype.removeLayer.call(group, m);
1604
-
1605
- m.setLatLng(m._preSpiderfyLatlng);
1606
- delete m._preSpiderfyLatlng;
1607
- m.setZIndexOffset(0);
1608
-
1609
- map.removeLayer(m._spiderLeg);
1610
- delete m._spiderLeg;
1611
- }
1722
+ this._noanimationUnspiderfy();
1612
1723
  }
1613
1724
  } : {
1614
1725
  //Animated versions here
@@ -1620,6 +1731,7 @@ L.MarkerCluster.include(!L.DomUtil.TRANSITION ? {
1620
1731
  var me = this,
1621
1732
  group = this._group,
1622
1733
  map = group._map,
1734
+ fg = group._featureGroup,
1623
1735
  thisLayerPos = map.latLngToLayerPoint(this._latlng),
1624
1736
  i, m, leg, newPos;
1625
1737
 
@@ -1627,12 +1739,18 @@ L.MarkerCluster.include(!L.DomUtil.TRANSITION ? {
1627
1739
  for (i = childMarkers.length - 1; i >= 0; i--) {
1628
1740
  m = childMarkers[i];
1629
1741
 
1630
- m.setZIndexOffset(1000000); //Make these appear on top of EVERYTHING
1631
- m.setOpacity(0);
1632
-
1633
- L.FeatureGroup.prototype.addLayer.call(group, m);
1742
+ //If it is a marker, add it now and we'll animate it out
1743
+ if (m.setOpacity) {
1744
+ m.setZIndexOffset(1000000); //Make these appear on top of EVERYTHING
1745
+ m.setOpacity(0);
1746
+
1747
+ fg.addLayer(m);
1634
1748
 
1635
- m._setPos(thisLayerPos);
1749
+ m._setPos(thisLayerPos);
1750
+ } else {
1751
+ //Vectors just get immediately added
1752
+ fg.addLayer(m);
1753
+ }
1636
1754
  }
1637
1755
 
1638
1756
  group._forceLayout();
@@ -1649,7 +1767,10 @@ L.MarkerCluster.include(!L.DomUtil.TRANSITION ? {
1649
1767
  //Move marker to new position
1650
1768
  m._preSpiderfyLatlng = m._latlng;
1651
1769
  m.setLatLng(newPos);
1652
- m.setOpacity(1);
1770
+
1771
+ if (m.setOpacity) {
1772
+ m.setOpacity(1);
1773
+ }
1653
1774
 
1654
1775
 
1655
1776
  //Add Legs.
@@ -1709,19 +1830,20 @@ L.MarkerCluster.include(!L.DomUtil.TRANSITION ? {
1709
1830
  setTimeout(function () {
1710
1831
  group._animationEnd();
1711
1832
  group.fire('spiderfied');
1712
- }, 250);
1833
+ }, 200);
1713
1834
  },
1714
1835
 
1715
1836
  _animationUnspiderfy: function (zoomDetails) {
1716
1837
  var group = this._group,
1717
1838
  map = group._map,
1839
+ fg = group._featureGroup,
1718
1840
  thisLayerPos = zoomDetails ? map._latLngToNewLayerPoint(this._latlng, zoomDetails.zoom, zoomDetails.center) : map.latLngToLayerPoint(this._latlng),
1719
1841
  childMarkers = this.getAllChildMarkers(),
1720
1842
  svg = L.Path.SVG && this.SVG_ANIMATION,
1721
1843
  m, i, a;
1722
1844
 
1723
1845
  group._animationStart();
1724
-
1846
+
1725
1847
  //Make us visible and bring the child markers back in
1726
1848
  this.setOpacity(1);
1727
1849
  for (i = childMarkers.length - 1; i >= 0; i--) {
@@ -1736,9 +1858,12 @@ L.MarkerCluster.include(!L.DomUtil.TRANSITION ? {
1736
1858
  m.setLatLng(m._preSpiderfyLatlng);
1737
1859
  delete m._preSpiderfyLatlng;
1738
1860
  //Hack override the location to be our center
1739
- m._setPos(thisLayerPos);
1740
-
1741
- m.setOpacity(0);
1861
+ if (m.setOpacity) {
1862
+ m._setPos(thisLayerPos);
1863
+ m.setOpacity(0);
1864
+ } else {
1865
+ fg.removeLayer(m);
1866
+ }
1742
1867
 
1743
1868
  //Animate the spider legs back in
1744
1869
  if (svg) {
@@ -1776,18 +1901,20 @@ L.MarkerCluster.include(!L.DomUtil.TRANSITION ? {
1776
1901
  }
1777
1902
 
1778
1903
 
1779
- m.setOpacity(1);
1780
- m.setZIndexOffset(0);
1904
+ if (m.setOpacity) {
1905
+ m.setOpacity(1);
1906
+ m.setZIndexOffset(0);
1907
+ }
1781
1908
 
1782
1909
  if (stillThereChildCount > 1) {
1783
- L.FeatureGroup.prototype.removeLayer.call(group, m);
1910
+ fg.removeLayer(m);
1784
1911
  }
1785
1912
 
1786
1913
  map.removeLayer(m._spiderLeg);
1787
1914
  delete m._spiderLeg;
1788
1915
  }
1789
1916
  group._animationEnd();
1790
- }, 250);
1917
+ }, 200);
1791
1918
  }
1792
1919
  });
1793
1920
 
@@ -1854,10 +1981,16 @@ L.MarkerClusterGroup.include({
1854
1981
  }
1855
1982
  },
1856
1983
 
1984
+ _noanimationUnspiderfy: function () {
1985
+ if (this._spiderfied) {
1986
+ this._spiderfied._noanimationUnspiderfy();
1987
+ }
1988
+ },
1989
+
1857
1990
  //If the given layer is currently being spiderfied then we unspiderfy it so it isn't on the map anymore etc
1858
1991
  _unspiderfyLayer: function (layer) {
1859
1992
  if (layer._spiderLeg) {
1860
- L.FeatureGroup.prototype.removeLayer.call(this, layer);
1993
+ this._featureGroup.removeLayer(layer);
1861
1994
 
1862
1995
  layer.setOpacity(1);
1863
1996
  //Position will be fixed up immediately in _animationUnspiderfy
@@ -1870,5 +2003,4 @@ L.MarkerClusterGroup.include({
1870
2003
  });
1871
2004
 
1872
2005
 
1873
-
1874
- }(this));
2006
+ }(window, document));