leaflet-rotate 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13,12 +13,24 @@
13
13
 
14
14
  L.extend(L.DomUtil, {
15
15
 
16
+ /**
17
+ * Resets the 3D CSS transform of `el` so it is
18
+ * translated by `offset` pixels and optionally
19
+ * scaled by `scale`. Does not have an effect if
20
+ * the browser doesn't support 3D CSS transforms.
21
+ *
22
+ * @param {HTMLElement} el
23
+ * @param {L.Point} offset
24
+ * @param {Number} scale
25
+ * @param {Number} bearing
26
+ * @param {L.Point} pivot
27
+ */
16
28
  setTransform: function(el, offset, scale, bearing, pivot) {
17
29
  var pos = offset || new L.Point(0, 0);
18
30
 
19
31
  if (!bearing) {
20
32
  offset = pos._round();
21
- return domUtilProto.setTransform.call(this, el, offset, scale);
33
+ return domUtilProto.setTransform.apply(this, arguments);
22
34
  }
23
35
 
24
36
  pos = pos.rotateFrom(bearing, pivot);
@@ -29,9 +41,21 @@
29
41
  ' rotate(' + bearing + 'rad)';
30
42
  },
31
43
 
32
- setPosition: function(el, point, bearing, pivot) { // (HTMLElement, Point[, Boolean])
44
+ /**
45
+ * Sets the position of `el` to coordinates specified by
46
+ * `position`, using CSS translate or top/left positioning
47
+ * depending on the browser (used by Leaflet internally
48
+ * to position its layers).
49
+ *
50
+ * @param {HTMLElement} el
51
+ * @param {L.Point} point
52
+ * @param {Number} bearing
53
+ * @param {L.Point} pivot
54
+ * @param {Number} scale
55
+ */
56
+ setPosition: function(el, point, bearing, pivot, scale) {
33
57
  if (!bearing) {
34
- return domUtilProto.setPosition.call(this, el, point);
58
+ return domUtilProto.setPosition.apply(this, arguments);
35
59
  }
36
60
 
37
61
  /*eslint-disable */
@@ -39,15 +63,21 @@
39
63
  /*eslint-enable */
40
64
 
41
65
  if (L.Browser.any3d) {
42
- L.DomUtil.setTransform(el, point, undefined, bearing, pivot);
66
+ L.DomUtil.setTransform(el, point, scale, bearing, pivot);
43
67
  } else {
44
68
  el.style.left = point.x + 'px';
45
69
  el.style.top = point.y + 'px';
46
70
  }
47
71
  },
48
72
 
49
- // Constants for rotation
73
+ /**
74
+ * @constant radians = degrees × π/180°
75
+ */
50
76
  DEG_TO_RAD: Math.PI / 180,
77
+
78
+ /**
79
+ * @constant degrees = radians × 180°/π
80
+ */
51
81
  RAD_TO_DEG: 180 / Math.PI,
52
82
 
53
83
  });
@@ -58,8 +88,15 @@
58
88
  * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/dom/Draggable.js
59
89
  */
60
90
 
91
+ /**
92
+ * A class for making DOM elements draggable (including touch support).
93
+ * Used internally for map and marker dragging. Only works for elements
94
+ * that were positioned with [`L.DomUtil.setPosition`](#domutil-setposition).
95
+ */
96
+
61
97
  L.Draggable.include({
62
98
 
99
+ /** @TODO */
63
100
  // updateMapBearing: function(mapBearing) {
64
101
  // this._mapBearing = mapBearing;
65
102
  // },
@@ -94,6 +131,11 @@
94
131
  * 3. add (pivot.x, pivot.y) back
95
132
  *
96
133
  * same as `this.subtract(pivot).rotate(theta).add(pivot)`
134
+ *
135
+ * @param {Number} theta
136
+ * @param {L.Point} pivot
137
+ *
138
+ * @returns {L.Point}
97
139
  */
98
140
  rotateFrom: function(theta, pivot) {
99
141
  if (!theta) { return this; }
@@ -122,16 +164,23 @@
122
164
 
123
165
  L.DivOverlay.include({
124
166
 
167
+ /**
168
+ * Update L.Popup and L.Tooltip anchor positions after
169
+ * the map is moved by calling `map.setBearing(theta)`
170
+ *
171
+ * @listens L.Map~rotate
172
+ */
125
173
  getEvents: function() {
126
- return L.extend(divOverlayProto.getEvents.call(this), { rotate: this._updatePosition });
174
+ return L.extend(divOverlayProto.getEvents.apply(this, arguments), { rotate: this._updatePosition });
127
175
  },
128
176
 
177
+ /**
178
+ * 0. update element anchor point (divOverlayProto v1.9.3)
179
+ * 1. rotate around anchor point (subtract anchor -> rotate point -> add anchor)
180
+ */
129
181
  _updatePosition: function() {
130
- // 0. update anchor (leaflet v1.9.3)
131
- divOverlayProto._updatePosition.call(this);
132
- // 1. subtract anchor
133
- // 2. rotate element
134
- // 3. restore anchor
182
+ if (!this._map) { return; }
183
+ divOverlayProto._updatePosition.apply(this, arguments);
135
184
  if (this._map && this._map._rotate && this._zoomAnimated) {
136
185
  var anchor = this._getAnchor();
137
186
  var pos = L.DomUtil.getPosition(this._container).subtract(anchor);
@@ -152,12 +201,12 @@
152
201
 
153
202
  L.Popup.include({
154
203
 
204
+ /**
205
+ * 0. update element anchor point (popupProto v1.9.3)
206
+ * 1. rotate around anchor point (subtract anchor -> rotate point -> add anchor)
207
+ */
155
208
  _animateZoom: function(e) {
156
- // 0. update anchor (leaflet v1.9.3)
157
- popupProto._animateZoom.call(this, e);
158
- // 1. subtract anchor
159
- // 2. rotate element
160
- // 3. restore anchor
209
+ popupProto._animateZoom.apply(this, arguments);
161
210
  if (this._map && this._map._rotate) {
162
211
  var anchor = this._getAnchor();
163
212
  var pos = L.DomUtil.getPosition(this._container).subtract(anchor);
@@ -166,7 +215,7 @@
166
215
  },
167
216
 
168
217
  /**
169
- * Hot fix for L.Popup.mergeOptions({ keepInView: true, });
218
+ * Fix for L.popup({ keepInView = true })
170
219
  *
171
220
  * @see https://github.com/fnicollet/Leaflet/pull/21
172
221
  */
@@ -188,8 +237,8 @@
188
237
 
189
238
  layerPos._add(L.DomUtil.getPosition(this._container));
190
239
 
191
- // var containerPos = map.layerPointToContainerPoint(layerPos);
192
240
  /** @TODO use popupProto._adjustPan */
241
+ // var containerPos = map.layerPointToContainerPoint(layerPos);
193
242
  var containerPos = layerPos._add(this._map._getMapPanePos()),
194
243
  padding = L.point(this.options.autoPanPadding),
195
244
  paddingTL = L.point(this.options.autoPanPaddingTopLeft || padding),
@@ -240,7 +289,7 @@
240
289
 
241
290
  _animateZoom: function(e) {
242
291
  if (!this._map._rotate) {
243
- return tooltipProto._animateZoom.call(this, e);
292
+ return tooltipProto._animateZoom.apply(this, arguments);
244
293
  }
245
294
  var pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center);
246
295
 
@@ -250,7 +299,7 @@
250
299
 
251
300
  _updatePosition: function() {
252
301
  if (!this._map._rotate) {
253
- return tooltipProto._updatePosition.call(this);
302
+ return tooltipProto._updatePosition.apply(this, arguments);
254
303
  }
255
304
  var pos = this._map.latLngToLayerPoint(this._latlng);
256
305
 
@@ -304,20 +353,35 @@
304
353
  * @external L.Handler.MarkerDrag
305
354
  *
306
355
  * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/layer/marker/Marker.js
356
+ * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/layer/marker/Marker.Drag.js
357
+ * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/dom/Draggable.js
307
358
  */
308
359
 
309
360
  const markerProto = L.extend({}, L.Marker.prototype);
310
361
 
311
362
  L.Marker.mergeOptions({
312
363
 
313
- // @option rotation: Number = 0
314
- // Rotation of this marker in rad
364
+ /**
365
+ * Rotation of this marker in rad
366
+ *
367
+ * @type {Number}
368
+ */
315
369
  rotation: 0,
316
370
 
317
- // @option rotateWithView: Boolean = false
318
- // Rotate this marker when map rotates
371
+ /**
372
+ * Rotate this marker when map rotates
373
+ *
374
+ * @type {Boolean}
375
+ */
319
376
  rotateWithView: false,
320
377
 
378
+ /**
379
+ * Scale of the marker icon
380
+ *
381
+ * @type {Number}
382
+ */
383
+ scale: undefined,
384
+
321
385
  });
322
386
 
323
387
  var markerDragProto; // retrived at runtime (see below: L.Marker::_initInteraction())
@@ -326,7 +390,7 @@
326
390
 
327
391
  // _onDragStart: function() {
328
392
  // if (!this._marker._map._rotate) {
329
- // return markerDragProto._onDragStart.call(this)
393
+ // return markerDragProto._onDragStart.apply(this, arguments);
330
394
  // }
331
395
  // this._draggable.updateMapBearing(this._marker._map._bearing);
332
396
  // },
@@ -369,24 +433,25 @@
369
433
  if (this._marker._map._rotate) {
370
434
  this._marker.update();
371
435
  }
372
- markerDragProto._onDragEnd.call(this, e);
436
+ markerDragProto._onDragEnd.apply(this, arguments);
373
437
  },
374
438
 
375
439
  };
376
440
 
377
441
  L.Marker.include({
378
442
 
443
+ /**
444
+ * Update L.Marker anchor position after the map
445
+ * is moved by calling `map.setBearing(theta)`
446
+ *
447
+ * @listens L.Map~rotate
448
+ */
379
449
  getEvents: function() {
380
- return L.extend(markerProto.getEvents.call(this), { rotate: this.update });
381
- },
382
-
383
- onAdd: function(map) {
384
- markerProto.onAdd.call(this, map);
385
- map.on('rotate', this.update, this);
450
+ return L.extend(markerProto.getEvents.apply(this, arguments), { rotate: this.update });
386
451
  },
387
452
 
388
453
  _initInteraction: function() {
389
- var ret = markerProto._initInteraction.call(this);
454
+ var ret = markerProto._initInteraction.apply(this, arguments);
390
455
  if (this.dragging && this.dragging.enabled() && this._map && this._map._rotate) {
391
456
  // L.Handler.MarkerDrag is used internally by L.Marker to make the markers draggable
392
457
  markerDragProto = markerDragProto || Object.getPrototypeOf(this.dragging);
@@ -416,12 +481,12 @@
416
481
 
417
482
  /** @TODO use markerProto._setPos */
418
483
  if (this._icon) {
419
- L.DomUtil.setPosition(this._icon, pos, bearing, pos);
484
+ L.DomUtil.setPosition(this._icon, pos, bearing, pos, this.options.scale);
420
485
  }
421
486
 
422
487
  /** @TODO use markerProto._setPos */
423
488
  if (this._shadow) {
424
- L.DomUtil.setPosition(this._shadow, pos, bearing, pos);
489
+ L.DomUtil.setPosition(this._shadow, pos, bearing, pos, this.options.scale);
425
490
  }
426
491
 
427
492
  this._zIndex = pos.y + this.options.zIndexOffset;
@@ -429,12 +494,12 @@
429
494
  this._resetZIndex();
430
495
  },
431
496
 
432
- _updateZIndex: function(offset) {
433
- if (!this._map._rotate) {
434
- return markerProto._updateZIndex.call(this, offset)
435
- }
436
- this._icon.style.zIndex = Math.round(this._zIndex + offset);
437
- },
497
+ // _updateZIndex: function(offset) {
498
+ // if (!this._map._rotate) {
499
+ // return markerProto._updateZIndex.apply(this, arguments);
500
+ // }
501
+ // this._icon.style.zIndex = Math.round(this._zIndex + offset);
502
+ // },
438
503
 
439
504
  setRotation: function(rotation) {
440
505
  this.options.rotation = rotation;
@@ -453,8 +518,14 @@
453
518
 
454
519
  L.GridLayer.include({
455
520
 
521
+ /**
522
+ * Redraw L.TileLayer bounds after the map is
523
+ * moved by just calling `map.setBearing(theta)`
524
+ *
525
+ * @listens L.Map~rotate
526
+ */
456
527
  getEvents: function() {
457
- var events = gridLayerProto.getEvents.call(this);
528
+ var events = gridLayerProto.getEvents.apply(this, arguments);
458
529
  if (this._map._rotate && !this.options.updateWhenIdle) {
459
530
  if (!this._onRotate) {
460
531
  this._onRotate = L.Util.throttle(this._onMoveEnd, this.options.updateInterval, this);
@@ -466,7 +537,7 @@
466
537
 
467
538
  _getTiledPixelBounds: function(center) {
468
539
  if (!this._map._rotate) {
469
- return gridLayerProto._getTiledPixelBounds.call(this, center);
540
+ return gridLayerProto._getTiledPixelBounds.apply(this, arguments);
470
541
  }
471
542
 
472
543
  return this._map._getNewPixelBounds(center, this._tileZoom);
@@ -474,35 +545,6 @@
474
545
 
475
546
  });
476
547
 
477
- /**
478
- * @external L.Canvas
479
- *
480
- * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/layer/vector/Canvas.js
481
- */
482
-
483
- L.extend({}, L.Canvas.prototype);
484
-
485
- L.Canvas.include({
486
-
487
- // onAdd: function() {
488
- // canvasProto.onAdd.call(this);
489
- // // When rotating the canvas itself, it is cleared by some weird reason, so redraw.
490
- // this._map.on('rotate', this._redraw, this);
491
- // },
492
-
493
- // onRemove: function() {
494
- // canvasProto.onRemove.call(this);
495
- // this._map.off('rotate', this._redraw, this);
496
- // },
497
-
498
- // _update: function() {
499
- // canvasProto._update.call(this);
500
- // // Tell paths to redraw themselves
501
- // this.fire('update')
502
- // },
503
-
504
- });
505
-
506
548
  /**
507
549
  * @external L.Renderer
508
550
  *
@@ -513,15 +555,15 @@
513
555
 
514
556
  L.Renderer.include({
515
557
 
516
- // onAdd: function() {
517
- // rendererProto.onAdd.call(this);
518
- // // this._map.on('rotate', this._update, this);
519
- // },
520
-
521
- // onRemove: function() {
522
- // rendererProto.onRemove.call(this);
523
- // // this._map.off('rotate', this._update, this);
524
- // },
558
+ /**
559
+ * Redraw L.Canvas and L.SVG renderer bounds after the
560
+ * map is moved by just calling `map.setBearing(theta)`
561
+ *
562
+ * @listens L.Map~rotate
563
+ */
564
+ getEvents: function() {
565
+ return L.extend(rendererProto.getEvents.apply(this, arguments), { rotate: this._update });
566
+ },
525
567
 
526
568
  /**
527
569
  * @TODO rechek this changes from leaflet@v1.9.3
@@ -530,7 +572,7 @@
530
572
  */
531
573
  _updateTransform: function(center, zoom) {
532
574
  if (!this._map._rotate) {
533
- return rendererProto._updateTransform.call(this, center, zoom);
575
+ return rendererProto._updateTransform.apply(this, arguments);
534
576
  }
535
577
  var scale = this._map.getZoomScale(zoom, this._zoom),
536
578
  offset = this._map._latLngToNewLayerPoint(this._topLeft, zoom, center);
@@ -543,7 +585,7 @@
543
585
 
544
586
  _update: function() {
545
587
  if (!this._map._rotate) {
546
- return rendererProto._update.call(this);
588
+ return rendererProto._update.apply(this, arguments);
547
589
  }
548
590
  // Update pixel bounds of renderer container (for positioning/sizing/clipping later)
549
591
  // Subclasses are responsible of firing the 'update' event.
@@ -555,25 +597,6 @@
555
597
 
556
598
  });
557
599
 
558
- /**
559
- * @external L.SVG
560
- *
561
- * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/layer/vector/SVG.js
562
- */
563
-
564
- L.extend({}, L.SVG.prototype);
565
-
566
- L.SVG.include({
567
-
568
- // _update: function() {
569
- // svgProto._update.call(this);
570
- // if (this._map._rotate) {
571
- // this.fire('update');
572
- // }
573
- // },
574
-
575
- });
576
-
577
600
  /**
578
601
  * @external L.Map
579
602
  *
@@ -595,7 +618,7 @@
595
618
  this._rotate = true;
596
619
  this._bearing = 0;
597
620
  }
598
- mapProto.initialize.call(this, id, options);
621
+ mapProto.initialize.apply(this, arguments);
599
622
  if(this.options.rotate){
600
623
  this.setBearing(this.options.bearing);
601
624
  }
@@ -611,7 +634,7 @@
611
634
  */
612
635
  containerPointToLayerPoint: function(point) {
613
636
  if (!this._rotate) {
614
- return mapProto.containerPointToLayerPoint.call(this, point);
637
+ return mapProto.containerPointToLayerPoint.apply(this, arguments);
615
638
  }
616
639
  return L.point(point)
617
640
  .subtract(this._getMapPanePos())
@@ -626,9 +649,9 @@
626
649
  * @param {L.Point} point pixel screen coordinates
627
650
  * @returns {L.Point} transformed pixel point
628
651
  */
629
- layerPointToContainerPoint: function(point) { // (Point)
652
+ layerPointToContainerPoint: function(point) {
630
653
  if (!this._rotate) {
631
- return mapProto.layerPointToContainerPoint.call(this, point);
654
+ return mapProto.layerPointToContainerPoint.apply(this, arguments);
632
655
  }
633
656
  return L.point(point)
634
657
  .add(this._getRotatePanePos())
@@ -645,6 +668,8 @@
645
668
  *
646
669
  * @param {L.Point} point pixel screen coordinates
647
670
  * @returns {L.Point}
671
+ *
672
+ * @since leaflet-rotate (v0.1)
648
673
  */
649
674
  rotatedPointToMapPanePoint: function(point) {
650
675
  return L.point(point)
@@ -660,6 +685,8 @@
660
685
  * (norotatePane) --> (rotatePane)
661
686
  *
662
687
  * @param {L.Point} point pixel screen coordinates
688
+ *
689
+ * @since leaflet-rotate (v0.1)
663
690
  */
664
691
  mapPanePointToRotatedPoint: function(point) {
665
692
  return L.point(point)
@@ -667,6 +694,31 @@
667
694
  .rotate(-this._bearing);
668
695
  },
669
696
 
697
+ /**
698
+ * Given latlng bounds, returns the bounds in projected pixel
699
+ * relative to the map container.
700
+ *
701
+ * @see https://github.com/ronikar/Leaflet/blob/5c480ef959b947c3beed7065425a5a36c486262b/src/map/Map.js#L1114-L1135
702
+ *
703
+ * @param {L.LatLngBounds} bounds
704
+ * @returns {L.Bounds}
705
+ *
706
+ * @since leaflet-rotate (v0.2)
707
+ */
708
+ mapBoundsToContainerBounds: function (bounds) {
709
+ if (!this._rotate && mapProto.mapBoundsToContainerBounds) {
710
+ return mapProto.mapBoundsToContainerBounds.apply(this, arguments);
711
+ }
712
+ const nw = this.latLngToContainerPoint(bounds.getNorthWest()),
713
+ ne = this.latLngToContainerPoint(bounds.getNorthEast()),
714
+ sw = this.latLngToContainerPoint(bounds.getSouthWest()),
715
+ se = this.latLngToContainerPoint(bounds.getSouthEast());
716
+ return L.bounds([
717
+ L.point(Math.min(nw.x, ne.x, se.x, sw.x), Math.min(nw.y, ne.y, se.y, sw.y)), // [ minX, minY ]
718
+ L.point(Math.max(nw.x, ne.x, se.x, sw.x), Math.max(nw.y, ne.y, se.y, sw.y)) // [ maxX, maxY ]
719
+ ]);
720
+ },
721
+
670
722
  /**
671
723
  * Returns geographical bounds visible in the current map view
672
724
  *
@@ -679,7 +731,7 @@
679
731
  */
680
732
  getBounds: function() {
681
733
  if (!this._rotate) {
682
- return mapProto.getBounds.call(this);
734
+ return mapProto.getBounds.apply(this, arguments);
683
735
  }
684
736
 
685
737
  // SEE: https://github.com/fnicollet/Leaflet/pull/22
@@ -722,6 +774,8 @@
722
774
  * Change map rotation
723
775
  *
724
776
  * @param {number} theta map degrees
777
+ *
778
+ * @since leaflet-rotate (v0.1)
725
779
  */
726
780
  setBearing: function(theta) {
727
781
  if (!L.Browser.any3d || !this._rotate) { return; }
@@ -745,6 +799,8 @@
745
799
  * Get current map rotation
746
800
  *
747
801
  * @returns {number} theta map degrees
802
+ *
803
+ * @since leaflet-rotate (v0.1)
748
804
  */
749
805
  getBearing: function() {
750
806
  return this._bearing * L.DomUtil.RAD_TO_DEG;
@@ -761,7 +817,7 @@
761
817
  */
762
818
  // createPane: function(name, container) {
763
819
  // if (!this._rotate || name == 'mapPane') {
764
- // return mapProto.createPane.call(this, name, container);
820
+ // return mapProto.createPane.apply(this, arguments);
765
821
  // }
766
822
  // // init "rotatePane"
767
823
  // if (!this._rotatePane) {
@@ -884,15 +940,108 @@
884
940
  // this._enforcingBounds = true;
885
941
  // var center = this.getCenter(),
886
942
  // newCenter = this._limitCenter(center, this._zoom, L.latLngBounds(bounds));
887
-
943
+ //
888
944
  // if (!center.equals(newCenter)) {
889
945
  // this.panTo(newCenter, options);
890
946
  // }
891
-
947
+ //
892
948
  // this._enforcingBounds = false;
893
949
  // return this;
894
950
  // },
895
951
 
952
+ // adjust center for view to get inside bounds
953
+ // _limitCenter(center, zoom, bounds) {
954
+ //
955
+ // if (!bounds) { return center; }
956
+ //
957
+ // const centerPoint = this.project(center, zoom),
958
+ // viewHalf = this.getSize().divideBy(2),
959
+ // viewBounds = new Bounds(centerPoint.subtract(viewHalf), centerPoint.add(viewHalf)),
960
+ // offset = this._getBoundsOffset(viewBounds, bounds, zoom);
961
+ //
962
+ // // If offset is less than a pixel, ignore.
963
+ // // This prevents unstable projections from getting into
964
+ // // an infinite loop of tiny offsets.
965
+ // if (Math.abs(offset.x) <= 1 && Math.abs(offset.y) <= 1) {
966
+ // return center;
967
+ // }
968
+ //
969
+ // return this.unproject(centerPoint.add(offset), zoom);
970
+ // },
971
+
972
+ // @method flyToBounds(bounds: LatLngBounds, options?: fitBounds options): this
973
+ // Sets the view of the map with a smooth animation like [`flyTo`](#map-flyto),
974
+ // but takes a bounds parameter like [`fitBounds`](#map-fitbounds).
975
+ // flyToBounds(bounds, options) {
976
+ // const target = this._getBoundsCenterZoom(bounds, options);
977
+ // return this.flyTo(target.center, target.zoom, options);
978
+ // },
979
+
980
+ // _getBoundsCenterZoom(bounds, options) {
981
+ //
982
+ // options = options || {};
983
+ // bounds = bounds.getBounds ? bounds.getBounds() : toLatLngBounds(bounds);
984
+ //
985
+ // const paddingTL = L.point(options.paddingTopLeft || options.padding || [0, 0]),
986
+ // paddingBR = L.point(options.paddingBottomRight || options.padding || [0, 0]);
987
+ //
988
+ // let zoom = this.getBoundsZoom(bounds, false, paddingTL.add(paddingBR));
989
+ //
990
+ // zoom = (typeof options.maxZoom === 'number') ? Math.min(options.maxZoom, zoom) : zoom;
991
+ //
992
+ // if (zoom === Infinity) {
993
+ // return { center: bounds.getCenter(), zoom };
994
+ // }
995
+ //
996
+ // return { center, zoom };
997
+ //
998
+ // },
999
+
1000
+ /**
1001
+ * Returns the maximum zoom level on which the given bounds fit to the map
1002
+ * view in its entirety. If `inside` (optional) is set to `true`, the method
1003
+ * instead returns the minimum zoom level on which the map view fits into
1004
+ * the given bounds in its entirety.
1005
+ *
1006
+ * @param {L.LatLngBounds} bounds
1007
+ * @param {Boolean} [inside=false]
1008
+ * @param {L.Point} [padding=[0,0]]
1009
+ *
1010
+ * @returns {Number} zoom level
1011
+ */
1012
+ getBoundsZoom(bounds, inside, padding) {
1013
+ if (!this._rotate || Math.abs(this._bearing).toFixed(1) < 0.1) {
1014
+ return mapProto.getBoundsZoom.apply(this, arguments);
1015
+ }
1016
+
1017
+ bounds = L.latLngBounds(bounds);
1018
+ padding = L.point(padding || [0, 0]);
1019
+
1020
+ let zoom = this.getZoom() || 0;
1021
+ const min = this.getMinZoom(),
1022
+ max = this.getMaxZoom(),
1023
+ /** @TODO use mapProto.getBoundsZoom */
1024
+ // nw = bounds.getNorthWest(),
1025
+ // se = bounds.getSouthEast(),
1026
+ // size = this.getSize().subtract(padding),
1027
+ // boundsSize = L.bounds(this.project(se, zoom), this.project(nw, zoom)).getSize(),
1028
+ size = this.getSize().subtract(padding),
1029
+ boundsSize = this.mapBoundsToContainerBounds(bounds).getSize(),
1030
+ snap = this.options.zoomSnap,
1031
+ scalex = size.x / boundsSize.x,
1032
+ scaley = size.y / boundsSize.y,
1033
+ scale = inside ? Math.max(scalex, scaley) : Math.min(scalex, scaley);
1034
+
1035
+ zoom = this.getScaleZoom(scale, zoom);
1036
+
1037
+ if (snap) {
1038
+ zoom = Math.round(zoom / (snap / 100)) * (snap / 100); // don't jump if within 1% of a snap level
1039
+ zoom = inside ? Math.ceil(zoom / snap) * snap : Math.floor(zoom / snap) * snap;
1040
+ }
1041
+
1042
+ return Math.max(min, Math.min(max, zoom));
1043
+ },
1044
+
896
1045
  /**
897
1046
  * Layer point of the current center
898
1047
  *
@@ -908,13 +1057,16 @@
908
1057
  * @param {L.LatLng} latlng map coordinates
909
1058
  */
910
1059
  _getCenterOffset: function(latlng) {
911
- var centerOffset = mapProto._getCenterOffset.call(this, latlng);
1060
+ var centerOffset = mapProto._getCenterOffset.apply(this, arguments);
912
1061
  if (this._rotate) {
913
1062
  centerOffset = centerOffset.rotate(this._bearing);
914
1063
  }
915
1064
  return centerOffset;
916
1065
  },
917
1066
 
1067
+ /**
1068
+ * @since leaflet-rotate (v0.1)
1069
+ */
918
1070
  _getRotatePanePos: function() {
919
1071
  return this._rotatePanePos || new L.Point(0, 0);
920
1072
  // return L.DomUtil.getPosition(this._rotatePane) || new L.Point(0, 0);
@@ -923,7 +1075,7 @@
923
1075
  _getNewPixelOrigin: function(center, zoom) {
924
1076
  var viewHalf = this.getSize()._divideBy(2);
925
1077
  if (!this._rotate) {
926
- return mapProto._getNewPixelOrigin.call(this, center, zoom);
1078
+ return mapProto._getNewPixelOrigin.apply(this, arguments);
927
1079
  }
928
1080
  return this.project(center, zoom)
929
1081
  .rotate(this._bearing)
@@ -1030,39 +1182,6 @@
1030
1182
  this.fire('locationfound', data);
1031
1183
  },
1032
1184
 
1033
- /**
1034
- * Given latlng bounds, returns the bounds in projected pixel
1035
- * relative to the map container.
1036
- *
1037
- * @see https://github.com/ronikar/Leaflet/blob/5c480ef959b947c3beed7065425a5a36c486262b/src/map/Map.js#L1114-L1135
1038
- *
1039
- * @param {L.LatLngBounds} bounds
1040
- * @returns {L.Bounds}
1041
- */
1042
- // boundsToContainerBounds: function (bounds) {
1043
- // if (this._rotate) {
1044
- // var northWest = this.latLngToContainerPoint(bounds.getNorthWest());
1045
- // var northEast = this.latLngToContainerPoint(bounds.getNorthEast());
1046
- // var southWest = this.latLngToContainerPoint(bounds.getSouthWest());
1047
- // var southEast = this.latLngToContainerPoint(bounds.getSouthEast());
1048
- //
1049
- // var minX = Math.min(northWest.x, northEast.x, southEast.x, southWest.x);
1050
- // var maxX = Math.max(northWest.x, northEast.x, southEast.x, southWest.x);
1051
- // var minY = Math.min(northWest.y, northEast.y, southEast.y, southWest.y);
1052
- // var maxY = Math.max(northWest.y, northEast.y, southEast.y, southWest.y);
1053
- //
1054
- // return L.bounds(
1055
- // L.point(minX, minY).multiplyBy(-1),
1056
- // L.point(maxX, maxY).multiplyBy(-1).add(this.getSize())
1057
- // );
1058
- // } else {
1059
- // return L.Bounds(
1060
- // this.latLngToContainerPoint(bounds.getNorthWest()).multiplyBy(-1),
1061
- // this.latLngToContainerPoint(bounds.getSouthEast()).multiplyBy(-1).add(this.getSize())
1062
- // );
1063
- // }
1064
- // },
1065
-
1066
1185
  /**
1067
1186
  * @see https://github.com/ronikar/Leaflet/blob/5c480ef959b947c3beed7065425a5a36c486262b/src/geo/LatLngBounds.js#L253-L264
1068
1187
  *
@@ -1113,9 +1232,11 @@
1113
1232
 
1114
1233
  });
1115
1234
 
1116
- // @section Handlers
1117
- // @property compassBearing: Handler
1118
- // Compass bearing handler.
1235
+ /**
1236
+ * Add Compass bearing handler to L.Map (disabled unless `window.DeviceOrientationEvent` is set).
1237
+ *
1238
+ * @property {L.Map.CompassBearing} compassBearing
1239
+ */
1119
1240
  L.Map.addInitHook('addHandler', 'compassBearing', L.Map.CompassBearing);
1120
1241
 
1121
1242
  /**
@@ -1124,14 +1245,23 @@
1124
1245
  * @typedef L.Map.ContainerMutation
1125
1246
  */
1126
1247
 
1127
- // @namespace Map
1128
- // @section Interaction Options
1248
+ /**
1249
+ * @TODO check again this file after leaflet v1.9.3 (eg. L.Browser.mutation).
1250
+ * Mutation Observer support will likely be added by default in next releases.
1251
+ */
1252
+
1129
1253
  L.Map.mergeOptions({
1130
1254
 
1131
- // @option trackContainerMutation: Boolean = false
1132
- // Whether the map uses [mutation observers](https://developer.mozilla.org/docs/Web/API/MutationObserver)
1133
- // to detect changes in its container and trigger `invalidateSize`. Disabled
1134
- // by default due to support not being available in all web browsers.
1255
+ /**
1256
+ * Whether the map uses mutation observers to
1257
+ * detect changes in its container and trigger
1258
+ * `invalidateSize`. Disabled by default due to
1259
+ * support not being available in all web browsers.
1260
+ *
1261
+ * @type {Boolean}
1262
+ *
1263
+ * @see https://developer.mozilla.org/docs/Web/API/MutationObserver
1264
+ */
1135
1265
  trackContainerMutation: false
1136
1266
 
1137
1267
  });
@@ -1139,15 +1269,10 @@
1139
1269
  L.Map.ContainerMutation = L.Handler.extend({
1140
1270
 
1141
1271
  addHooks: function() {
1142
- /** @TODO check again this property. Will likely be added in future releases (leaflet > v1.9.3) */
1143
- // if (!L.Browser.mutation) {
1144
- // return;
1145
- // }
1146
-
1272
+ // if (!L.Browser.mutation) { return; }
1147
1273
  if (!this._observer) {
1148
- this._observer = new MutationObserver(L.Util.bind(this._onMutation, this));
1274
+ this._observer = new MutationObserver(L.Util.bind(this._map.invalidateSize, this._map));
1149
1275
  }
1150
-
1151
1276
  this._observer.observe(this._map.getContainer(), {
1152
1277
  childList: false,
1153
1278
  attributes: true,
@@ -1158,22 +1283,17 @@
1158
1283
  },
1159
1284
 
1160
1285
  removeHooks: function() {
1161
- /** @TODO check again this property. Will likely be added in future releases (leaflet > v1.9.3) */
1162
- // if (!L.Browser.mutation) {
1163
- // return;
1164
- // }
1286
+ // if (!L.Browser.mutation) { return; }
1165
1287
  this._observer.disconnect();
1166
1288
  },
1167
1289
 
1168
- _onMutation: function() {
1169
- this._map.invalidateSize();
1170
- },
1171
-
1172
1290
  });
1173
1291
 
1174
- // @section Handlers
1175
- // @property containerMutation: Handler
1176
- // Container mutation handler (disabled unless [`trackContainerMutation`](#map-trackcontainermutation) is set).
1292
+ /**
1293
+ * Add Container mutation handler to L.Map (disabled unless `trackContainerMutation` is set).
1294
+ *
1295
+ * @property {L.Map.ContainerMutation} trackContainerMutation
1296
+ */
1177
1297
  L.Map.addInitHook('addHandler', 'trackContainerMutation', L.Map.ContainerMutation);
1178
1298
 
1179
1299
  /**
@@ -1185,13 +1305,15 @@
1185
1305
  * @typedef L.Map.TouchGestures
1186
1306
  */
1187
1307
 
1188
- // @namespace Map
1189
- // @section Interaction Options
1190
1308
  L.Map.mergeOptions({
1191
1309
 
1192
- // @option bounceAtZoomLimits: Boolean = true
1193
- // Set it to false if you don't want the map to zoom beyond min/max zoom
1194
- // and then bounce back when pinch-zooming.
1310
+ /**
1311
+ * Set it to false if you don't want the map to
1312
+ * zoom beyond min/max zoom and then bounce back
1313
+ * when pinch-zooming.
1314
+ *
1315
+ * @type {Boolean}
1316
+ */
1195
1317
  bounceAtZoomLimits: true,
1196
1318
 
1197
1319
  });
@@ -1270,8 +1392,14 @@
1270
1392
  var bearingDelta = (theta - this._startTheta) * L.DomUtil.RAD_TO_DEG;
1271
1393
  if (vector.y < 0) { bearingDelta += 180; }
1272
1394
  if (bearingDelta) {
1273
- /// TODO: The pivot should be the last touch point, but zoomAnimation manages to
1274
- /// overwrite the rotate pane position. Maybe related to #3529.
1395
+ /**
1396
+ * @TODO the pivot should be the last touch point,
1397
+ * but zoomAnimation manages to overwrite the rotate
1398
+ * pane position. Maybe related to #3529.
1399
+ *
1400
+ * @see https://github.com/Leaflet/Leaflet/pull/3529
1401
+ * @see https://github.com/fnicollet/Leaflet/commit/a77af51a6b10f308d1b9a16552091d1d0aee8834
1402
+ */
1275
1403
  map.setBearing(this._startBearing - bearingDelta);
1276
1404
  }
1277
1405
  }
@@ -1339,9 +1467,11 @@
1339
1467
 
1340
1468
  });
1341
1469
 
1342
- // @section Handlers
1343
- // @property touchGestures: Handler
1344
- // Touch gestures handler.
1470
+ /**
1471
+ * Add Touch Gestures handler (enabled unless `touchGestures` is unset).
1472
+ *
1473
+ * @property {L.Map.TouchGestures} touchGestures
1474
+ */
1345
1475
  L.Map.addInitHook('addHandler', 'touchGestures', L.Map.TouchGestures);
1346
1476
 
1347
1477
  /**
@@ -1350,13 +1480,13 @@
1350
1480
  * @typedef L.Map.TouchRotate
1351
1481
  */
1352
1482
 
1353
- // @namespace Map
1354
- // @section Interaction Options
1355
1483
  L.Map.mergeOptions({
1356
1484
 
1357
- // @section Touch interaction options
1358
- // @option touchRotate: Boolean|String = *
1359
- // Whether the map can be rotated with a two-finger rotation gesture
1485
+ /**
1486
+ * Whether the map can be rotated with a two-finger rotation gesture
1487
+ *
1488
+ * @type {Boolean}
1489
+ */
1360
1490
  touchRotate: false,
1361
1491
 
1362
1492
  });
@@ -1374,24 +1504,25 @@
1374
1504
 
1375
1505
  });
1376
1506
 
1377
- // @section Handlers
1378
- // @property touchZoom: Handler
1379
- // Touch rotate handler.
1507
+ /**
1508
+ * Add Touch Rotate handler (disabled unless `touchGestures` is set).
1509
+ *
1510
+ * @property {L.Map.TouchGestures} touchGestures
1511
+ */
1380
1512
  L.Map.addInitHook('addHandler', 'touchRotate', L.Map.TouchRotate);
1381
1513
 
1382
1514
  /**
1383
- * Rotates the map on shift key + mouseheel scrolling (desktop).
1515
+ * Rotates the map on shift key + mousewheel scrolling (desktop).
1384
1516
  *
1385
1517
  * @typedef L.Map.ShiftKeyRotate
1386
1518
  */
1387
1519
 
1388
- // @namespace Map
1389
- // @section Interaction Options
1390
1520
  L.Map.mergeOptions({
1391
1521
 
1392
- // @section ShiftKey interaction options
1393
- // @option shiftKeyRotate: Boolean|String = *
1394
- // Whether the map can be rotated with a shit-wheel rotation
1522
+ /**
1523
+ * Whether the map can be rotated with shift + wheel scroll
1524
+ * @type {Boolean}
1525
+ */
1395
1526
  shiftKeyRotate: true,
1396
1527
 
1397
1528
  });
@@ -1421,12 +1552,14 @@
1421
1552
 
1422
1553
  });
1423
1554
 
1424
- // @section Handlers
1425
- // @property touchZoom: Handler
1426
- // Touch rotate handler.
1555
+ /**
1556
+ * Add ShiftKey handler to L.Map (enabled unless `shiftKeyRotate` is unset).
1557
+ *
1558
+ * @property {L.Map.ShiftKeyRotate} shiftKeyRotate
1559
+ */
1427
1560
  L.Map.addInitHook('addHandler', 'shiftKeyRotate', L.Map.ShiftKeyRotate);
1428
1561
 
1429
- // decrease "scrollWheelZoom" handler priority over "shiftKeyRotate" handler
1562
+ // decrease `scrollWheelZoom` handler priority over `shiftKeyRotate` handler
1430
1563
  L.Map.addInitHook(function() {
1431
1564
  if (this.scrollWheelZoom.enabled() && this.shiftKeyRotate.enabled()) {
1432
1565
  this.scrollWheelZoom.disable();
@@ -1442,25 +1575,32 @@
1442
1575
  * @external L.Map.TouchZoom
1443
1576
  */
1444
1577
 
1445
- // @namespace Map
1446
- // @section Interaction Options
1447
1578
  L.Map.mergeOptions({
1448
1579
 
1449
- // @section Touch interaction options
1450
- // @option touchZoom: Boolean|String = *
1451
- // Whether the map can be zoomed by touch-dragging with two fingers. If
1452
- // passed `'center'`, it will zoom to the center of the view regardless of
1453
- // where the touch events (fingers) were. Enabled for touch-capable web
1454
- // browsers.
1580
+ /**
1581
+ * Whether the map can be zoomed by touch-dragging
1582
+ * with two fingers. If passed `'center'`, it will
1583
+ * zoom to the center of the view regardless of
1584
+ * where the touch events (fingers) were. Enabled
1585
+ * for touch-capable web browsers.
1586
+ *
1587
+ * @type {(Boolean|String)}
1588
+ */
1455
1589
  touchZoom: L.Browser.touch,
1456
1590
 
1457
1591
  /**
1458
- * @TODO check if this is a duplicate of `L.Map.TouchGestures::bounceAtZoomLimits`
1592
+ *
1459
1593
  */
1460
1594
 
1461
- // @option bounceAtZoomLimits: Boolean = true
1462
- // Set it to false if you don't want the map to zoom beyond min/max zoom
1463
- // and then bounce back when pinch-zooming.
1595
+ /**
1596
+ * @TODO check if this is a duplicate of `L.Map.TouchGestures::bounceAtZoomLimits`
1597
+ *
1598
+ * Set it to false if you don't want the map to
1599
+ * zoom beyond min/max zoom and then bounce back
1600
+ * when pinch-zooming.
1601
+ *
1602
+ * @type {Boolean}
1603
+ */
1464
1604
  bounceAtZoomLimits: false,
1465
1605
 
1466
1606
  });
@@ -1480,9 +1620,11 @@
1480
1620
 
1481
1621
  });
1482
1622
 
1483
- // @section Handlers
1484
- // @property touchZoom: Handler
1485
- // Touch zoom handler.
1623
+ /**
1624
+ * Add Touch Zoom handler (disabled unless `L.Browser.touch` is set).
1625
+ *
1626
+ * @property {L.Map.TouchGestures} touchGestures
1627
+ */
1486
1628
  L.Map.addInitHook('addHandler', 'touchZoom', L.Map.TouchZoom);
1487
1629
 
1488
1630
  /**