leaflet-rotate 0.1.4 → 0.2.0

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.
@@ -1,11 +1,14 @@
1
1
  (function (factory) {
2
2
  typeof define === 'function' && define.amd ? define(factory) :
3
3
  factory();
4
- }((function () { 'use strict';
4
+ })((function () { 'use strict';
5
5
 
6
6
  /**
7
- * L.DomUtil
7
+ * @external L.DomUtil
8
+ *
9
+ * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/dom/DomUtil.js
8
10
  */
11
+
9
12
  const domUtilProto = L.extend({}, L.DomUtil);
10
13
 
11
14
  L.extend(L.DomUtil, {
@@ -50,41 +53,48 @@
50
53
  });
51
54
 
52
55
  /**
53
- * L.Draggable
56
+ * @external L.Draggable
57
+ *
58
+ * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/dom/Draggable.js
54
59
  */
60
+
55
61
  L.Draggable.include({
56
62
 
57
- updateMapBearing: function(mapBearing) {
58
- this._mapBearing = mapBearing;
59
- },
63
+ // updateMapBearing: function(mapBearing) {
64
+ // this._mapBearing = mapBearing;
65
+ // },
60
66
 
61
67
  });
62
68
 
63
69
  /**
64
- * L.Point
70
+ * @external L.Point
71
+ *
72
+ * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/geometry/Point.js
65
73
  */
74
+
66
75
  L.extend(L.Point.prototype, {
67
76
 
68
- // Rotate around (0,0) by applying the 2D rotation matrix:
69
- // ⎡ x' ⎤ = ⎡ cos θ -sin θ ⎤ ⎡ x ⎤
70
- // ⎣ y' ⎦ ⎣ sin θ cos θ ⎦ ⎣ y ⎦
71
- // Theta must be given in radians.
77
+ /**
78
+ * Rotate around (0,0) by applying the 2D rotation matrix:
79
+ *
80
+ * ⎡ x' ⎤ = ⎡ cos θ -sin θ ⎤ ⎡ x ⎤
81
+ * ⎣ y' ⎦ ⎣ sin θ cos θ ⎦ ⎣ y ⎦
82
+ *
83
+ * @param theta must be given in radians.
84
+ */
72
85
  rotate: function(theta) {
73
- if (!theta) { return this; }
74
- var sinTheta = Math.sin(theta);
75
- var cosTheta = Math.cos(theta);
76
-
77
- return new L.Point(
78
- this.x * cosTheta - this.y * sinTheta,
79
- this.x * sinTheta + this.y * cosTheta
80
- );
81
- },
82
-
83
- // Rotate around (pivot.x, pivot.y) by:
84
- // 1. subtract (pivot.x, pivot.y)
85
- // 2. rotate around (0, 0)
86
- // 3. add (pivot.x, pivot.y) back
87
- // same as `this.subtract(pivot).rotate(theta).add(pivot)`
86
+ return this.rotateFrom(theta, new L.Point(0,0))
87
+ },
88
+
89
+ /**
90
+ * Rotate around (pivot.x, pivot.y) by:
91
+ *
92
+ * 1. subtract (pivot.x, pivot.y)
93
+ * 2. rotate around (0, 0)
94
+ * 3. add (pivot.x, pivot.y) back
95
+ *
96
+ * same as `this.subtract(pivot).rotate(theta).add(pivot)`
97
+ */
88
98
  rotateFrom: function(theta, pivot) {
89
99
  if (!theta) { return this; }
90
100
  var sinTheta = Math.sin(theta);
@@ -103,8 +113,11 @@
103
113
  });
104
114
 
105
115
  /**
106
- * L.DivOverlay
116
+ * @external L.DivOverlay
117
+ *
118
+ * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/layer/DivOverlay.js
107
119
  */
120
+
108
121
  const divOverlayProto = L.extend({}, L.DivOverlay.prototype);
109
122
 
110
123
  L.DivOverlay.include({
@@ -114,54 +127,59 @@
114
127
  },
115
128
 
116
129
  _updatePosition: function() {
117
- if (!this._map) { return; }
118
-
119
- var pos = this._map.latLngToLayerPoint(this._latlng),
120
- offset = L.point(this.options.offset),
121
- anchor = this._getAnchor();
122
-
123
- if (this._zoomAnimated) {
124
- // TODO: use divOverlayProto._updatePosition
125
- if (this._map._rotate) {
126
- pos = this._map.rotatedPointToMapPanePoint(pos);
127
- }
128
- L.DomUtil.setPosition(this._container, pos.add(anchor));
129
- } else {
130
- offset = offset.add(pos).add(anchor);
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
135
+ if (this._map && this._map._rotate && this._zoomAnimated) {
136
+ var anchor = this._getAnchor();
137
+ var pos = L.DomUtil.getPosition(this._container).subtract(anchor);
138
+ L.DomUtil.setPosition(this._container, this._map.rotatedPointToMapPanePoint(pos).add(anchor));
131
139
  }
132
140
 
133
- var bottom = this._containerBottom = -offset.y,
134
- left = this._containerLeft = -Math.round(this._containerWidth / 2) + offset.x;
135
-
136
- // bottom position the popup in case the height of the popup changes (images loading etc)
137
- this._container.style.bottom = bottom + 'px';
138
- this._container.style.left = left + 'px';
139
141
  },
140
142
 
141
143
  });
142
144
 
143
145
  /**
144
- * L.Popup
146
+ * @external L.Popup
147
+ *
148
+ * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/layer/Popup.js
145
149
  */
150
+
146
151
  const popupProto = L.extend({}, L.Popup.prototype);
147
152
 
148
153
  L.Popup.include({
149
154
 
150
155
  _animateZoom: function(e) {
151
- if (!this._map._rotate) {
152
- popupProto._animateZoom.call(this, 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
161
+ if (this._map && this._map._rotate) {
162
+ var anchor = this._getAnchor();
163
+ var pos = L.DomUtil.getPosition(this._container).subtract(anchor);
164
+ L.DomUtil.setPosition(this._container, this._map.rotatedPointToMapPanePoint(pos).add(anchor));
153
165
  }
154
- var pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center),
155
- anchor = this._getAnchor();
156
-
157
- pos = this._map.rotatedPointToMapPanePoint(pos);
158
-
159
- L.DomUtil.setPosition(this._container, pos.add(anchor));
160
166
  },
161
167
 
168
+ /**
169
+ * Hot fix for L.Popup.mergeOptions({ keepInView: true, });
170
+ *
171
+ * @see https://github.com/fnicollet/Leaflet/pull/21
172
+ */
162
173
  _adjustPan: function() {
163
174
  if (!this.options.autoPan || (this._map._panAnim && this._map._panAnim._inProgress)) { return; }
164
175
 
176
+ // We can endlessly recurse if keepInView is set and the view resets.
177
+ // Let's guard against that by exiting early if we're responding to our own autopan.
178
+ if (this._autopanning) {
179
+ this._autopanning = false;
180
+ return;
181
+ }
182
+
165
183
  var map = this._map,
166
184
  marginBottom = parseInt(L.DomUtil.getStyle(this._container, 'marginBottom'), 10) || 0,
167
185
  containerHeight = this._container.offsetHeight + marginBottom,
@@ -171,7 +189,7 @@
171
189
  layerPos._add(L.DomUtil.getPosition(this._container));
172
190
 
173
191
  // var containerPos = map.layerPointToContainerPoint(layerPos);
174
- // TODO: use popupProto._adjustPan
192
+ /** @TODO use popupProto._adjustPan */
175
193
  var containerPos = layerPos._add(this._map._getMapPanePos()),
176
194
  padding = L.point(this.options.autoPanPadding),
177
195
  paddingTL = L.point(this.options.autoPanPaddingTopLeft || padding),
@@ -198,6 +216,10 @@
198
216
  // @event autopanstart: Event
199
217
  // Fired when the map starts autopanning when opening a popup.
200
218
  if (dx || dy) {
219
+ // Track that we're autopanning, as this function will be re-ran on moveend
220
+ if (this.options.keepInView) {
221
+ this._autopanning = true;
222
+ }
201
223
  map
202
224
  .fire('autopanstart')
203
225
  .panBy([dx, dy]);
@@ -207,27 +229,30 @@
207
229
  });
208
230
 
209
231
  /**
210
- * L.Tooltip
232
+ * @external L.Tooltip
233
+ *
234
+ * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/layer/Tooltip.js
211
235
  */
236
+
212
237
  const tooltipProto = L.extend({}, L.Tooltip.prototype);
213
238
 
214
239
  L.Tooltip.include({
215
240
 
216
- _updatePosition: function() {
241
+ _animateZoom: function(e) {
217
242
  if (!this._map._rotate) {
218
- return tooltipProto._updatePosition.call(this);
243
+ return tooltipProto._animateZoom.call(this, e);
219
244
  }
220
- var pos = this._map.latLngToLayerPoint(this._latlng);
245
+ var pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center);
221
246
 
222
247
  pos = this._map.rotatedPointToMapPanePoint(pos);
223
248
  this._setPosition(pos);
224
249
  },
225
250
 
226
- _animateZoom: function(e) {
251
+ _updatePosition: function() {
227
252
  if (!this._map._rotate) {
228
- return tooltipProto._animateZoom.call(this, e);
253
+ return tooltipProto._updatePosition.call(this);
229
254
  }
230
- var pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center);
255
+ var pos = this._map.latLngToLayerPoint(this._latlng);
231
256
 
232
257
  pos = this._map.rotatedPointToMapPanePoint(pos);
233
258
  this._setPosition(pos);
@@ -236,9 +261,12 @@
236
261
  });
237
262
 
238
263
  /**
239
- * L.Icon
264
+ * @external L.Icon
265
+ *
266
+ * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/layer/marker/Icon.js
240
267
  */
241
- const iconProto = L.extend({}, L.Icon.prototype);
268
+
269
+ L.extend({}, L.Icon.prototype);
242
270
 
243
271
  L.Icon.include({
244
272
 
@@ -259,7 +287,7 @@
259
287
  if (anchor) {
260
288
  img.style.marginLeft = (-anchor.x) + 'px';
261
289
  img.style.marginTop = (-anchor.y) + 'px';
262
- // TODO: use iconProto._setIconStyles
290
+ /** @TODO use iconProto._setIconStyles */
263
291
  img.style[L.DomUtil.TRANSFORM + "Origin"] = anchor.x + "px " + anchor.y + "px 0px";
264
292
  }
265
293
 
@@ -272,33 +300,51 @@
272
300
  });
273
301
 
274
302
  /**
275
- * L.Handler.MarkerDrag
303
+ * @external L.Marker
304
+ * @external L.Handler.MarkerDrag
305
+ *
306
+ * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/layer/marker/Marker.js
276
307
  */
277
- var markerDragProto;
308
+
309
+ const markerProto = L.extend({}, L.Marker.prototype);
310
+
311
+ L.Marker.mergeOptions({
312
+
313
+ // @option rotation: Number = 0
314
+ // Rotation of this marker in rad
315
+ rotation: 0,
316
+
317
+ // @option rotateWithView: Boolean = false
318
+ // Rotate this marker when map rotates
319
+ rotateWithView: false,
320
+
321
+ });
322
+
323
+ var markerDragProto; // retrived at runtime (see below: L.Marker::_initInteraction())
278
324
 
279
325
  var MarkerDrag = {
280
326
 
281
- _onDragStart: function() {
282
- if (!this._marker._map._rotate) {
283
- return markerDragProto._onDragStart.call(this)
284
- }
285
- this._draggable.updateMapBearing(this._marker._map._bearing);
286
- },
327
+ // _onDragStart: function() {
328
+ // if (!this._marker._map._rotate) {
329
+ // return markerDragProto._onDragStart.call(this)
330
+ // }
331
+ // this._draggable.updateMapBearing(this._marker._map._bearing);
332
+ // },
287
333
 
288
334
  _onDrag: function(e) {
289
335
  var marker = this._marker,
290
- // TODO: use markerDragProto._onDrag
336
+ /** @TODO use markerDragProto._onDrag */
291
337
  rotated_marker = marker.options.rotation || marker.options.rotateWithView,
292
338
  shadow = marker._shadow,
293
339
  iconPos = L.DomUtil.getPosition(marker._icon);
294
340
 
295
- // TODO: use markerDragProto._onDrag
341
+ /** @TODO use markerDragProto._onDrag */
296
342
  // update shadow position
297
343
  if (!rotated_marker && shadow) {
298
344
  L.DomUtil.setPosition(shadow, iconPos);
299
345
  }
300
346
 
301
- // TODO: use markerDragProto._onDrag
347
+ /** @TODO use markerDragProto._onDrag */
302
348
  if (marker._map._rotate) {
303
349
  // Reverse calculation from mapPane coordinates to rotatePane coordinates
304
350
  iconPos = marker._map.mapPanePointToRotatedPoint(iconPos);
@@ -309,7 +355,7 @@
309
355
  e.latlng = latlng;
310
356
  e.oldLatLng = this._oldLatLng;
311
357
 
312
- // TODO: use markerDragProto._onDrag
358
+ /** @TODO use markerDragProto._onDrag */
313
359
  if (rotated_marker) marker.setLatLng(latlng); // use `setLatLng` to presisit rotation. low efficiency
314
360
  else marker.fire('move', e); // `setLatLng` will trig 'move' event. we imitate here.
315
361
 
@@ -328,23 +374,6 @@
328
374
 
329
375
  };
330
376
 
331
- /**
332
- * L.Marker
333
- */
334
- const markerProto = L.extend({}, L.Marker.prototype);
335
-
336
- L.Marker.mergeOptions({
337
-
338
- // @option rotation: Number = 0
339
- // Rotation of this marker in rad
340
- rotation: 0,
341
-
342
- // @option rotateWithView: Boolean = false
343
- // Rotate this marker when map rotates
344
- rotateWithView: false,
345
-
346
- });
347
-
348
377
  L.Marker.include({
349
378
 
350
379
  getEvents: function() {
@@ -361,9 +390,11 @@
361
390
  if (this.dragging && this.dragging.enabled() && this._map && this._map._rotate) {
362
391
  // L.Handler.MarkerDrag is used internally by L.Marker to make the markers draggable
363
392
  markerDragProto = markerDragProto || Object.getPrototypeOf(this.dragging);
364
- this.dragging._onDragStart = MarkerDrag._onDragStart.bind(this.dragging);
365
- this.dragging._onDrag = MarkerDrag._onDrag.bind(this.dragging);
366
- this.dragging._onDragEnd = MarkerDrag._onDragEnd.bind(this.dragging);
393
+ Object.assign(this.dragging, {
394
+ // _onDragStart: MarkerDrag._onDragStart.bind(this.dragging),
395
+ _onDrag: MarkerDrag._onDrag.bind(this.dragging),
396
+ _onDragEnd: MarkerDrag._onDragEnd.bind(this.dragging),
397
+ });
367
398
  this.dragging.disable();
368
399
  this.dragging.enable();
369
400
  }
@@ -372,21 +403,23 @@
372
403
 
373
404
  _setPos: function(pos) {
374
405
 
375
- // TODO: use markerProto._setPos
406
+ /** @TODO use markerProto._setPos */
376
407
  if (this._map._rotate) {
377
408
  pos = this._map.rotatedPointToMapPanePoint(pos);
378
409
  }
379
410
 
380
- // TODO: use markerProto._setPos
411
+ /** @TODO use markerProto._setPos */
381
412
  var bearing = this.options.rotation || 0;
382
413
  if (this.options.rotateWithView) {
383
414
  bearing += this._map._bearing;
384
415
  }
385
416
 
386
- // TODO: use markerProto._setPos
387
- L.DomUtil.setPosition(this._icon, pos, bearing, pos);
417
+ /** @TODO use markerProto._setPos */
418
+ if (this._icon) {
419
+ L.DomUtil.setPosition(this._icon, pos, bearing, pos);
420
+ }
388
421
 
389
- // TODO: use markerProto._setPos
422
+ /** @TODO use markerProto._setPos */
390
423
  if (this._shadow) {
391
424
  L.DomUtil.setPosition(this._shadow, pos, bearing, pos);
392
425
  }
@@ -411,8 +444,11 @@
411
444
  });
412
445
 
413
446
  /**
414
- * L.GridLayer
447
+ * @external L.GridLayer
448
+ *
449
+ * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/layer/tile/GridLayer.js
415
450
  */
451
+
416
452
  const gridLayerProto = L.extend({}, L.GridLayer.prototype);
417
453
 
418
454
  L.GridLayer.include({
@@ -433,66 +469,65 @@
433
469
  return gridLayerProto._getTiledPixelBounds.call(this, center);
434
470
  }
435
471
 
436
- var map = this._map,
437
- mapZoom = map._animatingZoom ? Math.max(map._animateToZoom, map.getZoom()) : map.getZoom(),
438
- scale = map.getZoomScale(mapZoom, this._tileZoom),
439
- pixelCenter = map.project(center, this._tileZoom).floor(),
440
- size = map.getSize(),
441
- halfSize = new L.Bounds([
442
- map.containerPointToLayerPoint([0, 0]).floor(),
443
- map.containerPointToLayerPoint([size.x, 0]).floor(),
444
- map.containerPointToLayerPoint([0, size.y]).floor(),
445
- map.containerPointToLayerPoint([size.x, size.y]).floor()
446
- ]).getSize().divideBy(scale * 2);
447
-
448
- return new L.Bounds(pixelCenter.subtract(halfSize), pixelCenter.add(halfSize));
472
+ return this._map._getNewPixelBounds(center, this._tileZoom);
449
473
  },
450
474
 
451
475
  });
452
476
 
453
477
  /**
454
- * L.Canvas
478
+ * @external L.Canvas
479
+ *
480
+ * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/layer/vector/Canvas.js
455
481
  */
456
- const canvasProto = L.extend({}, L.Canvas.prototype);
482
+
483
+ L.extend({}, L.Canvas.prototype);
457
484
 
458
485
  L.Canvas.include({
459
486
 
460
- onAdd: function() {
461
- canvasProto.onAdd.call(this);
462
- // When rotating the canvas itself, it is cleared by some weird reason, so redraw.
463
- this._map.on('rotate', this._redraw, this);
464
- },
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
+ // },
465
492
 
466
- onRemove: function() {
467
- canvasProto.onRemove.call(this);
468
- this._map.off('rotate', this._redraw, this);
469
- },
493
+ // onRemove: function() {
494
+ // canvasProto.onRemove.call(this);
495
+ // this._map.off('rotate', this._redraw, this);
496
+ // },
470
497
 
471
- _update: function() {
472
- canvasProto._update.call(this);
473
- // Tell paths to redraw themselves
474
- this.fire('update');
475
- },
498
+ // _update: function() {
499
+ // canvasProto._update.call(this);
500
+ // // Tell paths to redraw themselves
501
+ // this.fire('update')
502
+ // },
476
503
 
477
504
  });
478
505
 
479
506
  /**
480
- * L.Renderer
507
+ * @external L.Renderer
508
+ *
509
+ * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/layer/vector/Renderer.js
481
510
  */
511
+
482
512
  const rendererProto = L.extend({}, L.Renderer.prototype);
483
513
 
484
514
  L.Renderer.include({
485
515
 
486
- onAdd: function() {
487
- rendererProto.onAdd.call(this);
488
- // this._map.on('rotate', this._update, this);
489
- },
516
+ // onAdd: function() {
517
+ // rendererProto.onAdd.call(this);
518
+ // // this._map.on('rotate', this._update, this);
519
+ // },
490
520
 
491
- onRemove: function() {
492
- rendererProto.onRemove.call(this);
493
- // this._map.off('rotate', this._update, this);
494
- },
521
+ // onRemove: function() {
522
+ // rendererProto.onRemove.call(this);
523
+ // // this._map.off('rotate', this._update, this);
524
+ // },
495
525
 
526
+ /**
527
+ * @TODO rechek this changes from leaflet@v1.9.3
528
+ *
529
+ * @see https://github.com/Leaflet/Leaflet/compare/v1.7.0...v1.9.3
530
+ */
496
531
  _updateTransform: function(center, zoom) {
497
532
  if (!this._map._rotate) {
498
533
  return rendererProto._updateTransform.call(this, center, zoom);
@@ -512,25 +547,8 @@
512
547
  }
513
548
  // Update pixel bounds of renderer container (for positioning/sizing/clipping later)
514
549
  // Subclasses are responsible of firing the 'update' event.
515
- var p = this.options.padding,
516
- map = this._map,
517
- size = this._map.getSize(),
518
- padMin = size.multiplyBy(-p),
519
- padMax = size.multiplyBy(1 + p),
520
- //// TODO: Somehow refactor this out into map.something() - the code is
521
- //// pretty much the same as in GridLayer.
522
- clip = new L.Bounds([
523
- map.containerPointToLayerPoint([padMin.x, padMin.y]).floor(),
524
- map.containerPointToLayerPoint([padMin.x, padMax.y]).floor(),
525
- map.containerPointToLayerPoint([padMax.x, padMin.y]).floor(),
526
- map.containerPointToLayerPoint([padMax.x, padMax.y]).floor()
527
- ]);
528
- //min = this._map.containerPointToLayerPoint(size.multiplyBy(-p)).round();
529
-
530
- this._bounds = clip;
531
- // this._topLeft = clip.min;
532
- this._topLeft = this._map.layerPointToLatLng(clip.min);
533
-
550
+ this._bounds = this._map._getPaddedPixelBounds(this.options.padding);
551
+ this._topLeft = this._map.layerPointToLatLng(this._bounds.min);
534
552
  this._center = this._map.getCenter();
535
553
  this._zoom = this._map.getZoom();
536
554
  },
@@ -538,31 +556,41 @@
538
556
  });
539
557
 
540
558
  /**
541
- * L.SVG
559
+ * @external L.SVG
560
+ *
561
+ * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/layer/vector/SVG.js
542
562
  */
543
- const svgProto = L.extend({}, L.SVG.prototype);
563
+
564
+ L.extend({}, L.SVG.prototype);
544
565
 
545
566
  L.SVG.include({
546
567
 
547
- _update: function() {
548
- svgProto._update.call(this);
549
- if (this._map._rotate) {
550
- this.fire('update');
551
- }
552
- },
568
+ // _update: function() {
569
+ // svgProto._update.call(this);
570
+ // if (this._map._rotate) {
571
+ // this.fire('update');
572
+ // }
573
+ // },
553
574
 
554
575
  });
555
576
 
556
577
  /**
557
- * L.Map
578
+ * @external L.Map
579
+ *
580
+ * @see https://github.com/Leaflet/Leaflet/blob/v1.9.3/src/map/Map.js
558
581
  */
582
+
559
583
  const mapProto = L.extend({}, L.Map.prototype);
560
584
 
561
585
  L.Map.mergeOptions({ rotate: false, bearing: 0, });
562
586
 
563
587
  L.Map.include({
564
588
 
565
- initialize: function(id, options) { // (HTMLElement or String, Object)
589
+ /**
590
+ * @param {(HTMLElement|String)} id html selector
591
+ * @param {Object} [options={}] leaflet map options
592
+ */
593
+ initialize: function(id, options) {
566
594
  if (options.rotate) {
567
595
  this._rotate = true;
568
596
  this._bearing = 0;
@@ -573,20 +601,15 @@
573
601
  }
574
602
  },
575
603
 
576
- // createPane: function(name, container) {
577
- // if (!this._rotate || name == 'mapPane') {
578
- // return mapProto.createPane.call(this, name, container);
579
- // }
580
- // // init "rotatePane"
581
- // if (!this._rotatePane) {
582
- // // this._pivot = this.getSize().divideBy(2);
583
- // this._rotatePane = mapProto.createPane.call(this, 'rotatePane', this._mapPane);
584
- // L.DomUtil.setPosition(this._rotatePane, new L.Point(0, 0), this._bearing, this._pivot);
585
- // }
586
- // return mapProto.createPane.call(this, name, container || this._rotatePane);
587
- // },
588
-
589
- containerPointToLayerPoint: function(point) { // (Point)
604
+ /**
605
+ * Given a pixel coordinate relative to the map container,
606
+ * returns the corresponding pixel coordinate relative to
607
+ * the [origin pixel](#map-getpixelorigin).
608
+ *
609
+ * @param {L.Point} point pixel screen coordinates
610
+ * @returns {L.Point} transformed pixel point
611
+ */
612
+ containerPointToLayerPoint: function(point) {
590
613
  if (!this._rotate) {
591
614
  return mapProto.containerPointToLayerPoint.call(this, point);
592
615
  }
@@ -596,20 +619,13 @@
596
619
  .subtract(this._getRotatePanePos());
597
620
  },
598
621
 
599
- getBounds: function() {
600
- if (!this._rotate) {
601
- return mapProto.getBounds.call(this);
602
- }
603
- var size = this.getSize();
604
- var topleft = this.layerPointToLatLng(this.containerPointToLayerPoint([0, 0])),
605
- topright = this.layerPointToLatLng(this.containerPointToLayerPoint([size.x, 0])),
606
- bottomright = this.layerPointToLatLng(this.containerPointToLayerPoint([size.x, size.y])),
607
- bottomleft = this.layerPointToLatLng(this.containerPointToLayerPoint([0, size.y]));
608
-
609
- // Use LatLngBounds' build-in constructor that automatically extends the bounds to fit the passed points
610
- return new L.LatLngBounds([topleft, topright, bottomright, bottomleft]);
611
- },
612
-
622
+ /**
623
+ * Given a pixel coordinate relative to the [origin pixel](#map-getpixelorigin),
624
+ * returns the corresponding pixel coordinate relative to the map container.
625
+ *
626
+ * @param {L.Point} point pixel screen coordinates
627
+ * @returns {L.Point} transformed pixel point
628
+ */
613
629
  layerPointToContainerPoint: function(point) { // (Point)
614
630
  if (!this._rotate) {
615
631
  return mapProto.layerPointToContainerPoint.call(this, point);
@@ -620,89 +636,182 @@
620
636
  .add(this._getMapPanePos());
621
637
  },
622
638
 
623
- // Rotation methods
624
- // setBearing will work with just the 'theta' parameter.
639
+ /**
640
+ * Converts a coordinate from the rotated pane reference system
641
+ * to the reference system of the not rotated map pane.
642
+ *
643
+ * (rotatePane) --> (mapPane)
644
+ * (rotatePane) --> (norotatePane)
645
+ *
646
+ * @param {L.Point} point pixel screen coordinates
647
+ * @returns {L.Point}
648
+ */
649
+ rotatedPointToMapPanePoint: function(point) {
650
+ return L.point(point)
651
+ .rotate(this._bearing)
652
+ ._add(this._getRotatePanePos());
653
+ },
654
+
655
+ /**
656
+ * Converts a coordinate from the not rotated map pane reference system
657
+ * to the reference system of the rotated pane.
658
+ *
659
+ * (mapPane) --> (rotatePane)
660
+ * (norotatePane) --> (rotatePane)
661
+ *
662
+ * @param {L.Point} point pixel screen coordinates
663
+ */
664
+ mapPanePointToRotatedPoint: function(point) {
665
+ return L.point(point)
666
+ ._subtract(this._getRotatePanePos())
667
+ .rotate(-this._bearing);
668
+ },
669
+
670
+ /**
671
+ * Returns geographical bounds visible in the current map view
672
+ *
673
+ * @TODO find out if map bounds calculated by `L.Map::getBounds()`
674
+ * function should match the `rotatePane` or `norotatePane` bounds
675
+ *
676
+ * @see https://github.com/fnicollet/Leaflet/issues/7
677
+ *
678
+ * @returns {L.LatLngBounds}
679
+ */
680
+ getBounds: function() {
681
+ if (!this._rotate) {
682
+ return mapProto.getBounds.call(this);
683
+ }
684
+
685
+ // SEE: https://github.com/fnicollet/Leaflet/pull/22
686
+ //
687
+ // var bounds = this.getPixelBounds(),
688
+ // sw = this.unproject(bounds.getBottomLeft()),
689
+ // ne = this.unproject(bounds.getTopRight());
690
+ // return new LatLngBounds(sw, ne);
691
+ //
692
+
693
+ // LatLngBounds' constructor automatically
694
+ // extends the bounds to fit the passed points
695
+ var size = this.getSize();
696
+ return new L.LatLngBounds([
697
+ this.containerPointToLatLng([0, 0]), // topleft
698
+ this.containerPointToLatLng([size.x, 0]), // topright
699
+ this.containerPointToLatLng([size.x, size.y]), // bottomright
700
+ this.containerPointToLatLng([0, size.y]), // bottomleft
701
+ ]);
702
+ },
703
+
704
+ /**
705
+ * Returns the bounds of the current map view in projected pixel
706
+ * coordinates (sometimes useful in layer and overlay implementations).
707
+ *
708
+ * @TODO find out if map bounds calculated by `L.Map::getPixelBounds()`
709
+ * function should match the `rotatePane` or `norotatePane` bounds
710
+ *
711
+ * @see https://github.com/fnicollet/Leaflet/issues/7
712
+ *
713
+ * @returns {L.Bounds}
714
+ */
715
+ // getPixelBounds(center, zoom) {
716
+ // // const topLeftPoint = map.containerPointToLayerPoint(this._getTopLeftPoint());
717
+ // const topLeftPoint = this._getTopLeftPoint(center, zoom);
718
+ // return new L.Bounds(topLeftPoint, topLeftPoint.add(this.getSize()));
719
+ // },
720
+
721
+ /**
722
+ * Change map rotation
723
+ *
724
+ * @param {number} theta map degrees
725
+ */
625
726
  setBearing: function(theta) {
626
727
  if (!L.Browser.any3d || !this._rotate) { return; }
627
728
 
628
- var rotatePanePos = this._getRotatePanePos();
629
- var halfSize = this.getSize().divideBy(2);
630
- this._pivot = this._getMapPanePos().clone().multiplyBy(-1).add(halfSize);
631
-
632
- rotatePanePos = rotatePanePos.rotateFrom(-this._bearing, this._pivot);
729
+ var bearing = L.Util.wrapNum(theta, [0, 360]) * L.DomUtil.DEG_TO_RAD,
730
+ center = this._getPixelCenter(),
731
+ oldPos = this._getRotatePanePos().rotateFrom(-this._bearing, center),
732
+ newPos = oldPos.rotateFrom(bearing, center);
633
733
 
634
- this._bearing = theta * L.DomUtil.DEG_TO_RAD; // TODO: mod 360
635
- this._rotatePanePos = rotatePanePos.rotateFrom(this._bearing, this._pivot);
734
+ // CSS transform
735
+ L.DomUtil.setPosition(this._rotatePane, oldPos, bearing, center);
636
736
 
637
- L.DomUtil.setPosition(this._rotatePane, rotatePanePos, this._bearing, this._pivot);
737
+ this._pivot = center;
738
+ this._bearing = bearing;
739
+ this._rotatePanePos = newPos;
638
740
 
639
741
  this.fire('rotate');
640
742
  },
641
743
 
744
+ /**
745
+ * Get current map rotation
746
+ *
747
+ * @returns {number} theta map degrees
748
+ */
642
749
  getBearing: function() {
643
750
  return this._bearing * L.DomUtil.RAD_TO_DEG;
644
751
  },
645
752
 
753
+ /**
754
+ * Creates a new [map pane](#map-pane) with the given name if it doesn't
755
+ * exist already, then returns it. The pane is created as a child of
756
+ * `container`, or as a child of the main map pane if not set.
757
+ *
758
+ * @param {String} name leaflet pane
759
+ * @param {HTMLElement} [container] parent element
760
+ * @returns {HTMLElement} pane container
761
+ */
762
+ // createPane: function(name, container) {
763
+ // if (!this._rotate || name == 'mapPane') {
764
+ // return mapProto.createPane.call(this, name, container);
765
+ // }
766
+ // // init "rotatePane"
767
+ // if (!this._rotatePane) {
768
+ // // this._pivot = this.getSize().divideBy(2);
769
+ // this._rotatePane = mapProto.createPane.call(this, 'rotatePane', this._mapPane);
770
+ // L.DomUtil.setPosition(this._rotatePane, new L.Point(0, 0), this._bearing, this._pivot);
771
+ // }
772
+ // return mapProto.createPane.call(this, name, container || this._rotatePane);
773
+ // },
774
+
775
+ /**
776
+ * Panes are DOM elements used to control the ordering of layers on
777
+ * the map. You can access panes with [`map.getPane`](#map-getpane)
778
+ * or [`map.getPanes`](#map-getpanes) methods. New panes can be created
779
+ * with the [`map.createPane`](#map-createpane) method.
780
+ *
781
+ * Every map has the following default panes that differ only in zIndex:
782
+ *
783
+ * - mapPane [HTMLElement = 'auto'] - Pane that contains all other map panes
784
+ * - tilePane [HTMLElement = 2] - Pane for tile layers
785
+ * - overlayPane [HTMLElement = 4] - Pane for overlays like polylines and polygons
786
+ * - shadowPane [HTMLElement = 5] - Pane for overlay shadows (e.g. marker shadows)
787
+ * - markerPane [HTMLElement = 6] - Pane for marker icons
788
+ * - tooltipPane [HTMLElement = 650] - Pane for tooltips.
789
+ * - popupPane [HTMLElement = 700] - Pane for popups.
790
+ */
646
791
  _initPanes: function() {
647
792
  var panes = this._panes = {};
648
793
  this._paneRenderers = {};
649
794
 
650
- // @section
651
- //
652
- // Panes are DOM elements used to control the ordering of layers on the map. You
653
- // can access panes with [`map.getPane`](#map-getpane) or
654
- // [`map.getPanes`](#map-getpanes) methods. New panes can be created with the
655
- // [`map.createPane`](#map-createpane) method.
656
- //
657
- // Every map has the following default panes that differ only in zIndex.
658
- //
659
- // @pane mapPane: HTMLElement = 'auto'
660
- // Pane that contains all other map panes
661
-
662
795
  this._mapPane = this.createPane('mapPane', this._container);
663
796
  L.DomUtil.setPosition(this._mapPane, new L.Point(0, 0));
664
797
 
665
798
  if (this._rotate) {
666
799
  this._rotatePane = this.createPane('rotatePane', this._mapPane);
667
800
  this._norotatePane = this.createPane('norotatePane', this._mapPane);
668
-
669
- // @pane tilePane: HTMLElement = 2
670
- // Pane for tile layers
801
+ // rotatePane
671
802
  this.createPane('tilePane', this._rotatePane);
672
- // @pane overlayPane: HTMLElement = 4
673
- // Pane for overlays like polylines and polygons
674
803
  this.createPane('overlayPane', this._rotatePane);
675
-
676
- // @pane shadowPane: HTMLElement = 5
677
- // Pane for overlay shadows (e.g. marker shadows)
804
+ // norotatePane
678
805
  this.createPane('shadowPane', this._norotatePane);
679
- // @pane markerPane: HTMLElement = 6
680
- // Pane for marker icons
681
806
  this.createPane('markerPane', this._norotatePane);
682
- // @pane tooltipPane: HTMLElement = 650
683
- // Pane for tooltips.
684
807
  this.createPane('tooltipPane', this._norotatePane);
685
- // @pane popupPane: HTMLElement = 700
686
- // Pane for popups.
687
808
  this.createPane('popupPane', this._norotatePane);
688
809
  } else {
689
- // @pane tilePane: HTMLElement = 2
690
- // Pane for tile layers
691
810
  this.createPane('tilePane');
692
- // @pane overlayPane: HTMLElement = 4
693
- // Pane for overlays like polylines and polygons
694
811
  this.createPane('overlayPane');
695
- // @pane shadowPane: HTMLElement = 5
696
- // Pane for overlay shadows (e.g. marker shadows)
697
812
  this.createPane('shadowPane');
698
- // @pane markerPane: HTMLElement = 6
699
- // Pane for marker icons
700
813
  this.createPane('markerPane');
701
- // @pane tooltipPane: HTMLElement = 650
702
- // Pane for tooltips.
703
814
  this.createPane('tooltipPane');
704
- // @pane popupPane: HTMLElement = 700
705
- // Pane for popups.
706
815
  this.createPane('popupPane');
707
816
  }
708
817
 
@@ -712,21 +821,92 @@
712
821
  }
713
822
  },
714
823
 
715
- // @method rotatedPointToMapPanePoint(point: Point): Point
716
- // Converts a coordinate from the rotated pane reference system
717
- // to the reference system of the not rotated map pane.
718
- rotatedPointToMapPanePoint: function(point) {
719
- return L.point(point).rotate(this._bearing)._add(this._getRotatePanePos());
720
- },
824
+ /**
825
+ * Pans the map the minimum amount to make the `latlng` visible. Use
826
+ * padding options to fit the display to more restricted bounds.
827
+ * If `latlng` is already within the (optionally padded) display bounds,
828
+ * the map will not be panned.
829
+ *
830
+ * @see https://github.com/Raruto/leaflet-rotate/issues/18
831
+ *
832
+ * @param {L.LatLng} latlng coordinates
833
+ * @param {Object} [options={}] padding options
834
+ *
835
+ * @returns {L.Map} current map instance
836
+ */
837
+ panInside(latlng, options) {
838
+ options = options || {};
839
+
840
+ const paddingTL = L.point(options.paddingTopLeft || options.padding || [0, 0]),
841
+ paddingBR = L.point(options.paddingBottomRight || options.padding || [0, 0]),
842
+ /** @TODO use mapProto.panInside */
843
+ // pixelPoint = this.project(latlng),
844
+ // pixelBounds = this.getPixelBounds(),
845
+ // pixelCenter = this.project(this.getCenter()),
846
+ rect = this._container.getBoundingClientRect(),
847
+ pixelPoint = this.latLngToContainerPoint(latlng),
848
+ pixelBounds = L.bounds([ L.point(rect), L.point(rect).add(this.getSize()) ]),
849
+ pixelCenter = pixelBounds.getCenter(),
850
+ //
851
+ paddedBounds = L.bounds([pixelBounds.min.add(paddingTL), pixelBounds.max.subtract(paddingBR)]),
852
+ paddedSize = paddedBounds.getSize();
853
+
854
+ if (!paddedBounds.contains(pixelPoint)) {
855
+ this._enforcingBounds = true;
856
+ const centerOffset = pixelPoint.subtract(paddedBounds.getCenter());
857
+ const offset = paddedBounds.extend(pixelPoint).getSize().subtract(paddedSize);
858
+ pixelCenter.x += centerOffset.x < 0 ? -offset.x : offset.x;
859
+ pixelCenter.y += centerOffset.y < 0 ? -offset.y : offset.y;
860
+ /** @TODO use mapProto.panInside */
861
+ // this.panTo(this.unproject(pixelCenter), options);
862
+ this.panTo(this.containerPointToLatLng(pixelCenter), options);
863
+ //
864
+ this._enforcingBounds = false;
865
+ }
866
+ return this;
867
+ },
868
+
869
+ /**
870
+ * Pans the map to the closest view that would lie inside the given bounds
871
+ * (if it's not already), controlling the animation using the options specific,
872
+ * if any.
873
+ *
874
+ * @TODO check if map bounds calculated by `L.Map::panInsideBounds()`
875
+ * function should match the `rotatePane` or `norotatePane` bounds
876
+ *
877
+ * @see https://github.com/fnicollet/Leaflet/issues/7
878
+ *
879
+ * @param {L.LatLngBounds} bounds coordinates
880
+ * @param {Object} [options] pan options
881
+ * @returns {L.Map} current map instance
882
+ */
883
+ // panInsideBounds: function (bounds, options) {
884
+ // this._enforcingBounds = true;
885
+ // var center = this.getCenter(),
886
+ // newCenter = this._limitCenter(center, this._zoom, L.latLngBounds(bounds));
887
+
888
+ // if (!center.equals(newCenter)) {
889
+ // this.panTo(newCenter, options);
890
+ // }
721
891
 
722
- // @method mapPanePointToRotatedPoint(point: Point): Point
723
- // Converts a coordinate from the not rotated map pane reference system
724
- // to the reference system of the rotated pane.
725
- mapPanePointToRotatedPoint: function(point) {
726
- return L.point(point)._subtract(this._getRotatePanePos()).rotate(-this._bearing);
727
- },
892
+ // this._enforcingBounds = false;
893
+ // return this;
894
+ // },
895
+
896
+ /**
897
+ * Layer point of the current center
898
+ *
899
+ * @returns {L.Point} layer center
900
+ */
901
+ // _getCenterLayerPoint: function () {
902
+ // return this.containerPointToLayerPoint(this.getSize()._divideBy(2));
903
+ // },
728
904
 
729
- // offset of the specified place to the current center in pixels
905
+ /**
906
+ * Offset of the specified place to the current center in pixels
907
+ *
908
+ * @param {L.LatLng} latlng map coordinates
909
+ */
730
910
  _getCenterOffset: function(latlng) {
731
911
  var centerOffset = mapProto._getCenterOffset.call(this, latlng);
732
912
  if (this._rotate) {
@@ -737,12 +917,13 @@
737
917
 
738
918
  _getRotatePanePos: function() {
739
919
  return this._rotatePanePos || new L.Point(0, 0);
920
+ // return L.DomUtil.getPosition(this._rotatePane) || new L.Point(0, 0);
740
921
  },
741
922
 
742
923
  _getNewPixelOrigin: function(center, zoom) {
743
924
  var viewHalf = this.getSize()._divideBy(2);
744
925
  if (!this._rotate) {
745
- mapProto._getNewPixelOrigin.call(this, center, zoom);
926
+ return mapProto._getNewPixelOrigin.call(this, center, zoom);
746
927
  }
747
928
  return this.project(center, zoom)
748
929
  .rotate(this._bearing)
@@ -753,10 +934,72 @@
753
934
  ._round();
754
935
  },
755
936
 
937
+ /**
938
+ * @since leaflet-rotate (v0.2)
939
+ *
940
+ * @see src\layer\tile\GridLayer::_getTiledPixelBounds()
941
+ */
942
+ _getNewPixelBounds: function(center, zoom) {
943
+ center = center || this.getCenter();
944
+ zoom = zoom || this.getZoom();
945
+ if (!this._rotate && mapProto._getNewPixelBounds) {
946
+ return mapProto._getNewPixelBounds.apply(this, arguments);
947
+ }
948
+ var mapZoom = this._animatingZoom ? Math.max(this._animateToZoom, this.getZoom()) : this.getZoom(),
949
+ scale = this.getZoomScale(mapZoom, zoom),
950
+ pixelCenter = this.project(center, zoom).floor(),
951
+ size = this.getSize(),
952
+ halfSize = new L.Bounds([
953
+ this.containerPointToLayerPoint([0, 0]).floor(),
954
+ this.containerPointToLayerPoint([size.x, 0]).floor(),
955
+ this.containerPointToLayerPoint([0, size.y]).floor(),
956
+ this.containerPointToLayerPoint([size.x, size.y]).floor()
957
+ ]).getSize().divideBy(scale * 2);
958
+
959
+ return new L.Bounds(pixelCenter.subtract(halfSize), pixelCenter.add(halfSize));
960
+ },
961
+
962
+ /**
963
+ * @since leaflet-rotate (v0.2)
964
+ *
965
+ * @return {L.Point} map pivot point (center)
966
+ */
967
+ _getPixelCenter: function() {
968
+ if (!this._rotate && mapProto._getPixelCenter) {
969
+ return mapProto._getPixelCenter.apply(this, arguments);
970
+ }
971
+ return this.getSize()._divideBy(2)._subtract(this._getMapPanePos());
972
+ },
973
+
974
+ /**
975
+ * @since leaflet-rotate (v0.2)
976
+ *
977
+ * @see src\layer\vector\Renderer::_update()
978
+ */
979
+ _getPaddedPixelBounds: function(padding) {
980
+ if (!this._rotate && mapProto._getPaddedPixelBounds) {
981
+ return mapProto._getPaddedPixelBounds.apply(this, arguments);
982
+ }
983
+ var p = padding,
984
+ size = this.getSize(),
985
+ padMin = size.multiplyBy(-p),
986
+ padMax = size.multiplyBy(1 + p);
987
+ //min = this.containerPointToLayerPoint(size.multiplyBy(-p)).round();
988
+
989
+ return new L.Bounds([
990
+ this.containerPointToLayerPoint([padMin.x, padMin.y]).floor(),
991
+ this.containerPointToLayerPoint([padMin.x, padMax.y]).floor(),
992
+ this.containerPointToLayerPoint([padMax.x, padMin.y]).floor(),
993
+ this.containerPointToLayerPoint([padMax.x, padMax.y]).floor()
994
+ ]);
995
+ },
996
+
756
997
  _handleGeolocationResponse: function(pos) {
998
+ if (!this._container._leaflet_id) { return; }
999
+
757
1000
  var lat = pos.coords.latitude,
758
1001
  lng = pos.coords.longitude,
759
- // TODO: use mapProto._handleGeolocationResponse
1002
+ /** @TODO use mapProto._handleGeolocationResponse */
760
1003
  hdg = pos.coords.heading,
761
1004
  latlng = new L.LatLng(lat, lng),
762
1005
  bounds = latlng.toBounds(pos.coords.accuracy),
@@ -771,7 +1014,7 @@
771
1014
  latlng: latlng,
772
1015
  bounds: bounds,
773
1016
  timestamp: pos.timestamp,
774
- // TODO: use mapProto._handleGeolocationResponse
1017
+ /** @TODO use mapProto._handleGeolocationResponse */
775
1018
  heading: hdg
776
1019
  };
777
1020
 
@@ -787,39 +1030,83 @@
787
1030
  this.fire('locationfound', data);
788
1031
  },
789
1032
 
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
+ /**
1067
+ * @see https://github.com/ronikar/Leaflet/blob/5c480ef959b947c3beed7065425a5a36c486262b/src/geo/LatLngBounds.js#L253-L264
1068
+ *
1069
+ * @param {L.Bounds} points
1070
+ * @returns {L.Bounds}
1071
+ */
1072
+ // toCircumscribedBounds(points) {
1073
+ // var minX = points.reduce(function (pv, v) { return Math.min(pv, v.x); }, points[0].x),
1074
+ // maxX = points.reduce(function (pv, v) { return Math.max(pv, v.x); }, points[0].x),
1075
+ // minY = points.reduce(function (pv, v) { return Math.min(pv, v.y); }, points[0].y),
1076
+ // maxY = points.reduce(function (pv, v) { return Math.max(pv, v.y); }, points[0].y);
1077
+ //
1078
+ // return L.bounds(L.point(minX, minY), L.point(maxX, maxY));
1079
+ // },
1080
+
790
1081
  });
791
1082
 
792
- /*
793
- * L.Map.CompassBearing will rotate the map according to a smartphone's compass.
1083
+ /**
1084
+ * Rotates the map according to a smartphone's compass.
1085
+ *
1086
+ * @typedef L.Map.CompassBearing
794
1087
  */
795
1088
 
796
1089
  L.Map.CompassBearing = L.Handler.extend({
797
1090
 
798
1091
  initialize: function(map) {
799
- if (!window.DeviceOrientationEvent) {
800
- this._capable = false;
801
- return;
802
- }
803
- this._capable = true;
804
1092
  this._map = map;
805
-
806
1093
  this._throttled = L.Util.throttle(this._onDeviceOrientation, 1000, this);
807
1094
  },
808
1095
 
809
1096
  addHooks: function() {
810
- if (this._capable && this._map._rotate) {
1097
+ if (this._map._rotate && window.DeviceOrientationEvent) {
811
1098
  L.DomEvent.on(window, 'deviceorientation', this._throttled, this);
812
1099
  }
813
1100
  },
814
1101
 
815
1102
  removeHooks: function() {
816
- if (this._capable && this._map._rotate) {
1103
+ if (this._map._rotate && window.DeviceOrientationEvent) {
817
1104
  L.DomEvent.off(window, 'deviceorientation', this._throttled, this);
818
1105
  }
819
1106
  },
820
1107
 
821
1108
  _onDeviceOrientation: function(event) {
822
- if (event.alpha !== null) {
1109
+ if (event.alpha !== null && window.orientation !== undefined) {
823
1110
  this._map.setBearing(event.alpha - window.orientation);
824
1111
  }
825
1112
  },
@@ -831,8 +1118,10 @@
831
1118
  // Compass bearing handler.
832
1119
  L.Map.addInitHook('addHandler', 'compassBearing', L.Map.CompassBearing);
833
1120
 
834
- /*
835
- * L.Handler.ContainerMutation triggers `invalidateResize` when the map's DOM container mutates.
1121
+ /**
1122
+ * Triggers `invalidateResize` when the map's DOM container mutates.
1123
+ *
1124
+ * @typedef L.Map.ContainerMutation
836
1125
  */
837
1126
 
838
1127
  // @namespace Map
@@ -850,9 +1139,10 @@
850
1139
  L.Map.ContainerMutation = L.Handler.extend({
851
1140
 
852
1141
  addHooks: function() {
853
- if (!L.Browser.mutation) {
854
- return;
855
- }
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
+ // }
856
1146
 
857
1147
  if (!this._observer) {
858
1148
  this._observer = new MutationObserver(L.Util.bind(this._onMutation, this));
@@ -868,9 +1158,10 @@
868
1158
  },
869
1159
 
870
1160
  removeHooks: function() {
871
- if (!L.Browser.mutation) {
872
- return;
873
- }
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
+ // }
874
1165
  this._observer.disconnect();
875
1166
  },
876
1167
 
@@ -885,8 +1176,13 @@
885
1176
  // Container mutation handler (disabled unless [`trackContainerMutation`](#map-trackcontainermutation) is set).
886
1177
  L.Map.addInitHook('addHandler', 'trackContainerMutation', L.Map.ContainerMutation);
887
1178
 
888
- /*
889
- * L.Handler.TouchGestures is both TouchZoom plus TouchRotate.
1179
+ /**
1180
+ * TouchGestures is both TouchZoom plus TouchRotate
1181
+ *
1182
+ * @see https://github.com/fnicollet/Leaflet/commit/a77af51a6b10f308d1b9a16552091d1d0aee8834
1183
+ * @see https://github.com/Leaflet/Leaflet/blob/v1.9.3/src/map/handler/Map.TouchZoom.js
1184
+ *
1185
+ * @typedef L.Map.TouchGestures
890
1186
  */
891
1187
 
892
1188
  // @namespace Map
@@ -950,11 +1246,11 @@
950
1246
 
951
1247
  this._moved = false;
952
1248
 
953
- map.stop();
1249
+ map._stop();
954
1250
 
955
1251
  L.DomEvent
956
1252
  .on(document, 'touchmove', this._onTouchMove, this)
957
- .on(document, 'touchend', this._onTouchEnd, this);
1253
+ .on(document, 'touchend touchcancel', this._onTouchEnd, this);
958
1254
 
959
1255
  L.DomEvent.preventDefault(e);
960
1256
  },
@@ -1005,20 +1301,20 @@
1005
1301
  }
1006
1302
 
1007
1303
  if (!this._moved) {
1008
- map._moveStart(true);
1304
+ map._moveStart(true, false);
1009
1305
  this._moved = true;
1010
1306
  }
1011
1307
 
1012
1308
  L.Util.cancelAnimFrame(this._animRequest);
1013
1309
 
1014
- var moveFn = L.bind(map._move, map, this._center, this._zoom, { pinch: true, round: false });
1310
+ var moveFn = map._move.bind(map, this._center, this._zoom, { pinch: true, round: false }, undefined);
1015
1311
  this._animRequest = L.Util.requestAnimFrame(moveFn, this, true);
1016
1312
 
1017
1313
  L.DomEvent.preventDefault(e);
1018
1314
  },
1019
1315
 
1020
1316
  _onTouchEnd: function() {
1021
- if (!this._moved || !this._zooming) {
1317
+ if (!this._moved || !(this._zooming || this._rotating)) {
1022
1318
  this._zooming = false;
1023
1319
  return;
1024
1320
  }
@@ -1028,13 +1324,13 @@
1028
1324
  L.Util.cancelAnimFrame(this._animRequest);
1029
1325
 
1030
1326
  L.DomEvent
1031
- .off(document, 'touchmove', this._onTouchMove)
1032
- .off(document, 'touchend', this._onTouchEnd);
1327
+ .off(document, 'touchmove', this._onTouchMove, this)
1328
+ .off(document, 'touchend touchcancel', this._onTouchEnd, this);
1033
1329
 
1034
1330
  if (this.zoom) {
1035
- // Pinch updates GridLayers' levels only when snapZoom is off, so snapZoom becomes noUpdate.
1331
+ // Pinch updates GridLayers' levels only when zoomSnap is off, so zoomSnap becomes noUpdate.
1036
1332
  if (this._map.options.zoomAnimation) {
1037
- this._map._animateZoom(this._center, this._map._limitZoom(this._zoom), true, this._map.options.snapZoom);
1333
+ this._map._animateZoom(this._center, this._map._limitZoom(this._zoom), true, this._map.options.zoomSnap);
1038
1334
  } else {
1039
1335
  this._map._resetView(this._center, this._map._limitZoom(this._zoom));
1040
1336
  }
@@ -1048,8 +1344,10 @@
1048
1344
  // Touch gestures handler.
1049
1345
  L.Map.addInitHook('addHandler', 'touchGestures', L.Map.TouchGestures);
1050
1346
 
1051
- /*
1052
- * L.Handler.TouchRotate is used by L.Map to add two-finger rotation gestures.
1347
+ /**
1348
+ * Rotates the map on two-finger (touch devices).
1349
+ *
1350
+ * @typedef L.Map.TouchRotate
1053
1351
  */
1054
1352
 
1055
1353
  // @namespace Map
@@ -1081,8 +1379,10 @@
1081
1379
  // Touch rotate handler.
1082
1380
  L.Map.addInitHook('addHandler', 'touchRotate', L.Map.TouchRotate);
1083
1381
 
1084
- /*
1085
- * L.Handler.ShiftKeyRotate is used by L.Map to add shift-wheel rotation.
1382
+ /**
1383
+ * Rotates the map on shift key + mouseheel scrolling (desktop).
1384
+ *
1385
+ * @typedef L.Map.ShiftKeyRotate
1086
1386
  */
1087
1387
 
1088
1388
  // @namespace Map
@@ -1134,8 +1434,12 @@
1134
1434
  }
1135
1435
  });
1136
1436
 
1137
- /*
1138
- * L.Handler.TouchZoom is used by L.Map to add pinch zoom on supported mobile browsers.
1437
+ /**
1438
+ * Adds pinch zoom rotation on mobile browsers
1439
+ *
1440
+ * @see https://github.com/Leaflet/Leaflet/blob/v1.9.3/src/map/handler/Map.TouchZoom.js
1441
+ *
1442
+ * @external L.Map.TouchZoom
1139
1443
  */
1140
1444
 
1141
1445
  // @namespace Map
@@ -1147,10 +1451,18 @@
1147
1451
  // Whether the map can be zoomed by touch-dragging with two fingers. If
1148
1452
  // passed `'center'`, it will zoom to the center of the view regardless of
1149
1453
  // where the touch events (fingers) were. Enabled for touch-capable web
1150
- // browsers except for old Androids.
1151
- touchZoom: L.Browser.touch && !L.Browser.android23,
1454
+ // browsers.
1455
+ touchZoom: L.Browser.touch,
1456
+
1457
+ /**
1458
+ * @TODO check if this is a duplicate of `L.Map.TouchGestures::bounceAtZoomLimits`
1459
+ */
1152
1460
 
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.
1153
1464
  bounceAtZoomLimits: false,
1465
+
1154
1466
  });
1155
1467
 
1156
1468
  L.Map.TouchZoom = L.Handler.extend({
@@ -1174,13 +1486,15 @@
1174
1486
  L.Map.addInitHook('addHandler', 'touchZoom', L.Map.TouchZoom);
1175
1487
 
1176
1488
  /**
1177
- * L.Control.Rotate
1489
+ * A tri-state control for map rotation, states are:
1490
+ *
1491
+ * - Locked (default)
1492
+ * - Unlocked (user can pinch-rotate)
1493
+ * - Follow (rotation follows device orientation, if available)
1494
+ *
1495
+ * @typedef L.Control.Rotate
1178
1496
  */
1179
1497
 
1180
- // A tri-state control for map rotation. States are:
1181
- // Locked (default)
1182
- // Unlocked (user can pinch-rotate)
1183
- // Follow (rotation follows device orientation, if available)
1184
1498
  L.Control.Rotate = L.Control.extend({
1185
1499
 
1186
1500
  options: {
@@ -1210,6 +1524,7 @@
1210
1524
  link.appendChild(arrow);
1211
1525
  link.href = '#';
1212
1526
  link.title = 'Rotate map';
1527
+ // link.draggable = false;
1213
1528
 
1214
1529
  L.DomEvent
1215
1530
  .on(link, 'dblclick', L.DomEvent.stopPropagation)
@@ -1238,7 +1553,7 @@
1238
1553
  },
1239
1554
 
1240
1555
  _handleMouseDown: function(e) {
1241
- L.DomEvent.stopPropagation(e);
1556
+ L.DomEvent.stop(e); // L.DomEvent.stopPropagation(e);
1242
1557
  this.dragging = true;
1243
1558
  this.dragstartX = e.pageX;
1244
1559
  this.dragstartY = e.pageY;
@@ -1248,7 +1563,7 @@
1248
1563
  },
1249
1564
 
1250
1565
  _handleMouseUp: function(e) {
1251
- L.DomEvent.stopPropagation(e);
1566
+ L.DomEvent.stop(e); // L.DomEvent.stopPropagation(e);
1252
1567
  this.dragging = false;
1253
1568
 
1254
1569
  L.DomEvent
@@ -1342,5 +1657,5 @@
1342
1657
  }
1343
1658
  });
1344
1659
 
1345
- })));
1660
+ }));
1346
1661
  //# sourceMappingURL=leaflet-rotate-src.js.map