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.
- package/README.md +74 -5
- package/build/test.js +18 -0
- package/dist/leaflet-rotate-src.js +1081 -303
- package/dist/leaflet-rotate-src.js.map +3 -3
- package/dist/leaflet-rotate.js +1 -1
- package/dist/leaflet-rotate.js.map +3 -3
- package/lib/debug.js +84 -66
- package/lib/debug.min.js +1 -1
- package/misc/leaflet-heat-rotate.js +14 -7
- package/misc/loremIpsum.js +1 -1
- package/misc/places.js +1 -1
- package/misc/route.js +1 -1
- package/package.json +5 -5
- package/src/control/Rotate.js +98 -29
- package/src/dom/DomUtil.js +42 -47
- package/src/dom/Draggable.js +6 -1
- package/src/geo/LatLngBounds.js +5 -0
- package/src/geometry/Bounds.js +5 -0
- package/src/geometry/Point.js +33 -10
- package/src/index.js +3 -1
- package/src/layer/DivOverlay.js +43 -12
- package/src/layer/Popup.js +29 -16
- package/src/layer/Tooltip.js +21 -5
- package/src/layer/marker/Icon.js +20 -8
- package/src/layer/marker/Marker.js +103 -24
- package/src/layer/tile/GridLayer.js +22 -6
- package/src/layer/vector/Renderer.js +102 -11
- package/src/map/Map.js +408 -121
- package/src/map/handler/CompassBearing.js +33 -7
- package/src/map/handler/ContainerMutation.js +20 -3
- package/src/map/handler/ShiftKeyRotate.js +156 -16
- package/src/map/handler/TouchGestures.js +91 -29
- package/src/map/handler/TouchRotate.js +20 -3
- package/src/map/handler/TouchZoom.js +25 -5
- package/test/features/example.feature +5 -0
- package/test/features/rotation.feature +30 -0
- package/test/index.html +60 -22
- package/test/steps/bearing.steps.js +345 -3
- package/test/steps/example.steps.js +72 -11
- package/test/steps/gestures.steps.js +4 -4
- package/test/steps/overlays.steps.js +32 -32
- 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
|
+
"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": "
|
|
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
|
}
|
package/src/control/Rotate.js
CHANGED
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Leaflet control for changing map rotation and selecting a rotation mode.
|
|
3
|
+
* Its modes are:
|
|
3
4
|
*
|
|
4
|
-
* - Locked
|
|
5
|
-
* -
|
|
6
|
-
* -
|
|
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
|
-
* @
|
|
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
|
-
|
|
19
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
131
|
+
const deltaX = e.clientX - this.dragstartX;
|
|
91
132
|
this._map.setBearing(deltaX);
|
|
92
133
|
},
|
|
93
134
|
|
|
94
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
185
|
+
this._link.classList.add('leaflet-disabled');
|
|
130
186
|
} else {
|
|
131
|
-
|
|
132
|
-
|
|
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
|
|
163
|
-
|
|
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
|
-
|
|
173
|
-
this.rotateControl = L.
|
|
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
|
});
|
package/src/dom/DomUtil.js
CHANGED
|
@@ -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 =
|
|
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
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
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
|
-
* @
|
|
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
|
|
24
|
-
|
|
24
|
+
setTransform(el, offset, scale, bearing, pivot) {
|
|
25
|
+
let pos = offset || new L.Point(0, 0);
|
|
25
26
|
|
|
26
27
|
if (!bearing) {
|
|
27
|
-
|
|
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
|
-
|
|
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
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* to position
|
|
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
|
-
* @
|
|
46
|
-
*
|
|
47
|
-
* @
|
|
48
|
-
* @param {L.Point} pivot
|
|
49
|
-
* @param {Number} scale
|
|
48
|
+
* @returns {void}
|
|
49
|
+
*
|
|
50
|
+
* @since leaflet-rotate (v0.1.0)
|
|
50
51
|
*/
|
|
51
|
-
setPosition
|
|
52
|
+
setPosition(el, point, bearing, pivot, scale) {
|
|
52
53
|
if (!bearing) {
|
|
53
|
-
return domUtilProto.setPosition
|
|
54
|
+
return domUtilProto.setPosition(el, point);
|
|
54
55
|
}
|
|
55
56
|
|
|
56
|
-
/*eslint-disable */
|
|
57
57
|
el._leaflet_pos = point;
|
|
58
|
-
|
|
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
|
-
*
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
*
|
|
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
|
-
|
|
77
|
-
|
|
70
|
+
getPosition(el) {
|
|
71
|
+
return el._leaflet_pos || domUtilProto.getPosition(el);
|
|
72
|
+
}
|
|
78
73
|
});
|
package/src/dom/Draggable.js
CHANGED
|
@@ -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
|
|
21
|
+
// updateMapBearing(mapBearing) {
|
|
17
22
|
// this._mapBearing = mapBearing;
|
|
18
23
|
// },
|
|
19
24
|
|
package/src/geo/LatLngBounds.js
CHANGED
|
@@ -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
|
package/src/geometry/Bounds.js
CHANGED
|
@@ -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
|
package/src/geometry/Point.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
|
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 {
|
|
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
|
|
40
|
+
rotateFrom(theta, pivot) {
|
|
36
41
|
if (!theta) { return this; }
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
42
|
+
const sinTheta = Math.sin(theta);
|
|
43
|
+
const cosTheta = Math.cos(theta);
|
|
44
|
+
const cx = pivot.x,
|
|
40
45
|
cy = pivot.y;
|
|
41
|
-
|
|
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
package/src/layer/DivOverlay.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
*
|
|
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
|
|
18
|
-
|
|
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
|
-
*
|
|
23
|
-
*
|
|
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
|
|
56
|
+
_updatePosition() {
|
|
26
57
|
if (!this._map) { return; }
|
|
27
58
|
divOverlayProto._updatePosition.apply(this, arguments);
|
|
28
59
|
if (this._map._rotate && this._zoomAnimated) {
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
34
|
-
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;
|
package/src/layer/Popup.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
*
|
|
13
|
-
*
|
|
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
|
|
24
|
+
_animateZoom(e) {
|
|
16
25
|
popupProto._animateZoom.apply(this, arguments);
|
|
17
26
|
if (this._map && this._map._rotate) {
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
*
|
|
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
|
|
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
|
-
|
|
40
|
-
marginBottom = parseInt(
|
|
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
|
-
|
|
50
|
-
padding =
|
|
51
|
-
paddingTL =
|
|
52
|
-
paddingBR =
|
|
53
|
-
size = map.getSize()
|
|
54
|
-
|
|
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
|