leaflet-rotate 0.3.0 → 0.5.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.
Files changed (42) hide show
  1. package/README.md +74 -5
  2. package/build/test.js +18 -0
  3. package/dist/leaflet-rotate-src.js +1081 -303
  4. package/dist/leaflet-rotate-src.js.map +3 -3
  5. package/dist/leaflet-rotate.js +1 -1
  6. package/dist/leaflet-rotate.js.map +3 -3
  7. package/lib/debug.js +84 -66
  8. package/lib/debug.min.js +1 -1
  9. package/misc/leaflet-heat-rotate.js +14 -7
  10. package/misc/loremIpsum.js +1 -1
  11. package/misc/places.js +1 -1
  12. package/misc/route.js +1 -1
  13. package/package.json +5 -5
  14. package/src/control/Rotate.js +98 -29
  15. package/src/dom/DomUtil.js +42 -47
  16. package/src/dom/Draggable.js +6 -1
  17. package/src/geo/LatLngBounds.js +5 -0
  18. package/src/geometry/Bounds.js +5 -0
  19. package/src/geometry/Point.js +33 -10
  20. package/src/index.js +3 -1
  21. package/src/layer/DivOverlay.js +43 -12
  22. package/src/layer/Popup.js +29 -16
  23. package/src/layer/Tooltip.js +21 -5
  24. package/src/layer/marker/Icon.js +20 -8
  25. package/src/layer/marker/Marker.js +103 -24
  26. package/src/layer/tile/GridLayer.js +22 -6
  27. package/src/layer/vector/Renderer.js +102 -11
  28. package/src/map/Map.js +408 -121
  29. package/src/map/handler/CompassBearing.js +33 -7
  30. package/src/map/handler/ContainerMutation.js +20 -3
  31. package/src/map/handler/ShiftKeyRotate.js +156 -16
  32. package/src/map/handler/TouchGestures.js +91 -29
  33. package/src/map/handler/TouchRotate.js +20 -3
  34. package/src/map/handler/TouchZoom.js +25 -5
  35. package/test/features/example.feature +5 -0
  36. package/test/features/rotation.feature +30 -0
  37. package/test/index.html +60 -22
  38. package/test/steps/bearing.steps.js +345 -3
  39. package/test/steps/example.steps.js +72 -11
  40. package/test/steps/gestures.steps.js +4 -4
  41. package/test/steps/overlays.steps.js +32 -32
  42. package/test/support/hooks.js +38 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "leaflet-rotate",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "A Leaflet plugin that allows to add rotation functionality to map tiles",
5
5
  "type": "module",
6
6
  "main": "dist/leaflet-rotate.js",
@@ -9,7 +9,7 @@
9
9
  "scripts": {
10
10
  "dev": "node build/dev.js",
11
11
  "build": "node build/build.js",
12
- "test": "npm run build && cucumber-js",
12
+ "test": "node build/test.js",
13
13
  "version": "npm run build && git add -A dist"
14
14
  },
15
15
  "repository": {
@@ -46,12 +46,12 @@
46
46
  "url": "https://github.com/Raruto/leaflet-rotate/issues"
47
47
  },
48
48
  "homepage": "https://github.com/Raruto/leaflet-rotate#readme",
49
+ "peerDependencies": {
50
+ "leaflet": "^1.9.3 || ^2.0.0-alpha.1"
51
+ },
49
52
  "devDependencies": {
50
53
  "@cucumber/cucumber": "^10.3.1",
51
54
  "esbuild": "^0.28.2",
52
55
  "playwright": "^1.64.1"
53
- },
54
- "peerDependencies": {
55
- "leaflet": "^1.9.3"
56
56
  }
57
57
  }
