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/src/map/Map.js
CHANGED
|
@@ -1,16 +1,65 @@
|
|
|
1
1
|
/**
|
|
2
|
+
* Extends Leaflet maps with bearing rotation and 3D pitch.
|
|
3
|
+
*
|
|
2
4
|
* @external L.Map
|
|
3
5
|
*
|
|
6
|
+
* @since leaflet-rotate (v0.1.0)
|
|
7
|
+
*
|
|
4
8
|
* @see https://github.com/Leaflet/Leaflet/blob/v1.9.3/src/map/Map.js
|
|
5
9
|
*/
|
|
6
10
|
|
|
7
|
-
|
|
11
|
+
/**
|
|
12
|
+
* @event L.Map#rotate Fired after the map bearing changes.
|
|
13
|
+
*
|
|
14
|
+
* @since leaflet-rotate (v0.1.0)
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @event L.Map#pitch Fired after the map pitch changes.
|
|
19
|
+
*
|
|
20
|
+
* @since leaflet-rotate (0.5.0)
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import { toPoint } from '../geometry/Point';
|
|
24
|
+
|
|
25
|
+
const mapProto = Object.defineProperties({}, Object.getOwnPropertyDescriptors(L.Map.prototype));
|
|
26
|
+
|
|
27
|
+
L.Map.mergeOptions({
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @type {boolean} Enable bearing and pitch transformations.
|
|
31
|
+
*
|
|
32
|
+
* @since leaflet-rotate (v0.1.0)
|
|
33
|
+
*/
|
|
34
|
+
rotate: false,
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @type {number} Initial map bearing in degrees.
|
|
38
|
+
*
|
|
39
|
+
* @since leaflet-rotate (v0.1.0)
|
|
40
|
+
*/
|
|
41
|
+
bearing: 0,
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @type {number} Initial map pitch in degrees, clamped to 0–85.
|
|
45
|
+
*
|
|
46
|
+
* @since leaflet-rotate (0.5.0)
|
|
47
|
+
*/
|
|
48
|
+
pitch: 0,
|
|
8
49
|
|
|
9
|
-
|
|
50
|
+
});
|
|
10
51
|
|
|
11
52
|
L.Map.include({
|
|
12
53
|
|
|
13
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Apply an immediate animated-zoom frame without waiting for a transition delay.
|
|
56
|
+
*
|
|
57
|
+
* @param {L.LatLng} center Target center.
|
|
58
|
+
* @param {number} zoom Target zoom level.
|
|
59
|
+
*
|
|
60
|
+
* @since leaflet-rotate (v0.1.0)
|
|
61
|
+
*/
|
|
62
|
+
_animateZoomNoDelay(center, zoom) {
|
|
14
63
|
if (!this._mapPane) { return; }
|
|
15
64
|
|
|
16
65
|
this._animatingZoom = true;
|
|
@@ -21,17 +70,24 @@ L.Map.include({
|
|
|
21
70
|
},
|
|
22
71
|
|
|
23
72
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
73
|
+
* Initialize the Leaflet map and apply its initial bearing and pitch.
|
|
74
|
+
*
|
|
75
|
+
* @param {HTMLElement|string} id Map container element or its ID.
|
|
76
|
+
* @param {Object} [options={}] Leaflet map options, including `rotate`, `bearing`, and `pitch`.
|
|
77
|
+
*
|
|
78
|
+
* @since leaflet-rotate (v0.1.0)
|
|
26
79
|
*/
|
|
27
|
-
initialize
|
|
80
|
+
initialize(id, options) {
|
|
28
81
|
if (options.rotate) {
|
|
29
82
|
this._rotate = true;
|
|
30
83
|
this._bearing = 0;
|
|
84
|
+
this._pitch = 0;
|
|
31
85
|
}
|
|
32
86
|
mapProto.initialize.apply(this, arguments);
|
|
33
|
-
if(this.options.rotate){
|
|
34
|
-
|
|
87
|
+
if (this.options.rotate) {
|
|
88
|
+
this.on('resize', this._updatePitchTransform, this);
|
|
89
|
+
this.setBearing(this.options.bearing);
|
|
90
|
+
this.setPitch(this.options.pitch);
|
|
35
91
|
}
|
|
36
92
|
},
|
|
37
93
|
|
|
@@ -40,14 +96,23 @@ L.Map.include({
|
|
|
40
96
|
* returns the corresponding pixel coordinate relative to
|
|
41
97
|
* the [origin pixel](#map-getpixelorigin).
|
|
42
98
|
*
|
|
43
|
-
* @param {L.Point} point
|
|
44
|
-
*
|
|
99
|
+
* @param {L.Point|number[]} point Pixel coordinate in the map container.
|
|
100
|
+
*
|
|
101
|
+
* @returns {L.Point} Corresponding layer-point coordinate.
|
|
102
|
+
*
|
|
103
|
+
* @since leaflet-rotate (v0.1.0)
|
|
45
104
|
*/
|
|
46
|
-
containerPointToLayerPoint
|
|
105
|
+
containerPointToLayerPoint(point) {
|
|
47
106
|
if (!this._rotate) {
|
|
48
107
|
return mapProto.containerPointToLayerPoint.apply(this, arguments);
|
|
49
108
|
}
|
|
50
|
-
|
|
109
|
+
if (this._pitch) {
|
|
110
|
+
return this._transformPitchPoint(
|
|
111
|
+
toPoint(point).subtract(this._getMapPanePos()),
|
|
112
|
+
this._pitchInverseTransform
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
return toPoint(point)
|
|
51
116
|
.subtract(this._getMapPanePos())
|
|
52
117
|
.rotateFrom(-this._bearing, this._getRotatePanePos())
|
|
53
118
|
.subtract(this._getRotatePanePos());
|
|
@@ -57,14 +122,20 @@ L.Map.include({
|
|
|
57
122
|
* Given a pixel coordinate relative to the [origin pixel](#map-getpixelorigin),
|
|
58
123
|
* returns the corresponding pixel coordinate relative to the map container.
|
|
59
124
|
*
|
|
60
|
-
* @param {L.Point} point
|
|
61
|
-
*
|
|
125
|
+
* @param {L.Point|number[]} point Pixel coordinate in layer-point space.
|
|
126
|
+
*
|
|
127
|
+
* @returns {L.Point} Corresponding pixel coordinate in the map container.
|
|
128
|
+
*
|
|
129
|
+
* @since leaflet-rotate (v0.1.0)
|
|
62
130
|
*/
|
|
63
|
-
layerPointToContainerPoint
|
|
131
|
+
layerPointToContainerPoint(point) {
|
|
64
132
|
if (!this._rotate) {
|
|
65
133
|
return mapProto.layerPointToContainerPoint.apply(this, arguments);
|
|
66
134
|
}
|
|
67
|
-
|
|
135
|
+
if (this._pitch) {
|
|
136
|
+
return this._transformPitchPoint(point, this._pitchTransform).add(this._getMapPanePos());
|
|
137
|
+
}
|
|
138
|
+
return toPoint(point)
|
|
68
139
|
.add(this._getRotatePanePos())
|
|
69
140
|
.rotateFrom(this._bearing, this._getRotatePanePos())
|
|
70
141
|
.add(this._getMapPanePos());
|
|
@@ -77,13 +148,17 @@ L.Map.include({
|
|
|
77
148
|
* (rotatePane) --> (mapPane)
|
|
78
149
|
* (rotatePane) --> (norotatePane)
|
|
79
150
|
*
|
|
80
|
-
* @param {L.Point} point
|
|
81
|
-
*
|
|
151
|
+
* @param {L.Point|number[]} point Point in the rotated pane.
|
|
152
|
+
*
|
|
153
|
+
* @returns {L.Point} Corresponding point in map-pane coordinates.
|
|
82
154
|
*
|
|
83
|
-
* @since leaflet-rotate (v0.1)
|
|
155
|
+
* @since leaflet-rotate (v0.1.0)
|
|
84
156
|
*/
|
|
85
|
-
rotatedPointToMapPanePoint
|
|
86
|
-
|
|
157
|
+
rotatedPointToMapPanePoint(point) {
|
|
158
|
+
if (this._pitch) {
|
|
159
|
+
return this._transformPitchPoint(point, this._pitchTransform);
|
|
160
|
+
}
|
|
161
|
+
return toPoint(point)
|
|
87
162
|
.rotate(this._bearing)
|
|
88
163
|
._add(this._getRotatePanePos());
|
|
89
164
|
},
|
|
@@ -95,22 +170,27 @@ L.Map.include({
|
|
|
95
170
|
* (mapPane) --> (rotatePane)
|
|
96
171
|
* (norotatePane) --> (rotatePane)
|
|
97
172
|
*
|
|
98
|
-
* @param {L.Point} point
|
|
173
|
+
* @param {L.Point|number[]} point Point in map-pane coordinates.
|
|
174
|
+
*
|
|
175
|
+
* @returns {L.Point} Corresponding point in the rotated pane.
|
|
99
176
|
*
|
|
100
|
-
* @since leaflet-rotate (v0.1)
|
|
177
|
+
* @since leaflet-rotate (v0.1.0)
|
|
101
178
|
*/
|
|
102
|
-
mapPanePointToRotatedPoint
|
|
103
|
-
|
|
179
|
+
mapPanePointToRotatedPoint(point) {
|
|
180
|
+
if (this._pitch) {
|
|
181
|
+
return this._transformPitchPoint(point, this._pitchInverseTransform);
|
|
182
|
+
}
|
|
183
|
+
return toPoint(point)
|
|
104
184
|
._subtract(this._getRotatePanePos())
|
|
105
185
|
.rotate(-this._bearing);
|
|
106
186
|
},
|
|
107
187
|
|
|
108
|
-
// latLngToLayerPoint
|
|
109
|
-
//
|
|
188
|
+
// latLngToLayerPoint(latlng) {
|
|
189
|
+
// const projectedPoint = this.project(L.latLng(latlng))._round();
|
|
110
190
|
// return projectedPoint._subtract(this.getPixelOrigin());
|
|
111
191
|
// },
|
|
112
192
|
|
|
113
|
-
// latLngToContainerPoint
|
|
193
|
+
// latLngToContainerPoint(latlng) {
|
|
114
194
|
// return this.layerPointToContainerPoint(this.latLngToLayerPoint(toLatLng(latlng)));
|
|
115
195
|
// },
|
|
116
196
|
|
|
@@ -120,12 +200,13 @@ L.Map.include({
|
|
|
120
200
|
*
|
|
121
201
|
* @see https://github.com/ronikar/Leaflet/blob/5c480ef959b947c3beed7065425a5a36c486262b/src/map/Map.js#L1114-L1135
|
|
122
202
|
*
|
|
123
|
-
* @param {L.LatLngBounds} bounds
|
|
124
|
-
* @returns {L.Bounds}
|
|
203
|
+
* @param {L.LatLngBounds} bounds Geographic bounds to project.
|
|
125
204
|
*
|
|
126
|
-
* @
|
|
205
|
+
* @returns {L.Bounds} Axis-aligned bounds in container-pixel coordinates.
|
|
206
|
+
*
|
|
207
|
+
* @since leaflet-rotate (v0.2.0)
|
|
127
208
|
*/
|
|
128
|
-
mapBoundsToContainerBounds
|
|
209
|
+
mapBoundsToContainerBounds(bounds) {
|
|
129
210
|
if (!this._rotate && mapProto.mapBoundsToContainerBounds) {
|
|
130
211
|
return mapProto.mapBoundsToContainerBounds.apply(this, arguments);
|
|
131
212
|
}
|
|
@@ -142,30 +223,29 @@ L.Map.include({
|
|
|
142
223
|
sw = this.layerPointToContainerPoint(this.project(bounds.getSouthWest())._subtract(origin)),
|
|
143
224
|
se = this.layerPointToContainerPoint(this.project(bounds.getSouthEast())._subtract(origin));
|
|
144
225
|
|
|
145
|
-
return L.
|
|
146
|
-
L.
|
|
147
|
-
L.
|
|
226
|
+
return new L.Bounds([
|
|
227
|
+
new L.Point(Math.min(nw.x, ne.x, se.x, sw.x), Math.min(nw.y, ne.y, se.y, sw.y)), // [ minX, minY ]
|
|
228
|
+
new L.Point(Math.max(nw.x, ne.x, se.x, sw.x), Math.max(nw.y, ne.y, se.y, sw.y)) // [ maxX, maxY ]
|
|
148
229
|
]);
|
|
149
230
|
},
|
|
150
231
|
|
|
151
232
|
/**
|
|
152
|
-
*
|
|
233
|
+
* Return the geographic bounds of the current viewport, accounting for rotation and pitch.
|
|
153
234
|
*
|
|
154
|
-
*
|
|
155
|
-
* function should match the `rotatePane` or `norotatePane` bounds
|
|
235
|
+
* The result is the smallest geographic bounds containing all four viewport corners.
|
|
156
236
|
*
|
|
157
|
-
* @
|
|
237
|
+
* @returns {L.LatLngBounds} Geographic bounds visible in the map viewport.
|
|
158
238
|
*
|
|
159
|
-
* @
|
|
239
|
+
* @since leaflet-rotate (v0.1.0)
|
|
160
240
|
*/
|
|
161
|
-
getBounds
|
|
241
|
+
getBounds() {
|
|
162
242
|
if (!this._rotate) {
|
|
163
243
|
return mapProto.getBounds.apply(this, arguments);
|
|
164
244
|
}
|
|
165
245
|
|
|
166
246
|
// SEE: https://github.com/fnicollet/Leaflet/pull/22
|
|
167
247
|
//
|
|
168
|
-
//
|
|
248
|
+
// const bounds = this.getPixelBounds(),
|
|
169
249
|
// sw = this.unproject(bounds.getBottomLeft()),
|
|
170
250
|
// ne = this.unproject(bounds.getTopRight());
|
|
171
251
|
// return new LatLngBounds(sw, ne);
|
|
@@ -173,7 +253,7 @@ L.Map.include({
|
|
|
173
253
|
|
|
174
254
|
// LatLngBounds' constructor automatically
|
|
175
255
|
// extends the bounds to fit the passed points
|
|
176
|
-
|
|
256
|
+
const size = this.getSize();
|
|
177
257
|
return new L.LatLngBounds([
|
|
178
258
|
this.containerPointToLatLng([0, 0]), // topleft
|
|
179
259
|
this.containerPointToLatLng([size.x, 0]), // topright
|
|
@@ -200,89 +280,234 @@ L.Map.include({
|
|
|
200
280
|
// },
|
|
201
281
|
|
|
202
282
|
/**
|
|
203
|
-
*
|
|
283
|
+
* Set the map bearing, optionally animating to the new value.
|
|
284
|
+
*
|
|
285
|
+
* @param {number} theta Target bearing in degrees; normalized to [0, 360).
|
|
286
|
+
* @param {Object} [options] Animation options.
|
|
287
|
+
* @param {boolean} [options.animate=false] Animate the change.
|
|
288
|
+
* @param {number} [options.duration=0.25] Animation duration in seconds.
|
|
289
|
+
* @param {number} [options.easeLinearity=0.5] Easing curve linearity.
|
|
290
|
+
*
|
|
291
|
+
* @returns {void}
|
|
204
292
|
*
|
|
205
|
-
* @
|
|
206
|
-
* @param {Object} [options] animation options
|
|
207
|
-
* @param {boolean} [options.animate=false]
|
|
208
|
-
* @param {number} [options.duration=0.25] animation duration in seconds
|
|
209
|
-
* @param {number} [options.easeLinearity=0.5]
|
|
293
|
+
* @fires L.Map#rotate
|
|
210
294
|
*
|
|
211
|
-
* @since leaflet-rotate (v0.1)
|
|
295
|
+
* @since leaflet-rotate (v0.1.0)
|
|
212
296
|
*/
|
|
213
|
-
setBearing
|
|
214
|
-
if (!
|
|
297
|
+
setBearing(theta, options) {
|
|
298
|
+
if (!this._rotate) { return; }
|
|
215
299
|
|
|
216
300
|
if (options && options.animate) {
|
|
217
301
|
this._bearingAnimationId = (this._bearingAnimationId || 0) + 1;
|
|
218
|
-
|
|
302
|
+
const animationId = this._bearingAnimationId;
|
|
219
303
|
if (this._bearingAnimationFrame) {
|
|
220
|
-
|
|
304
|
+
cancelAnimationFrame(this._bearingAnimationFrame);
|
|
221
305
|
}
|
|
222
306
|
|
|
223
|
-
|
|
307
|
+
const startBearing = this.getBearing(),
|
|
224
308
|
endBearing = L.Util.wrapNum(theta, [0, 360]),
|
|
225
309
|
delta = ((endBearing - startBearing + 540) % 360) - 180,
|
|
226
310
|
duration = Math.max(0, options.duration == null ? 0.25 : options.duration) * 1000,
|
|
227
311
|
easeLinearity = Math.max(options.easeLinearity || 0.5, 0.2),
|
|
228
312
|
startTime = performance.now();
|
|
229
313
|
|
|
230
|
-
|
|
314
|
+
const animate = function() {
|
|
231
315
|
if (!this._mapPane) {
|
|
232
316
|
delete this._bearingAnimationFrame;
|
|
233
317
|
return;
|
|
234
318
|
}
|
|
235
319
|
|
|
236
|
-
|
|
320
|
+
const progress = duration ? Math.min((performance.now() - startTime) / duration, 1) : 1,
|
|
237
321
|
eased = 1 - Math.pow(1 - progress, 1 / easeLinearity);
|
|
238
322
|
|
|
239
323
|
this._setBearing(progress === 1 ? endBearing : startBearing + delta * eased);
|
|
240
324
|
if (this._bearingAnimationId !== animationId) { return; }
|
|
241
325
|
if (progress < 1) {
|
|
242
|
-
this._bearingAnimationFrame =
|
|
326
|
+
this._bearingAnimationFrame = requestAnimationFrame(animate.bind(this));
|
|
243
327
|
} else {
|
|
244
328
|
delete this._bearingAnimationFrame;
|
|
245
329
|
}
|
|
246
330
|
};
|
|
247
331
|
|
|
248
|
-
this._bearingAnimationFrame =
|
|
332
|
+
this._bearingAnimationFrame = requestAnimationFrame(animate.bind(this));
|
|
249
333
|
return;
|
|
250
334
|
}
|
|
251
335
|
|
|
252
336
|
this._bearingAnimationId = (this._bearingAnimationId || 0) + 1;
|
|
253
337
|
if (this._bearingAnimationFrame) {
|
|
254
|
-
|
|
338
|
+
cancelAnimationFrame(this._bearingAnimationFrame);
|
|
255
339
|
delete this._bearingAnimationFrame;
|
|
256
340
|
}
|
|
257
341
|
|
|
258
342
|
this._setBearing(theta);
|
|
259
343
|
},
|
|
260
344
|
|
|
261
|
-
|
|
262
|
-
|
|
345
|
+
/**
|
|
346
|
+
* Apply a bearing immediately and update the rotated pane and map coordinates.
|
|
347
|
+
*
|
|
348
|
+
* @param {number} theta Bearing in degrees.
|
|
349
|
+
* @param {L.LatLng} [mapCenter] Center to preserve while applying the change.
|
|
350
|
+
*
|
|
351
|
+
* @fires L.Map#rotate
|
|
352
|
+
*
|
|
353
|
+
* @since leaflet-rotate (v0.1.0)
|
|
354
|
+
*/
|
|
355
|
+
_setBearing(theta, mapCenter) {
|
|
356
|
+
if (!mapCenter && this._loaded) {
|
|
357
|
+
mapCenter = this.getCenter();
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
const bearing = L.Util.wrapNum(theta, [0, 360]) * (Math.PI / 180),
|
|
263
361
|
center = this._getPixelCenter(),
|
|
264
362
|
oldPos = this._getRotatePanePos().rotateFrom(-this._bearing, center),
|
|
265
363
|
newPos = oldPos.rotateFrom(bearing, center);
|
|
266
364
|
|
|
267
|
-
// CSS transform
|
|
268
|
-
L.DomUtil.setPosition(this._rotatePane, oldPos, bearing, center);
|
|
269
|
-
|
|
270
365
|
this._pivot = center;
|
|
271
366
|
this._bearing = bearing;
|
|
272
367
|
this._rotatePanePos = newPos;
|
|
273
368
|
|
|
369
|
+
if (this._pitch) {
|
|
370
|
+
this._rotatePane._leaflet_pos = oldPos;
|
|
371
|
+
this._updatePitchTransform();
|
|
372
|
+
} else {
|
|
373
|
+
L.DomUtil.setPosition(this._rotatePane, oldPos, bearing, center);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (mapCenter) {
|
|
377
|
+
this._pixelOrigin = this.project(mapCenter, this._zoom)
|
|
378
|
+
.subtract(this.containerPointToLayerPoint(this.getSize().divideBy(2)));
|
|
379
|
+
delete this._lastCenter;
|
|
380
|
+
this.fire('move');
|
|
381
|
+
}
|
|
382
|
+
|
|
274
383
|
this.fire('rotate');
|
|
275
384
|
},
|
|
276
385
|
|
|
277
386
|
/**
|
|
278
|
-
*
|
|
387
|
+
* Transform a point with a projective matrix, accepting DOMMatrix or its 2D inverse.
|
|
279
388
|
*
|
|
280
|
-
* @
|
|
389
|
+
* @param {L.Point|number[]} point Input pixel coordinate.
|
|
390
|
+
* @param {DOMMatrix|Object} matrix Forward or inverse transformation matrix.
|
|
281
391
|
*
|
|
282
|
-
* @
|
|
392
|
+
* @returns {L.Point} Transformed pixel coordinate.
|
|
393
|
+
*
|
|
394
|
+
* @since leaflet-rotate (0.5.0)
|
|
283
395
|
*/
|
|
284
|
-
|
|
285
|
-
|
|
396
|
+
_transformPitchPoint(point, matrix) {
|
|
397
|
+
point = toPoint(point);
|
|
398
|
+
if (!(matrix instanceof DOMMatrix)) {
|
|
399
|
+
const denominator = matrix.g * point.x + matrix.h * point.y + matrix.i;
|
|
400
|
+
return new L.Point(
|
|
401
|
+
(matrix.a * point.x + matrix.b * point.y + matrix.c) / denominator,
|
|
402
|
+
(matrix.d * point.x + matrix.e * point.y + matrix.f) / denominator
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
const transformed = new DOMPoint(point.x, point.y).matrixTransform(matrix);
|
|
406
|
+
return new L.Point(transformed.x / transformed.w, transformed.y / transformed.w);
|
|
407
|
+
},
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Apply the current pitch/bearing CSS transform and cache its forward and inverse matrices.
|
|
411
|
+
*
|
|
412
|
+
* @since leaflet-rotate (0.5.0)
|
|
413
|
+
*/
|
|
414
|
+
_updatePitchTransform() {
|
|
415
|
+
if (!this._pitch || !this._rotatePane) { return; }
|
|
416
|
+
|
|
417
|
+
const pivot = this._getPixelCenter(),
|
|
418
|
+
size = this.getSize(),
|
|
419
|
+
perspective = Math.max(1, size.y * 1.5),
|
|
420
|
+
position = this._rotatePane._leaflet_pos || new L.Point(0, 0),
|
|
421
|
+
transform = `translate3d(${pivot.x}px,${pivot.y}px,0) perspective(${perspective}px) rotateX(${this.getPitch()}deg) rotateZ(${this.getBearing()}deg) translate3d(${position.x - pivot.x}px,${position.y - pivot.y}px,0)`;
|
|
422
|
+
|
|
423
|
+
this._rotatePane.style.transformOrigin = '0 0';
|
|
424
|
+
this._rotatePane.style.transform = transform;
|
|
425
|
+
const matrix = this._pitchTransform = new DOMMatrix(getComputedStyle(this._rotatePane).transform),
|
|
426
|
+
a = matrix.m11, b = matrix.m21, c = matrix.m41,
|
|
427
|
+
d = matrix.m12, e = matrix.m22, f = matrix.m42,
|
|
428
|
+
g = matrix.m14, h = matrix.m24, i = matrix.m44,
|
|
429
|
+
determinant = a * (e * i - f * h) - b * (d * i - f * g) + c * (d * h - e * g);
|
|
430
|
+
|
|
431
|
+
this._pitchInverseTransform = {
|
|
432
|
+
a: (e * i - f * h) / determinant,
|
|
433
|
+
b: (c * h - b * i) / determinant,
|
|
434
|
+
c: (b * f - c * e) / determinant,
|
|
435
|
+
d: (f * g - d * i) / determinant,
|
|
436
|
+
e: (a * i - c * g) / determinant,
|
|
437
|
+
f: (c * d - a * f) / determinant,
|
|
438
|
+
g: (d * h - e * g) / determinant,
|
|
439
|
+
h: (b * g - a * h) / determinant,
|
|
440
|
+
i: (a * e - b * d) / determinant,
|
|
441
|
+
};
|
|
442
|
+
},
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* Set the map pitch in degrees. Values are clamped to the range 0–85.
|
|
446
|
+
*
|
|
447
|
+
* @param {number} pitch Pitch angle in degrees; clamped to [0, 85].
|
|
448
|
+
*
|
|
449
|
+
* @returns {L.Map} This map instance.
|
|
450
|
+
*
|
|
451
|
+
* @fires L.Map#pitch
|
|
452
|
+
*
|
|
453
|
+
* @since leaflet-rotate (0.5.0)
|
|
454
|
+
*/
|
|
455
|
+
setPitch(pitch) {
|
|
456
|
+
this._setPitchAndBearing(pitch, this.getBearing());
|
|
457
|
+
return this;
|
|
458
|
+
},
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Update pitch and bearing together, preserving the current map center.
|
|
462
|
+
* Used by the Ctrl+drag handler to avoid applying two separate transforms.
|
|
463
|
+
*
|
|
464
|
+
* @param {number} pitch Pitch angle in degrees.
|
|
465
|
+
* @param {number} bearing Bearing angle in degrees.
|
|
466
|
+
*
|
|
467
|
+
* @fires L.Map#pitch
|
|
468
|
+
* @fires L.Map#rotate
|
|
469
|
+
*
|
|
470
|
+
* @since leaflet-rotate (0.5.0)
|
|
471
|
+
*/
|
|
472
|
+
_setPitchAndBearing(pitch, bearing) {
|
|
473
|
+
if (!this._rotate) { return; }
|
|
474
|
+
|
|
475
|
+
const clampedPitch = Math.max(0, Math.min(pitch, 85)) * (Math.PI / 180),
|
|
476
|
+
clampedBearing = L.Util.wrapNum(bearing, [0, 360]) * (Math.PI / 180),
|
|
477
|
+
pitchChanged = clampedPitch !== this._pitch;
|
|
478
|
+
if (!pitchChanged && clampedBearing === this._bearing) { return; }
|
|
479
|
+
|
|
480
|
+
const mapCenter = this._loaded ? this.getCenter() : undefined;
|
|
481
|
+
if (pitchChanged) {
|
|
482
|
+
this._pitch = clampedPitch;
|
|
483
|
+
this._rotatePane.style.transformOrigin = L.version.startsWith('2.') ? '0 0' : '';
|
|
484
|
+
}
|
|
485
|
+
this._setBearing(bearing, mapCenter);
|
|
486
|
+
if (pitchChanged) {
|
|
487
|
+
this.fire('pitch');
|
|
488
|
+
}
|
|
489
|
+
},
|
|
490
|
+
|
|
491
|
+
/**
|
|
492
|
+
* Get the current map pitch in degrees.
|
|
493
|
+
*
|
|
494
|
+
* @returns {number} Pitch angle in degrees.
|
|
495
|
+
*
|
|
496
|
+
* @since leaflet-rotate (0.5.0)
|
|
497
|
+
*/
|
|
498
|
+
getPitch() {
|
|
499
|
+
return (this._pitch || 0) * (180 / Math.PI);
|
|
500
|
+
},
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Get the current map bearing. Enable the `rotate` map option before calling.
|
|
504
|
+
*
|
|
505
|
+
* @returns {number} Bearing in degrees, normalized to [0, 360).
|
|
506
|
+
*
|
|
507
|
+
* @since leaflet-rotate (v0.1.0)
|
|
508
|
+
*/
|
|
509
|
+
getBearing() {
|
|
510
|
+
return this._bearing * (180 / Math.PI);
|
|
286
511
|
},
|
|
287
512
|
|
|
288
513
|
/**
|
|
@@ -292,9 +517,12 @@ L.Map.include({
|
|
|
292
517
|
*
|
|
293
518
|
* @param {String} name leaflet pane
|
|
294
519
|
* @param {HTMLElement} [container] parent element
|
|
520
|
+
*
|
|
295
521
|
* @returns {HTMLElement} pane container
|
|
522
|
+
*
|
|
523
|
+
* @since leaflet-rotate (v0.1.0)
|
|
296
524
|
*/
|
|
297
|
-
// createPane
|
|
525
|
+
// createPane(name, container) {
|
|
298
526
|
// if (!this._rotate || name == 'mapPane') {
|
|
299
527
|
// return mapProto.createPane.apply(this, arguments);
|
|
300
528
|
// }
|
|
@@ -323,8 +551,14 @@ L.Map.include({
|
|
|
323
551
|
* - tooltipPane [HTMLElement = 650] - Pane for tooltips.
|
|
324
552
|
* - popupPane [HTMLElement = 700] - Pane for popups.
|
|
325
553
|
*/
|
|
326
|
-
|
|
327
|
-
|
|
554
|
+
/**
|
|
555
|
+
* Create the map's panes, placing tile/vector layers in the transformed pane
|
|
556
|
+
* and markers/overlays in the pane that remains upright.
|
|
557
|
+
*
|
|
558
|
+
* @since leaflet-rotate (v0.1.0)
|
|
559
|
+
*/
|
|
560
|
+
_initPanes() {
|
|
561
|
+
const panes = this._panes = {};
|
|
328
562
|
this._paneRenderers = {};
|
|
329
563
|
|
|
330
564
|
this._mapPane = this.createPane('mapPane', this._container);
|
|
@@ -333,6 +567,9 @@ L.Map.include({
|
|
|
333
567
|
if (this._rotate) {
|
|
334
568
|
this._rotatePane = this.createPane('rotatePane', this._mapPane);
|
|
335
569
|
this._norotatePane = this.createPane('norotatePane', this._mapPane);
|
|
570
|
+
if (L.version.startsWith('2.')) {
|
|
571
|
+
this._rotatePane.style.transformOrigin = '0 0';
|
|
572
|
+
}
|
|
336
573
|
// rotatePane
|
|
337
574
|
this.createPane('tilePane', this._rotatePane);
|
|
338
575
|
this.createPane('overlayPane', this._rotatePane);
|
|
@@ -351,8 +588,8 @@ L.Map.include({
|
|
|
351
588
|
}
|
|
352
589
|
|
|
353
590
|
if (!this.options.markerZoomAnimation) {
|
|
354
|
-
|
|
355
|
-
|
|
591
|
+
panes.markerPane.classList.add('leaflet-zoom-hide');
|
|
592
|
+
panes.shadowPane.classList.add('leaflet-zoom-hide');
|
|
356
593
|
}
|
|
357
594
|
},
|
|
358
595
|
|
|
@@ -364,29 +601,31 @@ L.Map.include({
|
|
|
364
601
|
*
|
|
365
602
|
* @see https://github.com/Raruto/leaflet-rotate/issues/18
|
|
366
603
|
*
|
|
367
|
-
* @param {L.LatLng} latlng
|
|
368
|
-
* @param {Object} [options={}] padding
|
|
604
|
+
* @param {L.LatLng} latlng Geographic point to keep visible.
|
|
605
|
+
* @param {Object} [options={}] Padding options (`padding`, `paddingTopLeft`, `paddingBottomRight`).
|
|
369
606
|
*
|
|
370
607
|
* @returns {L.Map} current map instance
|
|
608
|
+
*
|
|
609
|
+
* @since leaflet-rotate (v0.1.4)
|
|
371
610
|
*/
|
|
372
611
|
panInside(latlng, options) {
|
|
373
|
-
if (!this._rotate || Math.abs(this._bearing).toFixed(1) < 0.1) {
|
|
612
|
+
if (!this._rotate || (!this._pitch && Math.abs(this._bearing).toFixed(1) < 0.1)) {
|
|
374
613
|
return mapProto.panInside.apply(this, arguments);
|
|
375
614
|
}
|
|
376
615
|
|
|
377
616
|
options = options || {};
|
|
378
617
|
|
|
379
|
-
const paddingTL =
|
|
380
|
-
paddingBR =
|
|
618
|
+
const paddingTL = toPoint(options.paddingTopLeft || options.padding || [0, 0]),
|
|
619
|
+
paddingBR = toPoint(options.paddingBottomRight || options.padding || [0, 0]),
|
|
381
620
|
/** @TODO use mapProto.panInside */
|
|
382
621
|
// pixelPoint = this.project(latlng),
|
|
383
622
|
// pixelBounds = this.getPixelBounds(),
|
|
384
623
|
// pixelCenter = this.project(this.getCenter()),
|
|
385
624
|
pixelPoint = this.latLngToContainerPoint(latlng),
|
|
386
|
-
pixelBounds = L.
|
|
625
|
+
pixelBounds = new L.Bounds([new L.Point(0, 0), this.getSize()]),
|
|
387
626
|
pixelCenter = pixelBounds.getCenter(),
|
|
388
627
|
//
|
|
389
|
-
paddedBounds = L.
|
|
628
|
+
paddedBounds = new L.Bounds([pixelBounds.min.add(paddingTL), pixelBounds.max.subtract(paddingBR)]),
|
|
390
629
|
paddedSize = paddedBounds.getSize();
|
|
391
630
|
|
|
392
631
|
if (!paddedBounds.contains(pixelPoint)) {
|
|
@@ -414,13 +653,16 @@ L.Map.include({
|
|
|
414
653
|
*
|
|
415
654
|
* @see https://github.com/fnicollet/Leaflet/issues/7
|
|
416
655
|
*
|
|
417
|
-
* @param {L.LatLngBounds} bounds
|
|
418
|
-
* @param {Object} [options]
|
|
419
|
-
*
|
|
656
|
+
* @param {L.LatLngBounds} bounds Geographic bounds to fit inside the viewport.
|
|
657
|
+
* @param {Object} [options] Pan animation options.
|
|
658
|
+
*
|
|
659
|
+
* @returns {L.Map} This map instance.
|
|
660
|
+
*
|
|
661
|
+
* @since leaflet-rotate (v0.1.0)
|
|
420
662
|
*/
|
|
421
|
-
// panInsideBounds
|
|
663
|
+
// panInsideBounds(bounds, options) {
|
|
422
664
|
// this._enforcingBounds = true;
|
|
423
|
-
//
|
|
665
|
+
// const center = this.getCenter(),
|
|
424
666
|
// newCenter = this._limitCenter(center, this._zoom, L.latLngBounds(bounds));
|
|
425
667
|
//
|
|
426
668
|
// if (!center.equals(newCenter)) {
|
|
@@ -485,19 +727,21 @@ L.Map.include({
|
|
|
485
727
|
* instead returns the minimum zoom level on which the map view fits into
|
|
486
728
|
* the given bounds in its entirety.
|
|
487
729
|
*
|
|
488
|
-
* @param {L.LatLngBounds} bounds
|
|
489
|
-
* @param {
|
|
490
|
-
* @param {L.Point} [padding=[0,0]]
|
|
730
|
+
* @param {L.LatLngBounds} bounds Geographic bounds to fit.
|
|
731
|
+
* @param {boolean} [inside=false] Fit the viewport inside bounds instead of bounds inside the viewport.
|
|
732
|
+
* @param {L.Point|number[]} [padding=[0,0]] Pixel padding around the viewport.
|
|
733
|
+
*
|
|
734
|
+
* @returns {number} Zoom level satisfying the fit.
|
|
491
735
|
*
|
|
492
|
-
* @
|
|
736
|
+
* @since leaflet-rotate (v0.1.0)
|
|
493
737
|
*/
|
|
494
738
|
getBoundsZoom(bounds, inside, padding) {
|
|
495
|
-
if (!this._rotate || Math.abs(this._bearing).toFixed(1) < 0.1) {
|
|
739
|
+
if (!this._rotate || (!this._pitch && Math.abs(this._bearing).toFixed(1) < 0.1)) {
|
|
496
740
|
return mapProto.getBoundsZoom.apply(this, arguments);
|
|
497
741
|
}
|
|
498
742
|
|
|
499
|
-
bounds = L.
|
|
500
|
-
padding =
|
|
743
|
+
bounds = bounds instanceof L.LatLngBounds ? bounds : new L.LatLngBounds(bounds);
|
|
744
|
+
padding = toPoint(padding || [0, 0]);
|
|
501
745
|
|
|
502
746
|
let zoom = this.getZoom() || 0;
|
|
503
747
|
const min = this.getMinZoom(),
|
|
@@ -529,27 +773,39 @@ L.Map.include({
|
|
|
529
773
|
*
|
|
530
774
|
* @returns {L.Point} layer center
|
|
531
775
|
*/
|
|
532
|
-
// _getCenterLayerPoint
|
|
776
|
+
// _getCenterLayerPoint() {
|
|
533
777
|
// return this.containerPointToLayerPoint(this.getSize()._divideBy(2));
|
|
534
778
|
// },
|
|
535
779
|
|
|
536
780
|
/**
|
|
537
|
-
*
|
|
781
|
+
* Return the pixel offset from the current center to the given geographic point.
|
|
538
782
|
*
|
|
539
|
-
* @param {L.LatLng} latlng
|
|
783
|
+
* @param {L.LatLng} latlng Geographic point.
|
|
784
|
+
*
|
|
785
|
+
* @returns {L.Point} Offset in layer pixels, adjusted for bearing and pitch.
|
|
786
|
+
*
|
|
787
|
+
* @since leaflet-rotate (v0.1.0)
|
|
540
788
|
*/
|
|
541
|
-
_getCenterOffset
|
|
542
|
-
|
|
543
|
-
if (this.
|
|
789
|
+
_getCenterOffset(latlng) {
|
|
790
|
+
let centerOffset = mapProto._getCenterOffset.apply(this, arguments);
|
|
791
|
+
if (this._pitch) {
|
|
792
|
+
const center = this.getSize()._divideBy(2);
|
|
793
|
+
centerOffset = this.containerPointToLayerPoint(center.add(centerOffset))
|
|
794
|
+
.subtract(this.containerPointToLayerPoint(center));
|
|
795
|
+
} else if (this._rotate) {
|
|
544
796
|
centerOffset = centerOffset.rotate(this._bearing);
|
|
545
797
|
}
|
|
546
798
|
return centerOffset;
|
|
547
799
|
},
|
|
548
800
|
|
|
549
801
|
/**
|
|
550
|
-
*
|
|
802
|
+
* Return the current position of the rotated pane.
|
|
803
|
+
*
|
|
804
|
+
* @returns {L.Point} Rotated-pane position in map-pane coordinates.
|
|
805
|
+
*
|
|
806
|
+
* @since leaflet-rotate (v0.1.0)
|
|
551
807
|
*/
|
|
552
|
-
_getRotatePanePos
|
|
808
|
+
_getRotatePanePos() {
|
|
553
809
|
return this._rotatePanePos || new L.Point(0, 0);
|
|
554
810
|
// return L.DomUtil.getPosition(this._rotatePane) || new L.Point(0, 0);
|
|
555
811
|
},
|
|
@@ -559,11 +815,21 @@ L.Map.include({
|
|
|
559
815
|
// return this.project(latlng, zoom)._subtract(topLeft);
|
|
560
816
|
//},
|
|
561
817
|
|
|
562
|
-
|
|
563
|
-
|
|
818
|
+
/**
|
|
819
|
+
* Calculate the pixel origin for a target view while preserving bearing-aware alignment.
|
|
820
|
+
*
|
|
821
|
+
* @param {L.LatLng} center Target center.
|
|
822
|
+
* @param {number} zoom Target zoom level.
|
|
823
|
+
*
|
|
824
|
+
* @returns {L.Point} New pixel origin.
|
|
825
|
+
*
|
|
826
|
+
* @since leaflet-rotate (v0.1.0)
|
|
827
|
+
*/
|
|
828
|
+
_getNewPixelOrigin(center, zoom) {
|
|
829
|
+
if (!this._rotate || L.version.startsWith('2.')) {
|
|
564
830
|
return mapProto._getNewPixelOrigin.apply(this, arguments);
|
|
565
831
|
}
|
|
566
|
-
|
|
832
|
+
const viewHalf = this.getSize()._divideBy(2);
|
|
567
833
|
return this.project(center, zoom)
|
|
568
834
|
.rotate(this._bearing)
|
|
569
835
|
._subtract(viewHalf)
|
|
@@ -574,17 +840,24 @@ L.Map.include({
|
|
|
574
840
|
},
|
|
575
841
|
|
|
576
842
|
/**
|
|
577
|
-
*
|
|
843
|
+
* Calculate the pixel bounds needed to cover the transformed viewport.
|
|
844
|
+
*
|
|
845
|
+
* @param {L.LatLng} [center=this.getCenter()] Target center.
|
|
846
|
+
* @param {number} [zoom=this.getZoom()] Target zoom level.
|
|
847
|
+
*
|
|
848
|
+
* @returns {L.Bounds} Pixel bounds in projected map coordinates.
|
|
849
|
+
*
|
|
850
|
+
* @since leaflet-rotate (v0.2.0)
|
|
578
851
|
*
|
|
579
852
|
* @see src\layer\tile\GridLayer::_getTiledPixelBounds()
|
|
580
853
|
*/
|
|
581
|
-
_getNewPixelBounds
|
|
854
|
+
_getNewPixelBounds(center, zoom) {
|
|
582
855
|
center = center || this.getCenter();
|
|
583
856
|
zoom = zoom || this.getZoom();
|
|
584
857
|
if (!this._rotate && mapProto._getNewPixelBounds) {
|
|
585
858
|
return mapProto._getNewPixelBounds.apply(this, arguments);
|
|
586
859
|
}
|
|
587
|
-
|
|
860
|
+
const mapZoom = this._animatingZoom ? Math.max(this._animateToZoom, this.getZoom()) : this.getZoom(),
|
|
588
861
|
scale = this.getZoomScale(mapZoom, zoom),
|
|
589
862
|
pixelCenter = this.project(center, zoom).floor(),
|
|
590
863
|
size = this.getSize(),
|
|
@@ -599,11 +872,11 @@ L.Map.include({
|
|
|
599
872
|
},
|
|
600
873
|
|
|
601
874
|
/**
|
|
602
|
-
* @since leaflet-rotate (v0.2)
|
|
875
|
+
* @since leaflet-rotate (v0.2.0)
|
|
603
876
|
*
|
|
604
|
-
* @
|
|
877
|
+
* @returns {L.Point} Map pivot point in pixel coordinates.
|
|
605
878
|
*/
|
|
606
|
-
_getPixelCenter
|
|
879
|
+
_getPixelCenter() {
|
|
607
880
|
if (!this._rotate && mapProto._getPixelCenter) {
|
|
608
881
|
return mapProto._getPixelCenter.apply(this, arguments);
|
|
609
882
|
}
|
|
@@ -611,15 +884,19 @@ L.Map.include({
|
|
|
611
884
|
},
|
|
612
885
|
|
|
613
886
|
/**
|
|
614
|
-
* @since leaflet-rotate (v0.2)
|
|
615
|
-
*
|
|
616
887
|
* @see src\layer\vector\Renderer::_update()
|
|
888
|
+
*
|
|
889
|
+
* @param {number} padding Bounds padding as a fraction of map size.
|
|
890
|
+
*
|
|
891
|
+
* @returns {L.Bounds} Padded bounds in layer-point coordinates.
|
|
892
|
+
*
|
|
893
|
+
* @since leaflet-rotate (v0.2.0)
|
|
617
894
|
*/
|
|
618
|
-
_getPaddedPixelBounds
|
|
895
|
+
_getPaddedPixelBounds(padding) {
|
|
619
896
|
if (!this._rotate && mapProto._getPaddedPixelBounds) {
|
|
620
897
|
return mapProto._getPaddedPixelBounds.apply(this, arguments);
|
|
621
898
|
}
|
|
622
|
-
|
|
899
|
+
const p = padding,
|
|
623
900
|
size = this.getSize(),
|
|
624
901
|
padMin = size.multiplyBy(-p),
|
|
625
902
|
padMax = size.multiplyBy(1 + p);
|
|
@@ -633,10 +910,19 @@ L.Map.include({
|
|
|
633
910
|
]);
|
|
634
911
|
},
|
|
635
912
|
|
|
636
|
-
|
|
913
|
+
/**
|
|
914
|
+
* Build and fire Leaflet's location-found event, including the device heading.
|
|
915
|
+
*
|
|
916
|
+
* @param {GeolocationPosition} pos Browser geolocation result.
|
|
917
|
+
*
|
|
918
|
+
* @fires L.Map#locationfound
|
|
919
|
+
*
|
|
920
|
+
* @since leaflet-rotate (v0.1.0)
|
|
921
|
+
*/
|
|
922
|
+
_handleGeolocationResponse(pos) {
|
|
637
923
|
if (!this._container._leaflet_id) { return; }
|
|
638
924
|
|
|
639
|
-
|
|
925
|
+
const lat = pos.coords.latitude,
|
|
640
926
|
lng = pos.coords.longitude,
|
|
641
927
|
/** @TODO use mapProto._handleGeolocationResponse */
|
|
642
928
|
hdg = pos.coords.heading,
|
|
@@ -645,11 +931,11 @@ L.Map.include({
|
|
|
645
931
|
options = this._locateOptions;
|
|
646
932
|
|
|
647
933
|
if (options.setView) {
|
|
648
|
-
|
|
934
|
+
const zoom = this.getBoundsZoom(bounds);
|
|
649
935
|
this.setView(latlng, options.maxZoom ? Math.min(zoom, options.maxZoom) : zoom);
|
|
650
936
|
}
|
|
651
937
|
|
|
652
|
-
|
|
938
|
+
const data = {
|
|
653
939
|
latlng: latlng,
|
|
654
940
|
bounds: bounds,
|
|
655
941
|
timestamp: pos.timestamp,
|
|
@@ -657,7 +943,7 @@ L.Map.include({
|
|
|
657
943
|
heading: hdg
|
|
658
944
|
};
|
|
659
945
|
|
|
660
|
-
for (
|
|
946
|
+
for (const i in pos.coords) {
|
|
661
947
|
if (typeof pos.coords[i] === 'number') {
|
|
662
948
|
data[i] = pos.coords[i];
|
|
663
949
|
}
|
|
@@ -673,10 +959,11 @@ L.Map.include({
|
|
|
673
959
|
* @see https://github.com/ronikar/Leaflet/blob/5c480ef959b947c3beed7065425a5a36c486262b/src/geo/LatLngBounds.js#L253-L264
|
|
674
960
|
*
|
|
675
961
|
* @param {L.Bounds} points
|
|
962
|
+
*
|
|
676
963
|
* @returns {L.Bounds}
|
|
677
964
|
*/
|
|
678
965
|
// toCircumscribedBounds(points) {
|
|
679
|
-
//
|
|
966
|
+
// const minX = points.reduce(function (pv, v) { return Math.min(pv, v.x); }, points[0].x),
|
|
680
967
|
// maxX = points.reduce(function (pv, v) { return Math.max(pv, v.x); }, points[0].x),
|
|
681
968
|
// minY = points.reduce(function (pv, v) { return Math.min(pv, v.y); }, points[0].y),
|
|
682
969
|
// maxY = points.reduce(function (pv, v) { return Math.max(pv, v.y); }, points[0].y);
|