leaflet-rotate 0.2.1 → 0.2.3

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,6 +13,18 @@
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
 
@@ -29,7 +41,19 @@
29
41
  ' rotate(' + bearing + 'rad)';
30
42
  },
31
43
 
32
- setPosition: function(el, point, bearing, pivot, scale) { // (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
58
  return domUtilProto.setPosition.apply(this, arguments);
35
59
  }
@@ -46,8 +70,14 @@
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
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)
182
+ if (!this._map) { return; }
131
183
  divOverlayProto._updatePosition.apply(this, arguments);
132
- // 1. subtract anchor
133
- // 2. rotate element
134
- // 3. restore anchor
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
209
  popupProto._animateZoom.apply(this, arguments);
158
- // 1. subtract anchor
159
- // 2. rotate element
160
- // 3. restore anchor
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),
@@ -304,22 +353,33 @@
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
 
321
- // @option scale: Number = undefined
322
- // Scale of the marker icon
378
+ /**
379
+ * Scale of the marker icon
380
+ *
381
+ * @type {Number}
382
+ */
323
383
  scale: undefined,
324
384
 
325
385
  });
@@ -380,15 +440,16 @@
380
440
 
381
441
  L.Marker.include({
382
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
+ */
383
449
  getEvents: function() {
384
450
  return L.extend(markerProto.getEvents.apply(this, arguments), { rotate: this.update });
385
451
  },
386
452
 
387
- onAdd: function(map) {
388
- markerProto.onAdd.apply(this, arguments);
389
- map.on('rotate', this.update, this);
390
- },
391
-
392
453
  _initInteraction: function() {
393
454
  var ret = markerProto._initInteraction.apply(this, arguments);
394
455
  if (this.dragging && this.dragging.enabled() && this._map && this._map._rotate) {
@@ -433,12 +494,12 @@
433
494
  this._resetZIndex();
434
495
  },
435
496
 
436
- _updateZIndex: function(offset) {
437
- if (!this._map._rotate) {
438
- return markerProto._updateZIndex.apply(this, arguments);
439
- }
440
- this._icon.style.zIndex = Math.round(this._zIndex + offset);
441
- },
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
+ // },
442
503
 
443
504
  setRotation: function(rotation) {
444
505
  this.options.rotation = rotation;
@@ -457,6 +518,12 @@
457
518
 
458
519
  L.GridLayer.include({
459
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
+ */
460
527
  getEvents: function() {
461
528
  var events = gridLayerProto.getEvents.apply(this, arguments);
462
529
  if (this._map._rotate && !this.options.updateWhenIdle) {
@@ -478,35 +545,6 @@
478
545
 
479
546
  });
480
547
 
481
- /**
482
- * @external L.Canvas
483
- *
484
- * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/layer/vector/Canvas.js
485
- */
486
-
487
- L.extend({}, L.Canvas.prototype);
488
-
489
- L.Canvas.include({
490
-
491
- // onAdd: function() {
492
- // canvasProto.onAdd.apply(this, arguments);
493
- // // When rotating the canvas itself, it is cleared by some weird reason, so redraw.
494
- // this._map.on('rotate', this._redraw, this);
495
- // },
496
-
497
- // onRemove: function() {
498
- // canvasProto.onRemove.apply(this, arguments);
499
- // this._map.off('rotate', this._redraw, this);
500
- // },
501
-
502
- // _update: function() {
503
- // canvasProto._update.apply(this, arguments);
504
- // // Tell paths to redraw themselves
505
- // this.fire('update')
506
- // },
507
-
508
- });
509
-
510
548
  /**
511
549
  * @external L.Renderer
512
550
  *
@@ -517,17 +555,44 @@
517
555
 
518
556
  L.Renderer.include({
519
557
 
520
- // onAdd: function() {
521
- // rendererProto.onAdd.apply(this, arguments);
522
- // // this._map.on('rotate', this._update, this);
523
- // },
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
+ },
524
567
 
525
- // onRemove: function() {
526
- // rendererProto.onRemove.apply(this, arguments);
527
- // // this._map.off('rotate', this._update, this);
528
- // },
568
+ /**
569
+ * Fix for `map.flyTo()` when `false === map.options.zoomAnimation`
570
+ *
571
+ * @see https://github.com/Leaflet/Leaflet/pull/8794
572
+ */
573
+ onAdd: function() {
574
+ rendererProto.onAdd.apply(this, arguments);
575
+ if (L.version <= "1.9.3") {
576
+ // always keep transform-origin as 0 0
577
+ this._container.classList.add('leaflet-zoom-animated');
578
+ }
579
+ },
529
580
 
530
581
  /**
582
+ * @FIXME layer drifts on `map.setZoom()` (eg. zoom during animation)
583
+ *
584
+ * the main cause seems to be related to `this._updateTransform(path._center, path._zoom))`
585
+ * and `this._topLeft = this._map.layerPointToLatLng(this._bounds.min);`
586
+ *
587
+ * @example
588
+ * map.setZoom(2);
589
+ * path._renderer._update();
590
+ * path._renderer._updateTransform(path._renderer._center, path._renderer._zoom);
591
+ *
592
+ * @see https://github.com/Leaflet/Leaflet/pull/8794
593
+ * @see https://github.com/Leaflet/Leaflet/pull/8103
594
+ * @see https://github.com/Leaflet/Leaflet/issues/7466
595
+ *
531
596
  * @TODO rechek this changes from leaflet@v1.9.3
532
597
  *
533
598
  * @see https://github.com/Leaflet/Leaflet/compare/v1.7.0...v1.9.3
@@ -536,15 +601,58 @@
536
601
  if (!this._map._rotate) {
537
602
  return rendererProto._updateTransform.apply(this, arguments);
538
603
  }
604
+ /**
605
+ * @FIXME see path._renderer._reset();
606
+ */
539
607
  var scale = this._map.getZoomScale(zoom, this._zoom),
540
608
  offset = this._map._latLngToNewLayerPoint(this._topLeft, zoom, center);
541
- if (L.Browser.any3d) {
542
- L.DomUtil.setTransform(this._container, offset, scale);
543
- } else {
544
- L.DomUtil.setPosition(this._container, offset);
545
- }
609
+
610
+ L.DomUtil.setTransform(this._container, offset, scale);
611
+
546
612
  },
547
613
 
614
+ // getEvents() {
615
+ // const events = {
616
+ // viewreset: this._reset,
617
+ // zoom: this._onZoom,
618
+ // moveend: this._update,
619
+ // zoomend: this._onZoomEnd
620
+ // };
621
+ // if (this._zoomAnimated) {
622
+ // events.zoomanim = this._onAnimZoom;
623
+ // }
624
+ // return events;
625
+ // },
626
+
627
+ // _onAnimZoom(ev) {
628
+ // this._updateTransform(ev.center, ev.zoom);
629
+ // },
630
+
631
+ // _onZoom() {
632
+ // this._updateTransform(this._map.getCenter(), this._map.getZoom());
633
+ // },
634
+
635
+ // _onZoomEnd() {
636
+ // for (const id in this._layers) {
637
+ // this._layers[id]._project();
638
+ // }
639
+ // },
640
+
641
+ // _reset() {
642
+ // this._update();
643
+ // this._updateTransform(this._center, this._zoom);
644
+
645
+ // for (const id in this._layers) {
646
+ // this._layers[id]._reset();
647
+ // }
648
+ // },
649
+
650
+ // _updatePaths() {
651
+ // for (const id in this._layers) {
652
+ // this._layers[id]._update();
653
+ // }
654
+ // },
655
+
548
656
  _update: function() {
549
657
  if (!this._map._rotate) {
550
658
  return rendererProto._update.apply(this, arguments);
@@ -559,25 +667,6 @@
559
667
 
560
668
  });
561
669
 
562
- /**
563
- * @external L.SVG
564
- *
565
- * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/layer/vector/SVG.js
566
- */
567
-
568
- L.extend({}, L.SVG.prototype);
569
-
570
- L.SVG.include({
571
-
572
- // _update: function() {
573
- // svgProto._update.apply(this, arguments);
574
- // if (this._map._rotate) {
575
- // this.fire('update');
576
- // }
577
- // },
578
-
579
- });
580
-
581
670
  /**
582
671
  * @external L.Map
583
672
  *
@@ -1053,11 +1142,16 @@
1053
1142
  // return L.DomUtil.getPosition(this._rotatePane) || new L.Point(0, 0);
1054
1143
  },
1055
1144
 
1145
+ // _latLngToNewLayerPoint(latlng, zoom, center) {
1146
+ // const topLeft = this._getNewPixelOrigin(center, zoom);
1147
+ // return this.project(latlng, zoom)._subtract(topLeft);
1148
+ //},
1149
+
1056
1150
  _getNewPixelOrigin: function(center, zoom) {
1057
- var viewHalf = this.getSize()._divideBy(2);
1058
1151
  if (!this._rotate) {
1059
1152
  return mapProto._getNewPixelOrigin.apply(this, arguments);
1060
1153
  }
1154
+ var viewHalf = this.getSize()._divideBy(2);
1061
1155
  return this.project(center, zoom)
1062
1156
  .rotate(this._bearing)
1063
1157
  ._subtract(viewHalf)
@@ -1190,32 +1284,73 @@
1190
1284
 
1191
1285
  initialize: function(map) {
1192
1286
  this._map = map;
1193
- this._throttled = L.Util.throttle(this._onDeviceOrientation, 1000, this);
1287
+ /** @see https://caniuse.com/?search=DeviceOrientation */
1288
+ if ('ondeviceorientationabsolute' in window) {
1289
+ this.__deviceOrientationEvent = 'deviceorientationabsolute';
1290
+ } else if('ondeviceorientation' in window) {
1291
+ this.__deviceOrientationEvent = 'deviceorientation';
1292
+ }
1293
+ this._throttled = L.Util.throttle(this._onDeviceOrientation, 100, this);
1194
1294
  },
1195
1295
 
1196
1296
  addHooks: function() {
1197
- if (this._map._rotate && window.DeviceOrientationEvent) {
1198
- L.DomEvent.on(window, 'deviceorientation', this._throttled, this);
1297
+ if (this._map._rotate && this.__deviceOrientationEvent) {
1298
+ L.DomEvent.on(window, this.__deviceOrientationEvent, this._throttled, this);
1299
+ } else {
1300
+ // L.Map.CompassBearing handler will be automatically
1301
+ // disabled if device orientation is not supported.
1302
+ this.disable();
1199
1303
  }
1200
1304
  },
1201
1305
 
1202
1306
  removeHooks: function() {
1203
- if (this._map._rotate && window.DeviceOrientationEvent) {
1204
- L.DomEvent.off(window, 'deviceorientation', this._throttled, this);
1307
+ if (this._map._rotate && this.__deviceOrientationEvent) {
1308
+ L.DomEvent.off(window, this.__deviceOrientationEvent, this._throttled, this);
1205
1309
  }
1206
1310
  },
1207
1311
 
1208
- _onDeviceOrientation: function(event) {
1209
- if (event.alpha !== null && window.orientation !== undefined) {
1210
- this._map.setBearing(event.alpha - window.orientation);
1312
+ /**
1313
+ * `DeviceOrientationEvent.absolute` - Indicates whether the device is providing absolute
1314
+ * orientation values (relatives to Magnetic North) or
1315
+ * using some arbitrary frame determined by the device.
1316
+ *
1317
+ * `DeviceOrientationEvent.alpha` - Returns the rotation of the device around the Z axis;
1318
+ * that is, the number of degrees by which the device is
1319
+ * being twisted around the center of the screen.
1320
+ *
1321
+ * `window.orientation` - Returns the screen orientation in degrees (in 90-degree increments)
1322
+ * of the viewport relative to the device's natural orientation.
1323
+ * Its only possible values are -90, 0, 90, and 180. Positive
1324
+ * values are counterclockwise; negative values are clockwise.
1325
+ *
1326
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/DeviceOrientationEvent/absolute
1327
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/DeviceOrientationEvent/alpha
1328
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Window/orientation
1329
+ */
1330
+ _onDeviceOrientation: function(e) {
1331
+ var angle = e.webkitCompassHeading || e.alpha;
1332
+ var deviceOrientation = 0;
1333
+
1334
+ // Safari iOS
1335
+ if (!e.absolute && e.webkitCompassHeading) {
1336
+ angle = 360 - angle;
1211
1337
  }
1338
+
1339
+ // Older browsers
1340
+ if (!e.absolute && 'undefined' !== typeof window.orientation) {
1341
+ deviceOrientation = window.orientation;
1342
+ }
1343
+
1344
+ this._map.setBearing(angle - deviceOrientation);
1212
1345
  },
1213
1346
 
1214
1347
  });
1215
1348
 
1216
- // @section Handlers
1217
- // @property compassBearing: Handler
1218
- // Compass bearing handler.
1349
+ /**
1350
+ * Add Compass bearing handler to L.Map (disabled unless `window.DeviceOrientationEvent` is set).
1351
+ *
1352
+ * @property {L.Map.CompassBearing} compassBearing
1353
+ */
1219
1354
  L.Map.addInitHook('addHandler', 'compassBearing', L.Map.CompassBearing);
1220
1355
 
1221
1356
  /**
@@ -1224,14 +1359,23 @@
1224
1359
  * @typedef L.Map.ContainerMutation
1225
1360
  */
1226
1361
 
1227
- // @namespace Map
1228
- // @section Interaction Options
1362
+ /**
1363
+ * @TODO check again this file after leaflet v1.9.3 (eg. L.Browser.mutation).
1364
+ * Mutation Observer support will likely be added by default in next releases.
1365
+ */
1366
+
1229
1367
  L.Map.mergeOptions({
1230
1368
 
1231
- // @option trackContainerMutation: Boolean = false
1232
- // Whether the map uses [mutation observers](https://developer.mozilla.org/docs/Web/API/MutationObserver)
1233
- // to detect changes in its container and trigger `invalidateSize`. Disabled
1234
- // by default due to support not being available in all web browsers.
1369
+ /**
1370
+ * Whether the map uses mutation observers to
1371
+ * detect changes in its container and trigger
1372
+ * `invalidateSize`. Disabled by default due to
1373
+ * support not being available in all web browsers.
1374
+ *
1375
+ * @type {Boolean}
1376
+ *
1377
+ * @see https://developer.mozilla.org/docs/Web/API/MutationObserver
1378
+ */
1235
1379
  trackContainerMutation: false
1236
1380
 
1237
1381
  });
@@ -1239,15 +1383,10 @@
1239
1383
  L.Map.ContainerMutation = L.Handler.extend({
1240
1384
 
1241
1385
  addHooks: function() {
1242
- /** @TODO check again this property. Will likely be added in future releases (leaflet > v1.9.3) */
1243
- // if (!L.Browser.mutation) {
1244
- // return;
1245
- // }
1246
-
1386
+ // if (!L.Browser.mutation) { return; }
1247
1387
  if (!this._observer) {
1248
- this._observer = new MutationObserver(L.Util.bind(this._onMutation, this));
1388
+ this._observer = new MutationObserver(L.Util.bind(this._map.invalidateSize, this._map));
1249
1389
  }
1250
-
1251
1390
  this._observer.observe(this._map.getContainer(), {
1252
1391
  childList: false,
1253
1392
  attributes: true,
@@ -1258,22 +1397,17 @@
1258
1397
  },
1259
1398
 
1260
1399
  removeHooks: function() {
1261
- /** @TODO check again this property. Will likely be added in future releases (leaflet > v1.9.3) */
1262
- // if (!L.Browser.mutation) {
1263
- // return;
1264
- // }
1400
+ // if (!L.Browser.mutation) { return; }
1265
1401
  this._observer.disconnect();
1266
1402
  },
1267
1403
 
1268
- _onMutation: function() {
1269
- this._map.invalidateSize();
1270
- },
1271
-
1272
1404
  });
1273
1405
 
1274
- // @section Handlers
1275
- // @property containerMutation: Handler
1276
- // Container mutation handler (disabled unless [`trackContainerMutation`](#map-trackcontainermutation) is set).
1406
+ /**
1407
+ * Add Container mutation handler to L.Map (disabled unless `trackContainerMutation` is set).
1408
+ *
1409
+ * @property {L.Map.ContainerMutation} trackContainerMutation
1410
+ */
1277
1411
  L.Map.addInitHook('addHandler', 'trackContainerMutation', L.Map.ContainerMutation);
1278
1412
 
1279
1413
  /**
@@ -1285,13 +1419,15 @@
1285
1419
  * @typedef L.Map.TouchGestures
1286
1420
  */
1287
1421
 
1288
- // @namespace Map
1289
- // @section Interaction Options
1290
1422
  L.Map.mergeOptions({
1291
1423
 
1292
- // @option bounceAtZoomLimits: Boolean = true
1293
- // Set it to false if you don't want the map to zoom beyond min/max zoom
1294
- // and then bounce back when pinch-zooming.
1424
+ /**
1425
+ * Set it to false if you don't want the map to
1426
+ * zoom beyond min/max zoom and then bounce back
1427
+ * when pinch-zooming.
1428
+ *
1429
+ * @type {Boolean}
1430
+ */
1295
1431
  bounceAtZoomLimits: true,
1296
1432
 
1297
1433
  });
@@ -1370,8 +1506,14 @@
1370
1506
  var bearingDelta = (theta - this._startTheta) * L.DomUtil.RAD_TO_DEG;
1371
1507
  if (vector.y < 0) { bearingDelta += 180; }
1372
1508
  if (bearingDelta) {
1373
- /// TODO: The pivot should be the last touch point, but zoomAnimation manages to
1374
- /// overwrite the rotate pane position. Maybe related to #3529.
1509
+ /**
1510
+ * @TODO the pivot should be the last touch point,
1511
+ * but zoomAnimation manages to overwrite the rotate
1512
+ * pane position. Maybe related to #3529.
1513
+ *
1514
+ * @see https://github.com/Leaflet/Leaflet/pull/3529
1515
+ * @see https://github.com/fnicollet/Leaflet/commit/a77af51a6b10f308d1b9a16552091d1d0aee8834
1516
+ */
1375
1517
  map.setBearing(this._startBearing - bearingDelta);
1376
1518
  }
1377
1519
  }
@@ -1439,9 +1581,11 @@
1439
1581
 
1440
1582
  });
1441
1583
 
1442
- // @section Handlers
1443
- // @property touchGestures: Handler
1444
- // Touch gestures handler.
1584
+ /**
1585
+ * Add Touch Gestures handler (enabled unless `touchGestures` is unset).
1586
+ *
1587
+ * @property {L.Map.TouchGestures} touchGestures
1588
+ */
1445
1589
  L.Map.addInitHook('addHandler', 'touchGestures', L.Map.TouchGestures);
1446
1590
 
1447
1591
  /**
@@ -1450,13 +1594,13 @@
1450
1594
  * @typedef L.Map.TouchRotate
1451
1595
  */
1452
1596
 
1453
- // @namespace Map
1454
- // @section Interaction Options
1455
1597
  L.Map.mergeOptions({
1456
1598
 
1457
- // @section Touch interaction options
1458
- // @option touchRotate: Boolean|String = *
1459
- // Whether the map can be rotated with a two-finger rotation gesture
1599
+ /**
1600
+ * Whether the map can be rotated with a two-finger rotation gesture
1601
+ *
1602
+ * @type {Boolean}
1603
+ */
1460
1604
  touchRotate: false,
1461
1605
 
1462
1606
  });
@@ -1474,24 +1618,25 @@
1474
1618
 
1475
1619
  });
1476
1620
 
1477
- // @section Handlers
1478
- // @property touchZoom: Handler
1479
- // Touch rotate handler.
1621
+ /**
1622
+ * Add Touch Rotate handler (disabled unless `touchGestures` is set).
1623
+ *
1624
+ * @property {L.Map.TouchGestures} touchGestures
1625
+ */
1480
1626
  L.Map.addInitHook('addHandler', 'touchRotate', L.Map.TouchRotate);
1481
1627
 
1482
1628
  /**
1483
- * Rotates the map on shift key + mouseheel scrolling (desktop).
1629
+ * Rotates the map on shift key + mousewheel scrolling (desktop).
1484
1630
  *
1485
1631
  * @typedef L.Map.ShiftKeyRotate
1486
1632
  */
1487
1633
 
1488
- // @namespace Map
1489
- // @section Interaction Options
1490
1634
  L.Map.mergeOptions({
1491
1635
 
1492
- // @section ShiftKey interaction options
1493
- // @option shiftKeyRotate: Boolean|String = *
1494
- // Whether the map can be rotated with a shit-wheel rotation
1636
+ /**
1637
+ * Whether the map can be rotated with shift + wheel scroll
1638
+ * @type {Boolean}
1639
+ */
1495
1640
  shiftKeyRotate: true,
1496
1641
 
1497
1642
  });
@@ -1521,12 +1666,14 @@
1521
1666
 
1522
1667
  });
1523
1668
 
1524
- // @section Handlers
1525
- // @property touchZoom: Handler
1526
- // Touch rotate handler.
1669
+ /**
1670
+ * Add ShiftKey handler to L.Map (enabled unless `shiftKeyRotate` is unset).
1671
+ *
1672
+ * @property {L.Map.ShiftKeyRotate} shiftKeyRotate
1673
+ */
1527
1674
  L.Map.addInitHook('addHandler', 'shiftKeyRotate', L.Map.ShiftKeyRotate);
1528
1675
 
1529
- // decrease "scrollWheelZoom" handler priority over "shiftKeyRotate" handler
1676
+ // decrease `scrollWheelZoom` handler priority over `shiftKeyRotate` handler
1530
1677
  L.Map.addInitHook(function() {
1531
1678
  if (this.scrollWheelZoom.enabled() && this.shiftKeyRotate.enabled()) {
1532
1679
  this.scrollWheelZoom.disable();
@@ -1542,25 +1689,28 @@
1542
1689
  * @external L.Map.TouchZoom
1543
1690
  */
1544
1691
 
1545
- // @namespace Map
1546
- // @section Interaction Options
1547
1692
  L.Map.mergeOptions({
1548
1693
 
1549
- // @section Touch interaction options
1550
- // @option touchZoom: Boolean|String = *
1551
- // Whether the map can be zoomed by touch-dragging with two fingers. If
1552
- // passed `'center'`, it will zoom to the center of the view regardless of
1553
- // where the touch events (fingers) were. Enabled for touch-capable web
1554
- // browsers.
1694
+ /**
1695
+ * Whether the map can be zoomed by touch-dragging
1696
+ * with two fingers. If passed `'center'`, it will
1697
+ * zoom to the center of the view regardless of
1698
+ * where the touch events (fingers) were. Enabled
1699
+ * for touch-capable web browsers.
1700
+ *
1701
+ * @type {(Boolean|String)}
1702
+ */
1555
1703
  touchZoom: L.Browser.touch,
1556
1704
 
1557
1705
  /**
1558
1706
  * @TODO check if this is a duplicate of `L.Map.TouchGestures::bounceAtZoomLimits`
1707
+ *
1708
+ * Set it to false if you don't want the map to
1709
+ * zoom beyond min/max zoom and then bounce back
1710
+ * when pinch-zooming.
1711
+ *
1712
+ * @type {Boolean}
1559
1713
  */
1560
-
1561
- // @option bounceAtZoomLimits: Boolean = true
1562
- // Set it to false if you don't want the map to zoom beyond min/max zoom
1563
- // and then bounce back when pinch-zooming.
1564
1714
  bounceAtZoomLimits: false,
1565
1715
 
1566
1716
  });
@@ -1580,9 +1730,11 @@
1580
1730
 
1581
1731
  });
1582
1732
 
1583
- // @section Handlers
1584
- // @property touchZoom: Handler
1585
- // Touch zoom handler.
1733
+ /**
1734
+ * Add Touch Zoom handler (disabled unless `L.Browser.touch` is set).
1735
+ *
1736
+ * @property {L.Map.TouchGestures} touchGestures
1737
+ */
1586
1738
  L.Map.addInitHook('addHandler', 'touchZoom', L.Map.TouchZoom);
1587
1739
 
1588
1740
  /**
@@ -1603,8 +1755,6 @@
1603
1755
  },
1604
1756
 
1605
1757
  onAdd: function(map) {
1606
- this._onDeviceOrientation = L.Util.throttle(this._unthrottledOnDeviceOrientation, 100, this);
1607
-
1608
1758
  var container = this._container = L.DomUtil.create('div', 'leaflet-control-rotate leaflet-bar');
1609
1759
 
1610
1760
  // this.button = L.Control.Zoom.prototype._createButton.call(this, 'R', 'leaflet-control-rotate', 'leaflet-control-rotate', container, this._toggleLock);
@@ -1624,7 +1774,6 @@
1624
1774
  link.appendChild(arrow);
1625
1775
  link.href = '#';
1626
1776
  link.title = 'Rotate map';
1627
- // link.draggable = false;
1628
1777
 
1629
1778
  L.DomEvent
1630
1779
  .on(link, 'dblclick', L.DomEvent.stopPropagation)
@@ -1639,7 +1788,7 @@
1639
1788
 
1640
1789
  this._restyle();
1641
1790
 
1642
- map.on('rotate', this._restyle.bind(this));
1791
+ map.on('rotate', this._restyle, this);
1643
1792
 
1644
1793
  // State flag
1645
1794
  this._follow = false;
@@ -1651,9 +1800,13 @@
1651
1800
 
1652
1801
  return container;
1653
1802
  },
1803
+
1804
+ onRemove: function(map) {
1805
+ map.off('rotate', this._restyle, this);
1806
+ },
1654
1807
 
1655
1808
  _handleMouseDown: function(e) {
1656
- L.DomEvent.stop(e); // L.DomEvent.stopPropagation(e);
1809
+ L.DomEvent.stop(e);
1657
1810
  this.dragging = true;
1658
1811
  this.dragstartX = e.pageX;
1659
1812
  this.dragstartY = e.pageY;
@@ -1663,7 +1816,7 @@
1663
1816
  },
1664
1817
 
1665
1818
  _handleMouseUp: function(e) {
1666
- L.DomEvent.stop(e); // L.DomEvent.stopPropagation(e);
1819
+ L.DomEvent.stop(e);
1667
1820
  this.dragging = false;
1668
1821
 
1669
1822
  L.DomEvent
@@ -1678,64 +1831,64 @@
1678
1831
  },
1679
1832
 
1680
1833
  _cycleState: function(ev) {
1681
- var map = this._map;
1834
+ if (!this._map) {
1835
+ return;
1836
+ }
1682
1837
 
1683
- if (!map) { return; }
1838
+ var map = this._map;
1684
1839
 
1840
+ // Touch mode
1685
1841
  if (!map.touchRotate.enabled() && !map.compassBearing.enabled()) {
1686
- // Go from disabled to touch
1687
1842
  map.touchRotate.enable();
1688
-
1689
- // console.log('state is now: touch rotate');
1690
- } else {
1691
-
1692
- if (!map.compassBearing.enabled()) {
1693
- // Go from touch to compass
1694
- map.touchRotate.disable();
1695
- map.compassBearing.enable();
1696
-
1697
- // console.log('state is now: compass');
1698
-
1699
- // It is possible that compass is not supported. If so,
1700
- // the hangler will automatically go from compass to disabled.
1701
- } else {
1702
- // Go from compass to disabled
1703
- map.compassBearing.disable();
1704
-
1705
- // console.log('state is now: locked');
1706
-
1707
- map.setBearing(0);
1708
- if (this.options.closeOnZeroBearing) {
1709
- map.touchRotate.enable();
1710
- }
1843
+ }
1844
+
1845
+ // Compass mode
1846
+ else if (!map.compassBearing.enabled()) {
1847
+ map.touchRotate.disable();
1848
+ map.compassBearing.enable();
1849
+ }
1850
+
1851
+ // Locked mode
1852
+ else {
1853
+ map.compassBearing.disable();
1854
+ map.setBearing(0);
1855
+ if (this.options.closeOnZeroBearing) {
1856
+ map.touchRotate.enable();
1711
1857
  }
1712
1858
  }
1713
1859
  this._restyle();
1714
1860
  },
1715
1861
 
1716
1862
  _restyle: function() {
1717
- if (this._map.options.rotate) {
1863
+ if (!this._map.options.rotate) {
1864
+ L.DomUtil.addClass(this._link, 'leaflet-disabled');
1865
+ } else {
1718
1866
  var map = this._map;
1719
1867
  var bearing = map.getBearing();
1720
- if (this.options.closeOnZeroBearing && bearing) {
1868
+
1869
+ this._arrow.style.transform = 'rotate(' + bearing + 'deg)';
1870
+
1871
+ if (bearing && this.options.closeOnZeroBearing) {
1721
1872
  this._container.style.display = 'block';
1722
1873
  }
1723
1874
 
1724
- var cssTransform = 'rotate(' + bearing + 'deg)';
1725
- this._arrow.style.transform = cssTransform;
1726
-
1875
+ // Compass mode
1727
1876
  if (map.compassBearing.enabled()) {
1728
1877
  this._link.style.backgroundColor = 'orange';
1729
- } else if (map.touchRotate.enabled()) {
1878
+ }
1879
+
1880
+ // Touch mode
1881
+ else if (map.touchRotate.enabled()) {
1730
1882
  this._link.style.backgroundColor = null;
1731
- } else {
1883
+ }
1884
+
1885
+ // Locked mode
1886
+ else {
1732
1887
  this._link.style.backgroundColor = 'grey';
1733
- if (this.options.closeOnZeroBearing && map.getBearing() === 0) {
1888
+ if (0 === bearing && this.options.closeOnZeroBearing) {
1734
1889
  this._container.style.display = 'none';
1735
1890
  }
1736
1891
  }
1737
- } else {
1738
- L.DomUtil.addClass(this._link, 'leaflet-disabled');
1739
1892
  }
1740
1893
  },
1741
1894