@@ -1,11 +1,19 @@
1
1
  /**
2
- * A tri-state control for map rotation, states are:
2
+ * Leaflet control for changing map rotation and selecting a rotation mode.
3
+ * Its modes are:
3
4
  *
4
- * - Locked (default)
5
- * - Unlocked (user can pinch-rotate)
6
- * - Follow (rotation follows device orientation, if available)
5
+ * - Locked: rotation gestures are disabled.
6
+ * - Touch: two-finger rotation is enabled.
7
+ * - Compass: bearing follows device orientation when supported and permitted.
7
8
  *
8
- * @typedef L.Control.Rotate
9
+ * @class L.Control.Rotate
10
+ *
11
+ * @extends L.Control
12
+ *
13
+ * @property {string} [position='topleft'] Leaflet control position.
14
+ * @property {boolean} [closeOnZeroBearing=true] Hide the control when bearing is zero.
15
+ *
16
+ * @since leaflet-rotate (v0.1.0)
9
17
  */
10
18
 
11
19
  L.Control.Rotate = L.Control.extend({
@@ -15,12 +23,21 @@ L.Control.Rotate = L.Control.extend({
15
23
  closeOnZeroBearing: true
16
24
  },
17
25
 
18
- onAdd: function(map) {
19
- var container = this._container = L.DomUtil.create('div', 'leaflet-control-rotate leaflet-bar');
26
+ /**
27
+ * Create the control element and subscribe to map rotation.
28
+ *
29
+ * @param {L.Map} map
30
+ *
31
+ * @returns {HTMLElement} Control container.
32
+ *
33
+ * @since leaflet-rotate (v0.1.0)
34
+ */
35
+ onAdd(map) {
36
+ const container = this._container = L.DomUtil.create('div', 'leaflet-control-rotate leaflet-bar');
20
37
 
21
38
  // this.button = L.Control.Zoom.prototype._createButton.call(this, 'R', 'leaflet-control-rotate', 'leaflet-control-rotate', container, this._toggleLock);
22
39
 
23
- var arrow = this._arrow = L.DomUtil.create('span', 'leaflet-control-rotate-arrow');
40
+ const arrow = this._arrow = L.DomUtil.create('span', 'leaflet-control-rotate-arrow');
24
41
 
25
42
  arrow.style.backgroundImage = `url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 29 29' xmlns='http://www.w3.org/2000/svg' fill='%23333'%3E%3Cpath d='M10.5 14l4-8 4 8h-8z'/%3E%3Cpath d='M10.5 16l4 8 4-8h-8z' fill='%23ccc'/%3E%3C/svg%3E")`;
26
43
  arrow.style.cursor = 'grab';
@@ -31,7 +48,7 @@ L.Control.Rotate = L.Control.extend({
31
48
  arrow.style.backgroundPosition = '50%';
32
49
 
33
50
  // Copy-pasted from L.Control.Zoom
34
- var link = this._link = L.DomUtil.create('a', 'leaflet-control-rotate-toggle', container);
51
+ const link = this._link = L.DomUtil.create('a', 'leaflet-control-rotate-toggle', container);
35
52
  link.appendChild(arrow);
36
53
  link.href = '#';
37
54
  link.title = 'Rotate map';
@@ -43,10 +60,6 @@ L.Control.Rotate = L.Control.extend({
43
60
  .on(link, 'click', this._cycleState, this)
44
61
  .on(link, 'click', this._refocusOnMap, this);
45
62
 
46
- if (!L.Browser.any3d) {
47
- L.DomUtil.addClass(link, 'leaflet-disabled');
48
- }
49
-
50
63
  this._restyle();
51
64
 
52
65
  map.on('rotate', this._restyle, this);
@@ -62,11 +75,25 @@ L.Control.Rotate = L.Control.extend({
62
75
  return container;
63
76
  },
64
77
 
65
- onRemove: function(map) {
78
+ /**
79
+ * Remove the map event listener when the control is detached.
80
+ *
81
+ * @param {L.Map} map
82
+ *
83
+ * @since leaflet-rotate (v0.1.0)
84
+ */
85
+ onRemove(map) {
66
86
  map.off('rotate', this._restyle, this);
67
87
  },
68
88
 
69
- _handleMouseDown: function(e) {
89
+ /**
90
+ * Begin dragging the control's bearing indicator.
91
+ *
92
+ * @param {MouseEvent} e Mouse-down event.
93
+ *
94
+ * @since leaflet-rotate (v0.1.0)
95
+ */
96
+ _handleMouseDown(e) {
70
97
  L.DomEvent.stop(e);
71
98
  this.dragging = true;
72
99
  this.dragstartX = e.pageX;
@@ -76,7 +103,14 @@ L.Control.Rotate = L.Control.extend({
76
103
  .on(document, 'mouseup', this._handleMouseUp, this);
77
104
  },
78
105
 
79
- _handleMouseUp: function(e) {
106
+ /**
107
+ * End bearing-indicator dragging and remove document listeners.
108
+ *
109
+ * @param {MouseEvent} e Mouse-up event.
110
+ *
111
+ * @since leaflet-rotate (v0.1.0)
112
+ */
113
+ _handleMouseUp(e) {
80
114
  L.DomEvent.stop(e);
81
115
  this.dragging = false;
82
116
 
@@ -85,18 +119,33 @@ L.Control.Rotate = L.Control.extend({
85
119
  .off(document, 'mouseup', this._handleMouseUp, this);
86
120
  },
87
121
 
88
- _handleMouseDrag: function(e) {
122
+ /**
123
+ * Set bearing from the horizontal drag distance.
124
+ *
125
+ * @param {MouseEvent} e Mouse-move event.
126
+ *
127
+ * @since leaflet-rotate (v0.1.0)
128
+ */
129
+ _handleMouseDrag(e) {
89
130
  if (!this.dragging) { return; }
90
- var deltaX = e.clientX - this.dragstartX;
131
+ const deltaX = e.clientX - this.dragstartX;
91
132
  this._map.setBearing(deltaX);
92
133
  },
93
134
 
94
- _cycleState: function(ev) {
135
+ /**
136
+ * Cycle through touch, compass, and locked rotation modes.
137
+ * Compass mode may require permission from the browser.
138
+ *
139
+ * @param {Event} ev Control click event.
140
+ *
141
+ * @since leaflet-rotate (v0.1.0)
142
+ */
143
+ _cycleState(ev) {
95
144
  if (!this._map) {
96
145
  return;
97
146
  }
98
147
 
99
- var map = this._map;
148
+ const map = this._map;
100
149
 
101
150
  // Touch mode
102
151
  if (!map.touchRotate.enabled() && !map.compassBearing.enabled()) {
@@ -124,12 +173,19 @@ L.Control.Rotate = L.Control.extend({
124
173
  this._restyle();
125
174
  },
126
175
 
127
- _restyle: function() {
176
+ /**
177
+ * Update the control icon and visibility to match the current mode.
178
+ *
179
+ * @listens L.Map#rotate
180
+ *
181
+ * @since leaflet-rotate (v0.1.0)
182
+ */
183
+ _restyle() {
128
184
  if (!this._map.options.rotate) {
129
- L.DomUtil.addClass(this._link, 'leaflet-disabled');
185
+ this._link.classList.add('leaflet-disabled');
130
186
  } else {
131
- var map = this._map;
132
- var bearing = map.getBearing();
187
+ const map = this._map;
188
+ const bearing = map.getBearing();
133
189
 
134
190
  this._arrow.style.transform = 'rotate(' + bearing + 'deg)';
135
191
 
@@ -159,18 +215,31 @@ L.Control.Rotate = L.Control.extend({
159
215
 
160
216
  });
161
217
 
162
- L.control.rotate = function(options) {
163
- return new L.Control.Rotate(options);
164
- };
218
+ if (L.control) {
219
+ L.control.rotate = options => new L.Control.Rotate(options);
220
+ }
165
221
 
166
222
  L.Map.mergeOptions({
223
+ /**
224
+ * Add the rotation control automatically. Set to `false` to disable,
225
+ * or pass an options object to configure the control.
226
+ *
227
+ * @type {boolean|Object}
228
+ *
229
+ * @since leaflet-rotate (v0.1.0)
230
+ */
167
231
  rotateControl: true,
168
232
  });
169
233
 
234
+ /**
235
+ * Add the configured rotation control to each newly initialized map.
236
+ *
237
+ * @since leaflet-rotate (v0.1.0)
238
+ */
170
239
  L.Map.addInitHook(function() {
171
240
  if (this.options.rotateControl) {
172
- var options = typeof this.options.rotateControl === 'object' ? this.options.rotateControl : {};
173
- this.rotateControl = L.control.rotate(options);
241
+ const options = typeof this.options.rotateControl === 'object' ? this.options.rotateControl : {};
242
+ this.rotateControl = new L.Control.Rotate(options);
174
243
  this.addControl(this.rotateControl);
175
244
  }
176
245
  });
@@ -4,75 +4,70 @@
4
4
  * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/dom/DomUtil.js
5
5
  */
6
6
 
7
- const domUtilProto = L.extend({}, L.DomUtil);
8
-
9
- L.extend(L.DomUtil, {
7
+ const domUtilProto = Object.assign({}, L.DomUtil);
10
8
 
9
+ Object.assign(L.DomUtil, {
11
10
  /**
12
- * Resets the 3D CSS transform of `el` so it is
13
- * translated by `offset` pixels and optionally
14
- * scaled by `scale`. Does not have an effect if
15
- * the browser doesn't support 3D CSS transforms.
11
+ * Resets the 3D CSS transform of `el` so it is translated by `offset` pixels,
12
+ * optionally scaled by `scale`, and rotated around `pivot` when `bearing` is set.
13
+ *
14
+ * @param {HTMLElement} el Element to transform.
15
+ * @param {L.Point} [offset] Translation in pixels; defaults to the origin.
16
+ * @param {number} [scale] Optional scale factor.
17
+ * @param {number} [bearing] Optional rotation in radians.
18
+ * @param {L.Point} [pivot] Point in pixels around which to rotate.
19
+ *
20
+ * @returns {void}
16
21
  *
17
- * @param {HTMLElement} el
18
- * @param {L.Point} offset
19
- * @param {Number} scale
20
- * @param {Number} bearing
21
- * @param {L.Point} pivot
22
+ * @since leaflet-rotate (v0.1.0)
22
23
  */
23
- setTransform: function(el, offset, scale, bearing, pivot) {
24
- var pos = offset || new L.Point(0, 0);
24
+ setTransform(el, offset, scale, bearing, pivot) {
25
+ let pos = offset || new L.Point(0, 0);
25
26
 
26
27
  if (!bearing) {
27
- offset = pos._round();
28
- return domUtilProto.setTransform.apply(this, arguments);
28
+ return domUtilProto.setTransform(el, pos._round(), scale);
29
29
  }
30
30
 
31
31
  pos = pos.rotateFrom(bearing, pivot);
32
-
33
- el.style[L.DomUtil.TRANSFORM] =
34
- 'translate3d(' + pos.x + 'px,' + pos.y + 'px' + ',0)' +
32
+ el.style.transform =
33
+ 'translate3d(' + pos.x + 'px,' + pos.y + 'px,0)' +
35
34
  (scale ? ' scale(' + scale + ')' : '') +
36
35
  ' rotate(' + bearing + 'rad)';
37
36
  },
38
37
 
39
38
  /**
40
- * Sets the position of `el` to coordinates specified by
41
- * `position`, using CSS translate or top/left positioning
42
- * depending on the browser (used by Leaflet internally
43
- * to position its layers).
39
+ * Sets the position of `el` to `point`, using CSS transforms or top/left positioning
40
+ * depending on browser support, and optionally rotating it around `pivot`.
41
+ *
42
+ * @param {HTMLElement} el Element to position.
43
+ * @param {L.Point} point Position in pixels.
44
+ * @param {number} [bearing] Rotation in radians; zero or omitted uses Leaflet positioning.
45
+ * @param {L.Point} [pivot] Point in pixels around which to rotate.
46
+ * @param {number} [scale] Optional scale factor.
44
47
  *
45
- * @param {HTMLElement} el
46
- * @param {L.Point} point
47
- * @param {Number} bearing
48
- * @param {L.Point} pivot
49
- * @param {Number} scale
48
+ * @returns {void}
49
+ *
50
+ * @since leaflet-rotate (v0.1.0)
50
51
  */
51
- setPosition: function(el, point, bearing, pivot, scale) {
52
+ setPosition(el, point, bearing, pivot, scale) {
52
53
  if (!bearing) {
53
- return domUtilProto.setPosition.apply(this, arguments);
54
+ return domUtilProto.setPosition(el, point);
54
55
  }
55
56
 
56
- /*eslint-disable */
57
57
  el._leaflet_pos = point;
58
- /*eslint-enable */
59
-
60
- if (L.Browser.any3d) {
61
- L.DomUtil.setTransform(el, point, scale, bearing, pivot);
62
- } else {
63
- el.style.left = point.x + 'px';
64
- el.style.top = point.y + 'px';
65
- }
58
+ L.DomUtil.setTransform(el, point, scale, bearing, pivot);
66
59
  },
67
60
 
68
61
  /**
69
- * @constant radians = degrees × π/180°
70
- */
71
- DEG_TO_RAD: Math.PI / 180,
72
-
73
- /**
74
- * @constant degrees = radians × 180°/π
62
+ * Returns the position assigned to `el`.
63
+ *
64
+ * @param {HTMLElement} el Element whose Leaflet position is requested.
65
+ *
66
+ * @returns {L.Point} Stored Leaflet position, or the position measured by Leaflet.
67
+ *
68
+ * @since leaflet-rotate (v0.1.0)
75
69
  */
76
- RAD_TO_DEG: 180 / Math.PI,
77
-
70
+ getPosition(el) {
71
+ return el._leaflet_pos || domUtilProto.getPosition(el);
72
+ }
78
73
  });
@@ -1,4 +1,7 @@
1
1
  /**
2
+ * This plugin does not modify the `L.Draggable` API; it adapts marker drag
3
+ * coordinates in `L.Marker` when rotation or pitch is enabled.
4
+ *
2
5
  * @external L.Draggable
3
6
  *
4
7
  * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/dom/Draggable.js
@@ -8,12 +11,14 @@
8
11
  * A class for making DOM elements draggable (including touch support).
9
12
  * Used internally for map and marker dragging. Only works for elements
10
13
  * that were positioned with [`L.DomUtil.setPosition`](#domutil-setposition).
14
+ *
15
+ * @since leaflet-rotate (v0.1.0)
11
16
  */
12
17
 
13
18
  L.Draggable.include({
14
19
 
15
20
  /** @TODO */
16
- // updateMapBearing: function(mapBearing) {
21
+ // updateMapBearing(mapBearing) {
17
22
  // this._mapBearing = mapBearing;
18
23
  // },
19
24
 
@@ -1,4 +1,9 @@
1
1
  /**
2
+ * Leaflet's `L.LatLngBounds` is not overridden by this plugin. Map methods
3
+ * such as `getBounds()` return standard Leaflet bounds containing the viewport.
4
+ *
5
+ * @since leaflet-rotate (v0.1.0)
6
+ *
2
7
  * @external L.LatLngBounds
3
8
  *
4
9
  * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/geo/LatLngBounds.js
@@ -1,4 +1,9 @@
1
1
  /**
2
+ * Leaflet's `L.Bounds` is not overridden by this plugin. Rotation-aware
3
+ * pixel bounds are calculated by the map and renderer extensions.
4
+ *
5
+ * @since leaflet-rotate (v0.1.0)
6
+ *
2
7
  * @external L.Bounds
3
8
  *
4
9
  * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/geometry/Bounds.js
@@ -4,7 +4,7 @@
4
4
  * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/geometry/Point.js
5
5
  */
6
6
 
7
- L.extend(L.Point.prototype, {
7
+ Object.assign(L.Point.prototype, {
8
8
 
9
9
  /**
10
10
  * Rotate around (0,0) by applying the 2D rotation matrix:
@@ -12,9 +12,12 @@ L.extend(L.Point.prototype, {
12
12
  * ⎡ x' ⎤ = ⎡ cos θ -sin θ ⎤ ⎡ x ⎤
13
13
  * ⎣ y' ⎦ ⎣ sin θ cos θ ⎦ ⎣ y ⎦
14
14
  *
15
- * @param theta must be given in radians.
15
+ * @param {number} theta Rotation angle in radians, counterclockwise.
16
+ * @returns {L.Point} Rotated point (or this point when theta is zero).
17
+ *
18
+ * @since leaflet-rotate (v0.1.0)
16
19
  */
17
- rotate: function(theta) {
20
+ rotate(theta) {
18
21
  return this.rotateFrom(theta, new L.Point(0,0))
19
22
  },
20
23
 
@@ -27,18 +30,20 @@ L.extend(L.Point.prototype, {
27
30
  *
28
31
  * same as `this.subtract(pivot).rotate(theta).add(pivot)`
29
32
  *
30
- * @param {Number} theta
31
- * @param {L.Point} pivot
33
+ * @param {number} theta Rotation angle in radians, counterclockwise.
34
+ * @param {L.Point} pivot Point to rotate around.
32
35
  *
33
36
  * @returns {L.Point}
37
+ *
38
+ * @since leaflet-rotate (v0.1.0)
34
39
  */
35
- rotateFrom: function(theta, pivot) {
40
+ rotateFrom(theta, pivot) {
36
41
  if (!theta) { return this; }
37
- var sinTheta = Math.sin(theta);
38
- var cosTheta = Math.cos(theta);
39
- var cx = pivot.x,
42
+ const sinTheta = Math.sin(theta);
43
+ const cosTheta = Math.cos(theta);
44
+ const cx = pivot.x,
40
45
  cy = pivot.y;
41
- var x = this.x - cx,
46
+ const x = this.x - cx,
42
47
  y = this.y - cy;
43
48
 
44
49
  return new L.Point(
@@ -48,3 +53,21 @@ L.extend(L.Point.prototype, {
48
53
  },
49
54
 
50
55
  });
56
+
57
+ /**
58
+ * Convert an array or point-like object to an `L.Point`.
59
+ *
60
+ * @param {L.Point|number[]|{x:number,y:number}|null} point Coordinate to convert.
61
+ *
62
+ * @returns {L.Point|null} Existing point, converted point, or `null` for a null input.
63
+ *
64
+ * @since leaflet-rotate (v0.1.0)
65
+ */
66
+ export function toPoint(point) {
67
+ if (point == null || point instanceof L.Point) {
68
+ return point;
69
+ }
70
+ return Array.isArray(point)
71
+ ? new L.Point(point[0], point[1])
72
+ : new L.Point(point.x, point.y);
73
+ }
package/src/index.js CHANGED
@@ -1,5 +1,7 @@
1
1
  /**
2
- * Export Leaflet classes in the same order as the core library
2
+ * Export Leaflet classes in the same order as the core library.
3
+ *
4
+ * @since leaflet-rotate (v0.1.0)
3
5
  *
4
6
  * @external L
5
7
  *
@@ -1,37 +1,68 @@
1
1
  /**
2
+ * Keeps popup and tooltip screen positions aligned with rotated and pitched maps.
3
+ *
2
4
  * @external L.DivOverlay
3
5
  *
4
6
  * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/layer/DivOverlay.js
7
+ *
8
+ * @since leaflet-rotate (v0.1.0)
5
9
  */
6
10
 
7
- const divOverlayProto = L.extend({}, L.DivOverlay.prototype);
11
+ import { toPoint } from '../geometry/Point';
12
+
13
+ const divOverlayProto = Object.defineProperties({}, Object.getOwnPropertyDescriptors(L.DivOverlay.prototype));
8
14
 
9
15
  L.DivOverlay.include({
10
16
 
11
17
  /**
12
- * Update L.Popup and L.Tooltip anchor positions after
13
- * the map is moved by calling `map.setBearing(theta)`
18
+ * Extend overlay event subscriptions to refresh position after map rotation and pitch.
14
19
  *
15
20
  * @listens L.Map~rotate
21
+ * @listens L.Map~pitch
22
+ *
23
+ * @returns {Object} Leaflet event map for the overlay.
24
+ *
25
+ * @since leaflet-rotate (v0.1.0)
16
26
  */
17
- getEvents: function() {
18
- return L.extend(divOverlayProto.getEvents.apply(this, arguments), { rotate: this._updatePosition });
27
+ getEvents() {
28
+ const events = Object.assign(divOverlayProto.getEvents.apply(this, arguments), {
29
+ rotate: this._updatePosition,
30
+ pitch: this._updatePitchEvents,
31
+ });
32
+ if (this._map && this._map._pitch) {
33
+ events.move = this._updatePosition;
34
+ }
35
+ return events;
19
36
  },
20
37
 
21
38
  /**
22
- * 0. update element anchor point (divOverlayProto v1.9.3)
23
- * 1. rotate around anchor point (subtract anchor -> rotate point -> add anchor)
39
+ * Listen to map movement only while pitch is non-zero.
40
+ *
41
+ * @since leaflet-rotate (0.5.0)
42
+ */
43
+ _updatePitchEvents() {
44
+ if (this._map._pitch) {
45
+ this._map.on('move', this._updatePosition, this);
46
+ } else {
47
+ this._map.off('move', this._updatePosition, this);
48
+ }
49
+ },
50
+
51
+ /**
52
+ * Reposition the overlay after map movement, applying rotation/pitch-aware coordinates.
53
+ *
54
+ * @since leaflet-rotate (v0.1.0)
24
55
  */
25
- _updatePosition: function() {
56
+ _updatePosition() {
26
57
  if (!this._map) { return; }
27
58
  divOverlayProto._updatePosition.apply(this, arguments);
28
59
  if (this._map._rotate && this._zoomAnimated) {
29
- var anchor = this._getAnchor();
30
- var pos = L.DomUtil.getPosition(this._container).subtract(anchor);
60
+ const anchor = this._getAnchor();
61
+ const pos = L.DomUtil.getPosition(this._container).subtract(anchor);
31
62
  L.DomUtil.setPosition(this._container, this._map.rotatedPointToMapPanePoint(pos).add(anchor));
32
63
  } else if (this._map._rotate) {
33
- var mapPanePoint = this._map.rotatedPointToMapPanePoint(this._map.latLngToLayerPoint(this._latlng)),
34
- offset = L.point(this.options.offset),
64
+ const mapPanePoint = this._map.rotatedPointToMapPanePoint(this._map.latLngToLayerPoint(this._latlng)),
65
+ offset = toPoint(this.options.offset || [0, 0]),
35
66
  anchor = this._getAnchor();
36
67
 
37
68
  this._containerLeft = -Math.round(this._containerWidth / 2) + mapPanePoint.x + offset.x + anchor.x;
@@ -1,32 +1,45 @@
1
1
  /**
2
+ * Preserves popup positioning and auto-pan behavior on rotated maps.
3
+ *
2
4
  * @external L.Popup
3
5
  *
4
6
  * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/layer/Popup.js
7
+ *
8
+ * @since leaflet-rotate (v0.1.0)
5
9
  */
6
10
 
7
- const popupProto = L.extend({}, L.Popup.prototype);
11
+ import { toPoint } from '../geometry/Point';
12
+
13
+ const popupProto = Object.defineProperties({}, Object.getOwnPropertyDescriptors(L.Popup.prototype));
8
14
 
9
15
  L.Popup.include({
10
16
 
11
17
  /**
12
- * 0. update element anchor point (popupProto v1.9.3)
13
- * 1. rotate around anchor point (subtract anchor -> rotate point -> add anchor)
18
+ * Update the popup position during zoom animation and transform it into map-pane coordinates.
19
+ *
20
+ * @param {Object} e Zoom animation event.
21
+ *
22
+ * @since leaflet-rotate (v0.1.0)
14
23
  */
15
- _animateZoom: function(e) {
24
+ _animateZoom(e) {
16
25
  popupProto._animateZoom.apply(this, arguments);
17
26
  if (this._map && this._map._rotate) {
18
- var anchor = this._getAnchor();
19
- var pos = L.DomUtil.getPosition(this._container).subtract(anchor);
27
+ const anchor = this._getAnchor();
28
+ const pos = L.DomUtil.getPosition(this._container).subtract(anchor);
20
29
  L.DomUtil.setPosition(this._container, this._map.rotatedPointToMapPanePoint(pos).add(anchor));
21
30
  }
22
31
  },
23
32
 
24
33
  /**
25
- * Fix for L.popup({ keepInView = true })
34
+ * Pan the map when a popup with auto-pan enabled would extend beyond the viewport.
26
35
  *
27
36
  * @see https://github.com/fnicollet/Leaflet/pull/21
37
+ *
38
+ * @fires L.Map#autopanstart
39
+ *
40
+ * @since leaflet-rotate (v0.1.0)
28
41
  */
29
- _adjustPan: function() {
42
+ _adjustPan() {
30
43
  if (!this.options.autoPan || (this._map._panAnim && this._map._panAnim._inProgress)) { return; }
31
44
 
32
45
  // We can endlessly recurse if keepInView is set and the view resets.
@@ -36,8 +49,8 @@ L.Popup.include({
36
49
  return;
37
50
  }
38
51
 
39
- var map = this._map,
40
- marginBottom = parseInt(L.DomUtil.getStyle(this._container, 'marginBottom'), 10) || 0,
52
+ const map = this._map,
53
+ marginBottom = parseInt(getComputedStyle(this._container).marginBottom, 10) || 0,
41
54
  containerHeight = this._container.offsetHeight + marginBottom,
42
55
  containerWidth = this._containerWidth,
43
56
  layerPos = new L.Point(this._containerLeft, -containerHeight - this._containerBottom);
@@ -46,12 +59,12 @@ L.Popup.include({
46
59
 
47
60
  /** @TODO use popupProto._adjustPan */
48
61
  // var containerPos = map.layerPointToContainerPoint(layerPos);
49
- var containerPos = layerPos._add(this._map._getMapPanePos()),
50
- padding = L.point(this.options.autoPanPadding),
51
- paddingTL = L.point(this.options.autoPanPaddingTopLeft || padding),
52
- paddingBR = L.point(this.options.autoPanPaddingBottomRight || padding),
53
- size = map.getSize(),
54
- dx = 0,
62
+ const containerPos = layerPos._add(this._map._getMapPanePos()),
63
+ padding = toPoint(this.options.autoPanPadding || [0, 0]),
64
+ paddingTL = toPoint(this.options.autoPanPaddingTopLeft || padding),
65
+ paddingBR = toPoint(this.options.autoPanPaddingBottomRight || padding),
66
+ size = map.getSize();
67
+ let dx = 0,
55
68
  dy = 0;
56
69
 
57
70
  if (containerPos.x + containerWidth + paddingBR.x > size.x) { // right