leaflet-rotate 0.2.8 → 0.4.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/.github/workflows/ci.yml +21 -0
- package/README.md +6 -2
- package/build/build.js +69 -0
- package/build/dev.js +24 -0
- package/build/server.js +104 -0
- package/build/test.js +18 -0
- package/cucumber.mjs +5 -0
- package/dist/leaflet-rotate-src.js +1425 -1853
- package/dist/leaflet-rotate-src.js.map +7 -1
- package/dist/leaflet-rotate.js +1 -1
- package/dist/leaflet-rotate.js.map +7 -1
- package/lib/debug.js +98 -69
- package/lib/debug.min.js +1 -1
- package/misc/leaflet-heat-rotate.js +96 -0
- package/misc/loremIpsum.js +1 -1
- package/misc/places.js +1 -1
- package/misc/route.js +1 -1
- package/package.json +10 -17
- package/src/control/Rotate.js +25 -25
- package/src/dom/DomUtil.js +31 -47
- package/src/dom/Draggable.js +1 -1
- package/src/geometry/Point.js +16 -7
- package/src/layer/DivOverlay.js +21 -7
- package/src/layer/Popup.js +15 -13
- package/src/layer/Tooltip.js +5 -5
- package/src/layer/marker/Icon.js +8 -8
- package/src/layer/marker/Marker.js +32 -18
- package/src/layer/tile/GridLayer.js +4 -4
- package/src/layer/vector/Renderer.js +51 -7
- package/src/map/Map.js +121 -57
- package/src/map/handler/CompassBearing.js +10 -8
- package/src/map/handler/ContainerMutation.js +2 -2
- package/src/map/handler/ShiftKeyRotate.js +4 -4
- package/src/map/handler/TouchGestures.js +36 -22
- package/src/map/handler/TouchRotate.js +2 -2
- package/src/map/handler/TouchZoom.js +4 -4
- package/test/features/example.feature +92 -0
- package/test/features/gestures.feature +33 -0
- package/test/features/overlays.feature +58 -0
- package/test/features/rotation.feature +36 -0
- package/test/index.html +59 -22
- package/test/steps/bearing.steps.js +235 -0
- package/test/steps/example.steps.js +424 -0
- package/test/steps/gestures.steps.js +145 -0
- package/test/steps/overlays.steps.js +427 -0
- package/test/support/hooks.js +92 -0
- package/build/rollup.config.js +0 -34
- package/test/setup/http_server.js +0 -104
|
@@ -1,1936 +1,1508 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
var leafletRotate = (() => {
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.js
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
toPoint: () => toPoint
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// src/dom/DomUtil.js
|
|
27
|
+
var domUtilProto = Object.assign({}, L.DomUtil);
|
|
28
|
+
Object.assign(L.DomUtil, {
|
|
29
|
+
/**
|
|
30
|
+
* Resets the 3D CSS transform of `el` so it is translated by `offset` pixels,
|
|
31
|
+
* optionally scaled by `scale`, and rotated around `pivot` when `bearing` is set.
|
|
32
|
+
*
|
|
33
|
+
* @param {HTMLElement} el
|
|
34
|
+
* @param {L.Point} offset
|
|
35
|
+
* @param {Number} scale
|
|
36
|
+
* @param {Number} bearing
|
|
37
|
+
* @param {L.Point} pivot
|
|
38
|
+
*/
|
|
39
|
+
setTransform(el, offset, scale, bearing, pivot) {
|
|
40
|
+
let pos = offset || new L.Point(0, 0);
|
|
41
|
+
if (!bearing) {
|
|
42
|
+
return domUtilProto.setTransform(el, pos._round(), scale);
|
|
43
|
+
}
|
|
44
|
+
pos = pos.rotateFrom(bearing, pivot);
|
|
45
|
+
el.style.transform = "translate3d(" + pos.x + "px," + pos.y + "px,0)" + (scale ? " scale(" + scale + ")" : "") + " rotate(" + bearing + "rad)";
|
|
46
|
+
},
|
|
47
|
+
/**
|
|
48
|
+
* Sets the position of `el` to `point`, using CSS transforms or top/left positioning
|
|
49
|
+
* depending on browser support, and optionally rotating it around `pivot`.
|
|
50
|
+
*
|
|
51
|
+
* @param {HTMLElement} el
|
|
52
|
+
* @param {L.Point} point
|
|
53
|
+
* @param {Number} bearing
|
|
54
|
+
* @param {L.Point} pivot
|
|
55
|
+
* @param {Number} scale
|
|
56
|
+
*/
|
|
57
|
+
setPosition(el, point, bearing, pivot, scale) {
|
|
58
|
+
if (!bearing) {
|
|
59
|
+
return domUtilProto.setPosition(el, point);
|
|
60
|
+
}
|
|
61
|
+
el._leaflet_pos = point;
|
|
62
|
+
L.DomUtil.setTransform(el, point, scale, bearing, pivot);
|
|
63
|
+
},
|
|
64
|
+
/**
|
|
65
|
+
* Returns the position assigned to `el`.
|
|
66
|
+
*
|
|
67
|
+
* @param {HTMLElement} el
|
|
68
|
+
* @returns {L.Point}
|
|
69
|
+
*/
|
|
70
|
+
getPosition(el) {
|
|
71
|
+
return el._leaflet_pos || domUtilProto.getPosition(el);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// src/dom/Draggable.js
|
|
76
|
+
L.Draggable.include({
|
|
77
|
+
/** @TODO */
|
|
78
|
+
// updateMapBearing(mapBearing) {
|
|
79
|
+
// this._mapBearing = mapBearing;
|
|
80
|
+
// },
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// src/geometry/Point.js
|
|
84
|
+
Object.assign(L.Point.prototype, {
|
|
6
85
|
/**
|
|
7
|
-
*
|
|
86
|
+
* Rotate around (0,0) by applying the 2D rotation matrix:
|
|
8
87
|
*
|
|
9
|
-
*
|
|
88
|
+
* ⎡ x' ⎤ = ⎡ cos θ -sin θ ⎤ ⎡ x ⎤
|
|
89
|
+
* ⎣ y' ⎦ ⎣ sin θ cos θ ⎦ ⎣ y ⎦
|
|
90
|
+
*
|
|
91
|
+
* @param theta must be given in radians.
|
|
10
92
|
*/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
L.extend(L.DomUtil, {
|
|
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
|
-
*/
|
|
28
|
-
setTransform: function(el, offset, scale, bearing, pivot) {
|
|
29
|
-
var pos = offset || new L.Point(0, 0);
|
|
30
|
-
|
|
31
|
-
if (!bearing) {
|
|
32
|
-
offset = pos._round();
|
|
33
|
-
return domUtilProto.setTransform.apply(this, arguments);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
pos = pos.rotateFrom(bearing, pivot);
|
|
37
|
-
|
|
38
|
-
el.style[L.DomUtil.TRANSFORM] =
|
|
39
|
-
'translate3d(' + pos.x + 'px,' + pos.y + 'px' + ',0)' +
|
|
40
|
-
(scale ? ' scale(' + scale + ')' : '') +
|
|
41
|
-
' rotate(' + bearing + 'rad)';
|
|
42
|
-
},
|
|
43
|
-
|
|
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) {
|
|
57
|
-
if (!bearing) {
|
|
58
|
-
return domUtilProto.setPosition.apply(this, arguments);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/*eslint-disable */
|
|
62
|
-
el._leaflet_pos = point;
|
|
63
|
-
/*eslint-enable */
|
|
64
|
-
|
|
65
|
-
if (L.Browser.any3d) {
|
|
66
|
-
L.DomUtil.setTransform(el, point, scale, bearing, pivot);
|
|
67
|
-
} else {
|
|
68
|
-
el.style.left = point.x + 'px';
|
|
69
|
-
el.style.top = point.y + 'px';
|
|
70
|
-
}
|
|
71
|
-
},
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* @constant radians = degrees × π/180°
|
|
75
|
-
*/
|
|
76
|
-
DEG_TO_RAD: Math.PI / 180,
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* @constant degrees = radians × 180°/π
|
|
80
|
-
*/
|
|
81
|
-
RAD_TO_DEG: 180 / Math.PI,
|
|
82
|
-
|
|
83
|
-
});
|
|
84
|
-
|
|
93
|
+
rotate(theta) {
|
|
94
|
+
return this.rotateFrom(theta, new L.Point(0, 0));
|
|
95
|
+
},
|
|
85
96
|
/**
|
|
86
|
-
*
|
|
97
|
+
* Rotate around (pivot.x, pivot.y) by:
|
|
98
|
+
*
|
|
99
|
+
* 1. subtract (pivot.x, pivot.y)
|
|
100
|
+
* 2. rotate around (0, 0)
|
|
101
|
+
* 3. add (pivot.x, pivot.y) back
|
|
87
102
|
*
|
|
88
|
-
*
|
|
103
|
+
* same as `this.subtract(pivot).rotate(theta).add(pivot)`
|
|
104
|
+
*
|
|
105
|
+
* @param {Number} theta
|
|
106
|
+
* @param {L.Point} pivot
|
|
107
|
+
*
|
|
108
|
+
* @returns {L.Point}
|
|
89
109
|
*/
|
|
90
|
-
|
|
110
|
+
rotateFrom(theta, pivot) {
|
|
111
|
+
if (!theta) {
|
|
112
|
+
return this;
|
|
113
|
+
}
|
|
114
|
+
const sinTheta = Math.sin(theta);
|
|
115
|
+
const cosTheta = Math.cos(theta);
|
|
116
|
+
const cx = pivot.x, cy = pivot.y;
|
|
117
|
+
const x = this.x - cx, y = this.y - cy;
|
|
118
|
+
return new L.Point(
|
|
119
|
+
x * cosTheta - y * sinTheta + cx,
|
|
120
|
+
x * sinTheta + y * cosTheta + cy
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
function toPoint(point) {
|
|
125
|
+
if (point == null || point instanceof L.Point) {
|
|
126
|
+
return point;
|
|
127
|
+
}
|
|
128
|
+
return Array.isArray(point) ? new L.Point(point[0], point[1]) : new L.Point(point.x, point.y);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// src/layer/DivOverlay.js
|
|
132
|
+
var divOverlayProto = Object.defineProperties({}, Object.getOwnPropertyDescriptors(L.DivOverlay.prototype));
|
|
133
|
+
L.DivOverlay.include({
|
|
91
134
|
/**
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
135
|
+
* Update L.Popup and L.Tooltip anchor positions after
|
|
136
|
+
* the map is moved by calling `map.setBearing(theta)`
|
|
137
|
+
*
|
|
138
|
+
* @listens L.Map~rotate
|
|
95
139
|
*/
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
140
|
+
getEvents() {
|
|
141
|
+
return Object.assign(divOverlayProto.getEvents.apply(this, arguments), { rotate: this._updatePosition });
|
|
142
|
+
},
|
|
143
|
+
/**
|
|
144
|
+
* 0. update element anchor point (divOverlayProto v1.9.3)
|
|
145
|
+
* 1. rotate around anchor point (subtract anchor -> rotate point -> add anchor)
|
|
146
|
+
*/
|
|
147
|
+
_updatePosition() {
|
|
148
|
+
if (!this._map) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
divOverlayProto._updatePosition.apply(this, arguments);
|
|
152
|
+
if (this._map._rotate && this._zoomAnimated) {
|
|
153
|
+
const anchor = this._getAnchor();
|
|
154
|
+
const pos = L.DomUtil.getPosition(this._container).subtract(anchor);
|
|
155
|
+
L.DomUtil.setPosition(this._container, this._map.rotatedPointToMapPanePoint(pos).add(anchor));
|
|
156
|
+
} else if (this._map._rotate) {
|
|
157
|
+
const mapPanePoint = this._map.rotatedPointToMapPanePoint(this._map.latLngToLayerPoint(this._latlng)), offset = toPoint(this.options.offset || [0, 0]), anchor = this._getAnchor();
|
|
158
|
+
this._containerLeft = -Math.round(this._containerWidth / 2) + mapPanePoint.x + offset.x + anchor.x;
|
|
159
|
+
this._containerBottom = -(mapPanePoint.y + offset.y + anchor.y);
|
|
160
|
+
this._container.style.left = this._containerLeft + "px";
|
|
161
|
+
this._container.style.bottom = this._containerBottom + "px";
|
|
162
|
+
this._container.style.top = "";
|
|
163
|
+
L.DomUtil.setPosition(this._container, new L.Point(0, 0));
|
|
164
|
+
this._container.style.transform = "";
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// src/layer/Popup.js
|
|
170
|
+
var popupProto = Object.defineProperties({}, Object.getOwnPropertyDescriptors(L.Popup.prototype));
|
|
171
|
+
L.Popup.include({
|
|
172
|
+
/**
|
|
173
|
+
* 0. update element anchor point (popupProto v1.9.3)
|
|
174
|
+
* 1. rotate around anchor point (subtract anchor -> rotate point -> add anchor)
|
|
175
|
+
*/
|
|
176
|
+
_animateZoom(e) {
|
|
177
|
+
popupProto._animateZoom.apply(this, arguments);
|
|
178
|
+
if (this._map && this._map._rotate) {
|
|
179
|
+
const anchor = this._getAnchor();
|
|
180
|
+
const pos = L.DomUtil.getPosition(this._container).subtract(anchor);
|
|
181
|
+
L.DomUtil.setPosition(this._container, this._map.rotatedPointToMapPanePoint(pos).add(anchor));
|
|
182
|
+
}
|
|
183
|
+
},
|
|
106
184
|
/**
|
|
107
|
-
*
|
|
185
|
+
* Fix for L.popup({ keepInView = true })
|
|
108
186
|
*
|
|
109
|
-
* @see https://github.com/
|
|
187
|
+
* @see https://github.com/fnicollet/Leaflet/pull/21
|
|
110
188
|
*/
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
189
|
+
_adjustPan() {
|
|
190
|
+
if (!this.options.autoPan || this._map._panAnim && this._map._panAnim._inProgress) {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
if (this._autopanning) {
|
|
194
|
+
this._autopanning = false;
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
const map = this._map, marginBottom = parseInt(getComputedStyle(this._container).marginBottom, 10) || 0, containerHeight = this._container.offsetHeight + marginBottom, containerWidth = this._containerWidth, layerPos = new L.Point(this._containerLeft, -containerHeight - this._containerBottom);
|
|
198
|
+
layerPos._add(L.DomUtil.getPosition(this._container));
|
|
199
|
+
const containerPos = layerPos._add(this._map._getMapPanePos()), padding = toPoint(this.options.autoPanPadding || [0, 0]), paddingTL = toPoint(this.options.autoPanPaddingTopLeft || padding), paddingBR = toPoint(this.options.autoPanPaddingBottomRight || padding), size = map.getSize();
|
|
200
|
+
let dx = 0, dy = 0;
|
|
201
|
+
if (containerPos.x + containerWidth + paddingBR.x > size.x) {
|
|
202
|
+
dx = containerPos.x + containerWidth - size.x + paddingBR.x;
|
|
203
|
+
}
|
|
204
|
+
if (containerPos.x - dx - paddingTL.x < 0) {
|
|
205
|
+
dx = containerPos.x - paddingTL.x;
|
|
206
|
+
}
|
|
207
|
+
if (containerPos.y + containerHeight + paddingBR.y > size.y) {
|
|
208
|
+
dy = containerPos.y + containerHeight - size.y + paddingBR.y;
|
|
209
|
+
}
|
|
210
|
+
if (containerPos.y - dy - paddingTL.y < 0) {
|
|
211
|
+
dy = containerPos.y - paddingTL.y;
|
|
212
|
+
}
|
|
213
|
+
if (dx || dy) {
|
|
214
|
+
if (this.options.keepInView) {
|
|
215
|
+
this._autopanning = true;
|
|
216
|
+
}
|
|
217
|
+
map.fire("autopanstart").panBy([dx, dy]);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
// src/layer/Tooltip.js
|
|
223
|
+
var tooltipProto = Object.defineProperties({}, Object.getOwnPropertyDescriptors(L.Tooltip.prototype));
|
|
224
|
+
L.Tooltip.include({
|
|
225
|
+
_animateZoom(e) {
|
|
226
|
+
if (!this._map._rotate) {
|
|
227
|
+
return tooltipProto._animateZoom.apply(this, arguments);
|
|
228
|
+
}
|
|
229
|
+
let pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center);
|
|
230
|
+
pos = this._map.rotatedPointToMapPanePoint(pos);
|
|
231
|
+
this._setPosition(pos);
|
|
232
|
+
},
|
|
233
|
+
_updatePosition() {
|
|
234
|
+
if (!this._map._rotate) {
|
|
235
|
+
return tooltipProto._updatePosition.apply(this, arguments);
|
|
236
|
+
}
|
|
237
|
+
let pos = this._map.latLngToLayerPoint(this._latlng);
|
|
238
|
+
pos = this._map.rotatedPointToMapPanePoint(pos);
|
|
239
|
+
this._setPosition(pos);
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
// src/layer/marker/Icon.js
|
|
244
|
+
var iconProto = Object.defineProperties({}, Object.getOwnPropertyDescriptors(L.Icon.prototype));
|
|
245
|
+
L.Icon.include({
|
|
246
|
+
_setIconStyles(img, name) {
|
|
247
|
+
const options = this.options;
|
|
248
|
+
let sizeOption = options[name + "Size"];
|
|
249
|
+
if (typeof sizeOption === "number") {
|
|
250
|
+
sizeOption = [sizeOption, sizeOption];
|
|
251
|
+
}
|
|
252
|
+
const size = sizeOption ? new L.Point(...Array.isArray(sizeOption) ? sizeOption : [sizeOption.x, sizeOption.y]) : null, anchorOption = name === "shadow" && options.shadowAnchor || options.iconAnchor || size && size.divideBy(2, true), anchor = anchorOption ? new L.Point(...Array.isArray(anchorOption) ? anchorOption : [anchorOption.x, anchorOption.y]) : null;
|
|
253
|
+
img.className = "leaflet-marker-" + name + " " + (options.className || "");
|
|
254
|
+
if (anchor) {
|
|
255
|
+
img.style.marginLeft = -anchor.x + "px";
|
|
256
|
+
img.style.marginTop = -anchor.y + "px";
|
|
257
|
+
img.style.transformOrigin = anchor.x + "px " + anchor.y + "px 0px";
|
|
258
|
+
}
|
|
259
|
+
if (size) {
|
|
260
|
+
img.style.width = size.x + "px";
|
|
261
|
+
img.style.height = size.y + "px";
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
// src/layer/marker/Marker.js
|
|
267
|
+
var markerProto = Object.defineProperties({}, Object.getOwnPropertyDescriptors(L.Marker.prototype));
|
|
268
|
+
L.Marker.mergeOptions({
|
|
157
269
|
/**
|
|
158
|
-
*
|
|
270
|
+
* Rotation of this marker in rad
|
|
159
271
|
*
|
|
160
|
-
* @
|
|
272
|
+
* @type {Number}
|
|
161
273
|
*/
|
|
162
|
-
|
|
163
|
-
const divOverlayProto = L.extend({}, L.DivOverlay.prototype);
|
|
164
|
-
|
|
165
|
-
L.DivOverlay.include({
|
|
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
|
-
*/
|
|
173
|
-
getEvents: function() {
|
|
174
|
-
return L.extend(divOverlayProto.getEvents.apply(this, arguments), { rotate: this._updatePosition });
|
|
175
|
-
},
|
|
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
|
-
*/
|
|
181
|
-
_updatePosition: function() {
|
|
182
|
-
if (!this._map) { return; }
|
|
183
|
-
divOverlayProto._updatePosition.apply(this, arguments);
|
|
184
|
-
if (this._map && this._map._rotate && this._zoomAnimated) {
|
|
185
|
-
var anchor = this._getAnchor();
|
|
186
|
-
var pos = L.DomUtil.getPosition(this._container).subtract(anchor);
|
|
187
|
-
L.DomUtil.setPosition(this._container, this._map.rotatedPointToMapPanePoint(pos).add(anchor));
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
},
|
|
191
|
-
|
|
192
|
-
});
|
|
193
|
-
|
|
274
|
+
rotation: 0,
|
|
194
275
|
/**
|
|
195
|
-
*
|
|
276
|
+
* Rotate this marker when map rotates
|
|
196
277
|
*
|
|
197
|
-
* @
|
|
278
|
+
* @type {Boolean}
|
|
198
279
|
*/
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
* 1. rotate around anchor point (subtract anchor -> rotate point -> add anchor)
|
|
207
|
-
*/
|
|
208
|
-
_animateZoom: function(e) {
|
|
209
|
-
popupProto._animateZoom.apply(this, arguments);
|
|
210
|
-
if (this._map && this._map._rotate) {
|
|
211
|
-
var anchor = this._getAnchor();
|
|
212
|
-
var pos = L.DomUtil.getPosition(this._container).subtract(anchor);
|
|
213
|
-
L.DomUtil.setPosition(this._container, this._map.rotatedPointToMapPanePoint(pos).add(anchor));
|
|
214
|
-
}
|
|
215
|
-
},
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* Fix for L.popup({ keepInView = true })
|
|
219
|
-
*
|
|
220
|
-
* @see https://github.com/fnicollet/Leaflet/pull/21
|
|
221
|
-
*/
|
|
222
|
-
_adjustPan: function() {
|
|
223
|
-
if (!this.options.autoPan || (this._map._panAnim && this._map._panAnim._inProgress)) { return; }
|
|
224
|
-
|
|
225
|
-
// We can endlessly recurse if keepInView is set and the view resets.
|
|
226
|
-
// Let's guard against that by exiting early if we're responding to our own autopan.
|
|
227
|
-
if (this._autopanning) {
|
|
228
|
-
this._autopanning = false;
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
var map = this._map,
|
|
233
|
-
marginBottom = parseInt(L.DomUtil.getStyle(this._container, 'marginBottom'), 10) || 0,
|
|
234
|
-
containerHeight = this._container.offsetHeight + marginBottom,
|
|
235
|
-
containerWidth = this._containerWidth,
|
|
236
|
-
layerPos = new L.Point(this._containerLeft, -containerHeight - this._containerBottom);
|
|
237
|
-
|
|
238
|
-
layerPos._add(L.DomUtil.getPosition(this._container));
|
|
239
|
-
|
|
240
|
-
/** @TODO use popupProto._adjustPan */
|
|
241
|
-
// var containerPos = map.layerPointToContainerPoint(layerPos);
|
|
242
|
-
var containerPos = layerPos._add(this._map._getMapPanePos()),
|
|
243
|
-
padding = L.point(this.options.autoPanPadding),
|
|
244
|
-
paddingTL = L.point(this.options.autoPanPaddingTopLeft || padding),
|
|
245
|
-
paddingBR = L.point(this.options.autoPanPaddingBottomRight || padding),
|
|
246
|
-
size = map.getSize(),
|
|
247
|
-
dx = 0,
|
|
248
|
-
dy = 0;
|
|
249
|
-
|
|
250
|
-
if (containerPos.x + containerWidth + paddingBR.x > size.x) { // right
|
|
251
|
-
dx = containerPos.x + containerWidth - size.x + paddingBR.x;
|
|
252
|
-
}
|
|
253
|
-
if (containerPos.x - dx - paddingTL.x < 0) { // left
|
|
254
|
-
dx = containerPos.x - paddingTL.x;
|
|
255
|
-
}
|
|
256
|
-
if (containerPos.y + containerHeight + paddingBR.y > size.y) { // bottom
|
|
257
|
-
dy = containerPos.y + containerHeight - size.y + paddingBR.y;
|
|
258
|
-
}
|
|
259
|
-
if (containerPos.y - dy - paddingTL.y < 0) { // top
|
|
260
|
-
dy = containerPos.y - paddingTL.y;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// @namespace Map
|
|
264
|
-
// @section Popup events
|
|
265
|
-
// @event autopanstart: Event
|
|
266
|
-
// Fired when the map starts autopanning when opening a popup.
|
|
267
|
-
if (dx || dy) {
|
|
268
|
-
// Track that we're autopanning, as this function will be re-ran on moveend
|
|
269
|
-
if (this.options.keepInView) {
|
|
270
|
-
this._autopanning = true;
|
|
271
|
-
}
|
|
272
|
-
map
|
|
273
|
-
.fire('autopanstart')
|
|
274
|
-
.panBy([dx, dy]);
|
|
275
|
-
}
|
|
276
|
-
},
|
|
277
|
-
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
+
rotateWithView: false,
|
|
281
|
+
/**
|
|
282
|
+
* Flip a rotated marker when needed to keep it upright
|
|
283
|
+
*
|
|
284
|
+
* @type {Boolean}
|
|
285
|
+
*/
|
|
286
|
+
keepUpright: false,
|
|
280
287
|
/**
|
|
281
|
-
*
|
|
288
|
+
* Scale of the marker icon
|
|
282
289
|
*
|
|
283
|
-
* @
|
|
290
|
+
* @type {Number}
|
|
284
291
|
*/
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
292
|
+
scale: void 0
|
|
293
|
+
});
|
|
294
|
+
var markerDragProto;
|
|
295
|
+
var MarkerDrag = {
|
|
296
|
+
// _onDragStart() {
|
|
297
|
+
// if (!this._marker._map._rotate) {
|
|
298
|
+
// return markerDragProto._onDragStart.apply(this, arguments);
|
|
299
|
+
// }
|
|
300
|
+
// this._draggable.updateMapBearing(this._marker._map._bearing);
|
|
301
|
+
// },
|
|
302
|
+
_onDrag(e) {
|
|
303
|
+
const marker = this._marker, rotated_marker = marker.options.rotation || marker.options.rotateWithView, shadow = marker._shadow;
|
|
304
|
+
let iconPos = L.DomUtil.getPosition(marker._icon);
|
|
305
|
+
if (!rotated_marker && shadow) {
|
|
306
|
+
L.DomUtil.setPosition(shadow, iconPos);
|
|
307
|
+
}
|
|
308
|
+
if (marker._map._rotate) {
|
|
309
|
+
iconPos = marker._map.mapPanePointToRotatedPoint(iconPos);
|
|
310
|
+
}
|
|
311
|
+
const latlng = marker._map.layerPointToLatLng(iconPos);
|
|
312
|
+
marker._latlng = latlng;
|
|
313
|
+
e.latlng = latlng;
|
|
314
|
+
e.oldLatLng = this._oldLatLng;
|
|
315
|
+
if (rotated_marker) marker.setLatLng(latlng);
|
|
316
|
+
else marker.fire("move", e);
|
|
317
|
+
marker.fire("drag", e);
|
|
318
|
+
},
|
|
319
|
+
_onDragEnd(e) {
|
|
320
|
+
if (this._marker._map._rotate) {
|
|
321
|
+
this._marker.update();
|
|
322
|
+
}
|
|
323
|
+
markerDragProto._onDragEnd.apply(this, arguments);
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
L.Marker.include({
|
|
312
327
|
/**
|
|
313
|
-
*
|
|
328
|
+
* Update L.Marker anchor position after the map
|
|
329
|
+
* is moved by calling `map.setBearing(theta)`
|
|
314
330
|
*
|
|
315
|
-
* @
|
|
331
|
+
* @listens L.Map~rotate
|
|
316
332
|
*/
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
333
|
+
getEvents() {
|
|
334
|
+
return Object.assign(markerProto.getEvents.apply(this, arguments), { rotate: this.update });
|
|
335
|
+
},
|
|
336
|
+
_initInteraction() {
|
|
337
|
+
const ret = markerProto._initInteraction.apply(this, arguments);
|
|
338
|
+
if (this.dragging && this.dragging.enabled() && this._map && this._map._rotate) {
|
|
339
|
+
markerDragProto = markerDragProto || Object.getPrototypeOf(this.dragging);
|
|
340
|
+
this.dragging.disable();
|
|
341
|
+
Object.assign(this.dragging, {
|
|
342
|
+
// _onDragStart: MarkerDrag._onDragStart.bind(this.dragging),
|
|
343
|
+
_onDrag: MarkerDrag._onDrag.bind(this.dragging),
|
|
344
|
+
_onDragEnd: MarkerDrag._onDragEnd.bind(this.dragging)
|
|
345
|
+
});
|
|
346
|
+
this.dragging.enable();
|
|
347
|
+
}
|
|
348
|
+
return ret;
|
|
349
|
+
},
|
|
350
|
+
_setPos(pos) {
|
|
351
|
+
if (this._map._rotate) {
|
|
352
|
+
pos = this._map.rotatedPointToMapPanePoint(pos);
|
|
353
|
+
}
|
|
354
|
+
let bearing = this.options.rotation || 0;
|
|
355
|
+
if (this.options.rotateWithView) {
|
|
356
|
+
bearing += this._map._bearing;
|
|
357
|
+
}
|
|
358
|
+
if (this.options.keepUpright) {
|
|
359
|
+
bearing = (bearing % (2 * Math.PI) + 2 * Math.PI) % (2 * Math.PI);
|
|
360
|
+
if (bearing > Math.PI / 2 && bearing < 3 * Math.PI / 2) {
|
|
361
|
+
bearing += Math.PI;
|
|
362
|
+
}
|
|
363
|
+
bearing %= 2 * Math.PI;
|
|
364
|
+
}
|
|
365
|
+
if (this._icon) {
|
|
366
|
+
L.DomUtil.setPosition(this._icon, pos, bearing, pos, this.options.scale);
|
|
367
|
+
}
|
|
368
|
+
if (this._shadow) {
|
|
369
|
+
L.DomUtil.setPosition(this._shadow, pos, bearing, pos, this.options.scale);
|
|
370
|
+
}
|
|
371
|
+
this._zIndex = pos.y + this.options.zIndexOffset;
|
|
372
|
+
this._resetZIndex();
|
|
373
|
+
},
|
|
374
|
+
// _updateZIndex(offset) {
|
|
375
|
+
// if (!this._map._rotate) {
|
|
376
|
+
// return markerProto._updateZIndex.apply(this, arguments);
|
|
377
|
+
// }
|
|
378
|
+
// this._icon.style.zIndex = Math.round(this._zIndex + offset);
|
|
379
|
+
// },
|
|
380
|
+
setRotation(rotation) {
|
|
381
|
+
this.options.rotation = rotation;
|
|
382
|
+
this.update();
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
// src/layer/tile/GridLayer.js
|
|
387
|
+
var gridLayerProto = Object.defineProperties({}, Object.getOwnPropertyDescriptors(L.GridLayer.prototype));
|
|
388
|
+
L.GridLayer.include({
|
|
351
389
|
/**
|
|
352
|
-
*
|
|
353
|
-
*
|
|
390
|
+
* Redraw L.TileLayer bounds after the map is
|
|
391
|
+
* moved by just calling `map.setBearing(theta)`
|
|
354
392
|
*
|
|
355
|
-
* @
|
|
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
|
|
393
|
+
* @listens L.Map~rotate
|
|
358
394
|
*/
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
*/
|
|
383
|
-
scale: undefined,
|
|
384
|
-
|
|
385
|
-
});
|
|
386
|
-
|
|
387
|
-
var markerDragProto; // retrived at runtime (see below: L.Marker::_initInteraction())
|
|
388
|
-
|
|
389
|
-
var MarkerDrag = {
|
|
390
|
-
|
|
391
|
-
// _onDragStart: function() {
|
|
392
|
-
// if (!this._marker._map._rotate) {
|
|
393
|
-
// return markerDragProto._onDragStart.apply(this, arguments);
|
|
394
|
-
// }
|
|
395
|
-
// this._draggable.updateMapBearing(this._marker._map._bearing);
|
|
396
|
-
// },
|
|
397
|
-
|
|
398
|
-
_onDrag: function(e) {
|
|
399
|
-
var marker = this._marker,
|
|
400
|
-
/** @TODO use markerDragProto._onDrag */
|
|
401
|
-
rotated_marker = marker.options.rotation || marker.options.rotateWithView,
|
|
402
|
-
shadow = marker._shadow,
|
|
403
|
-
iconPos = L.DomUtil.getPosition(marker._icon);
|
|
404
|
-
|
|
405
|
-
/** @TODO use markerDragProto._onDrag */
|
|
406
|
-
// update shadow position
|
|
407
|
-
if (!rotated_marker && shadow) {
|
|
408
|
-
L.DomUtil.setPosition(shadow, iconPos);
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
/** @TODO use markerDragProto._onDrag */
|
|
412
|
-
if (marker._map._rotate) {
|
|
413
|
-
// Reverse calculation from mapPane coordinates to rotatePane coordinates
|
|
414
|
-
iconPos = marker._map.mapPanePointToRotatedPoint(iconPos);
|
|
415
|
-
}
|
|
416
|
-
var latlng = marker._map.layerPointToLatLng(iconPos);
|
|
417
|
-
|
|
418
|
-
marker._latlng = latlng;
|
|
419
|
-
e.latlng = latlng;
|
|
420
|
-
e.oldLatLng = this._oldLatLng;
|
|
421
|
-
|
|
422
|
-
/** @TODO use markerDragProto._onDrag */
|
|
423
|
-
if (rotated_marker) marker.setLatLng(latlng); // use `setLatLng` to presisit rotation. low efficiency
|
|
424
|
-
else marker.fire('move', e); // `setLatLng` will trig 'move' event. we imitate here.
|
|
425
|
-
|
|
426
|
-
// @event drag: Event
|
|
427
|
-
// Fired repeatedly while the user drags the marker.
|
|
428
|
-
marker
|
|
429
|
-
.fire('drag', e);
|
|
430
|
-
},
|
|
431
|
-
|
|
432
|
-
_onDragEnd: function(e) {
|
|
433
|
-
if (this._marker._map._rotate) {
|
|
434
|
-
this._marker.update();
|
|
435
|
-
}
|
|
436
|
-
markerDragProto._onDragEnd.apply(this, arguments);
|
|
437
|
-
},
|
|
438
|
-
|
|
439
|
-
};
|
|
440
|
-
|
|
441
|
-
L.Marker.include({
|
|
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
|
-
*/
|
|
449
|
-
getEvents: function() {
|
|
450
|
-
return L.extend(markerProto.getEvents.apply(this, arguments), { rotate: this.update });
|
|
451
|
-
},
|
|
452
|
-
|
|
453
|
-
_initInteraction: function() {
|
|
454
|
-
var ret = markerProto._initInteraction.apply(this, arguments);
|
|
455
|
-
if (this.dragging && this.dragging.enabled() && this._map && this._map._rotate) {
|
|
456
|
-
// L.Handler.MarkerDrag is used internally by L.Marker to make the markers draggable
|
|
457
|
-
markerDragProto = markerDragProto || Object.getPrototypeOf(this.dragging);
|
|
458
|
-
this.dragging.disable();
|
|
459
|
-
Object.assign(this.dragging, {
|
|
460
|
-
// _onDragStart: MarkerDrag._onDragStart.bind(this.dragging),
|
|
461
|
-
_onDrag: MarkerDrag._onDrag.bind(this.dragging),
|
|
462
|
-
_onDragEnd: MarkerDrag._onDragEnd.bind(this.dragging),
|
|
463
|
-
});
|
|
464
|
-
this.dragging.enable();
|
|
465
|
-
}
|
|
466
|
-
return ret;
|
|
467
|
-
},
|
|
468
|
-
|
|
469
|
-
_setPos: function(pos) {
|
|
470
|
-
|
|
471
|
-
/** @TODO use markerProto._setPos */
|
|
472
|
-
if (this._map._rotate) {
|
|
473
|
-
pos = this._map.rotatedPointToMapPanePoint(pos);
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
/** @TODO use markerProto._setPos */
|
|
477
|
-
var bearing = this.options.rotation || 0;
|
|
478
|
-
if (this.options.rotateWithView) {
|
|
479
|
-
bearing += this._map._bearing;
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
/** @TODO use markerProto._setPos */
|
|
483
|
-
if (this._icon) {
|
|
484
|
-
L.DomUtil.setPosition(this._icon, pos, bearing, pos, this.options.scale);
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
/** @TODO use markerProto._setPos */
|
|
488
|
-
if (this._shadow) {
|
|
489
|
-
L.DomUtil.setPosition(this._shadow, pos, bearing, pos, this.options.scale);
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
this._zIndex = pos.y + this.options.zIndexOffset;
|
|
493
|
-
|
|
494
|
-
this._resetZIndex();
|
|
495
|
-
},
|
|
496
|
-
|
|
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
|
-
// },
|
|
503
|
-
|
|
504
|
-
setRotation: function(rotation) {
|
|
505
|
-
this.options.rotation = rotation;
|
|
506
|
-
this.update();
|
|
507
|
-
},
|
|
508
|
-
|
|
509
|
-
});
|
|
510
|
-
|
|
395
|
+
getEvents() {
|
|
396
|
+
const events = gridLayerProto.getEvents.apply(this, arguments);
|
|
397
|
+
if (this._map._rotate && !this.options.updateWhenIdle) {
|
|
398
|
+
if (!this._onRotate) {
|
|
399
|
+
this._onRotate = L.Util.throttle(this._onMoveEnd, this.options.updateInterval, this);
|
|
400
|
+
}
|
|
401
|
+
events.rotate = this._onRotate;
|
|
402
|
+
}
|
|
403
|
+
return events;
|
|
404
|
+
},
|
|
405
|
+
_getTiledPixelBounds(center) {
|
|
406
|
+
if (!this._map._rotate) {
|
|
407
|
+
return gridLayerProto._getTiledPixelBounds.apply(this, arguments);
|
|
408
|
+
}
|
|
409
|
+
return this._map._getNewPixelBounds(center, this._tileZoom);
|
|
410
|
+
}
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
// src/layer/vector/Renderer.js
|
|
414
|
+
var rendererProto = Object.defineProperties({}, Object.getOwnPropertyDescriptors(L.Renderer.prototype));
|
|
415
|
+
var rendererBase = Object.getPrototypeOf(L.Renderer.prototype);
|
|
416
|
+
var rendererGetEvents = rendererProto.getEvents || rendererBase.getEvents;
|
|
417
|
+
L.Renderer.include({
|
|
511
418
|
/**
|
|
512
|
-
*
|
|
419
|
+
* Redraw L.Canvas and L.SVG renderer bounds after the
|
|
420
|
+
* map is moved by just calling `map.setBearing(theta)`
|
|
513
421
|
*
|
|
514
|
-
* @
|
|
422
|
+
* @listens L.Map~rotate
|
|
515
423
|
*/
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
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
|
-
*/
|
|
527
|
-
getEvents: function() {
|
|
528
|
-
var events = gridLayerProto.getEvents.apply(this, arguments);
|
|
529
|
-
if (this._map._rotate && !this.options.updateWhenIdle) {
|
|
530
|
-
if (!this._onRotate) {
|
|
531
|
-
this._onRotate = L.Util.throttle(this._onMoveEnd, this.options.updateInterval, this);
|
|
532
|
-
}
|
|
533
|
-
events.rotate = this._onRotate;
|
|
534
|
-
}
|
|
535
|
-
return events;
|
|
536
|
-
},
|
|
537
|
-
|
|
538
|
-
_getTiledPixelBounds: function(center) {
|
|
539
|
-
if (!this._map._rotate) {
|
|
540
|
-
return gridLayerProto._getTiledPixelBounds.apply(this, arguments);
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
return this._map._getNewPixelBounds(center, this._tileZoom);
|
|
544
|
-
},
|
|
545
|
-
|
|
546
|
-
});
|
|
547
|
-
|
|
424
|
+
getEvents() {
|
|
425
|
+
const events = rendererGetEvents.apply(this, arguments);
|
|
426
|
+
return L.version.startsWith("2.") ? events : Object.assign(events, { rotate: this._update });
|
|
427
|
+
},
|
|
548
428
|
/**
|
|
549
|
-
*
|
|
429
|
+
* Fix for `map.flyTo()` when `false === map.options.zoomAnimation`
|
|
550
430
|
*
|
|
551
|
-
* @see https://github.com/Leaflet/Leaflet/
|
|
431
|
+
* @see https://github.com/Leaflet/Leaflet/pull/8794
|
|
552
432
|
*/
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
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
|
-
},
|
|
567
|
-
|
|
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
|
-
},
|
|
580
|
-
|
|
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
|
-
*
|
|
596
|
-
* @TODO rechek this changes from leaflet@v1.9.3
|
|
597
|
-
*
|
|
598
|
-
* @see https://github.com/Leaflet/Leaflet/compare/v1.7.0...v1.9.3
|
|
599
|
-
*/
|
|
600
|
-
_updateTransform: function(center, zoom) {
|
|
601
|
-
if (!this._map._rotate) {
|
|
602
|
-
return rendererProto._updateTransform.apply(this, arguments);
|
|
603
|
-
}
|
|
604
|
-
/**
|
|
605
|
-
* @FIXME see path._renderer._reset();
|
|
606
|
-
*/
|
|
607
|
-
var scale = this._map.getZoomScale(zoom, this._zoom),
|
|
608
|
-
offset = this._map._latLngToNewLayerPoint(this._topLeft, zoom, center);
|
|
609
|
-
|
|
610
|
-
L.DomUtil.setTransform(this._container, offset, scale);
|
|
611
|
-
|
|
612
|
-
},
|
|
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
|
-
|
|
656
|
-
_update: function() {
|
|
657
|
-
if (!this._map._rotate) {
|
|
658
|
-
return rendererProto._update.apply(this, arguments);
|
|
659
|
-
}
|
|
660
|
-
// Update pixel bounds of renderer container (for positioning/sizing/clipping later)
|
|
661
|
-
// Subclasses are responsible of firing the 'update' event.
|
|
662
|
-
this._bounds = this._map._getPaddedPixelBounds(this.options.padding);
|
|
663
|
-
this._topLeft = this._map.layerPointToLatLng(this._bounds.min);
|
|
664
|
-
this._center = this._map.getCenter();
|
|
665
|
-
this._zoom = this._map.getZoom();
|
|
666
|
-
},
|
|
667
|
-
|
|
668
|
-
});
|
|
669
|
-
|
|
433
|
+
onAdd() {
|
|
434
|
+
rendererProto.onAdd.apply(this, arguments);
|
|
435
|
+
if (L.version <= "1.9.3") {
|
|
436
|
+
this._container.classList.add("leaflet-zoom-animated");
|
|
437
|
+
}
|
|
438
|
+
},
|
|
670
439
|
/**
|
|
671
|
-
* @
|
|
440
|
+
* @FIXME layer drifts on `map.setZoom()` (eg. zoom during animation)
|
|
441
|
+
*
|
|
442
|
+
* the main cause seems to be related to `this._updateTransform(path._center, path._zoom))`
|
|
443
|
+
* and `this._topLeft = this._map.layerPointToLatLng(this._bounds.min);`
|
|
444
|
+
*
|
|
445
|
+
* @example
|
|
446
|
+
* map.setZoom(2);
|
|
447
|
+
* path._renderer._update();
|
|
448
|
+
* path._renderer._updateTransform(path._renderer._center, path._renderer._zoom);
|
|
672
449
|
*
|
|
673
|
-
* @see https://github.com/Leaflet/Leaflet/
|
|
450
|
+
* @see https://github.com/Leaflet/Leaflet/pull/8794
|
|
451
|
+
* @see https://github.com/Leaflet/Leaflet/pull/8103
|
|
452
|
+
* @see https://github.com/Leaflet/Leaflet/issues/7466
|
|
453
|
+
*
|
|
454
|
+
* @TODO rechek this changes from leaflet@v1.9.3
|
|
455
|
+
*
|
|
456
|
+
* @see https://github.com/Leaflet/Leaflet/compare/v1.7.0...v1.9.3
|
|
674
457
|
*/
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
/**
|
|
777
|
-
* Given latlng bounds, returns the bounds in projected pixel
|
|
778
|
-
* relative to the map container.
|
|
779
|
-
*
|
|
780
|
-
* @see https://github.com/ronikar/Leaflet/blob/5c480ef959b947c3beed7065425a5a36c486262b/src/map/Map.js#L1114-L1135
|
|
781
|
-
*
|
|
782
|
-
* @param {L.LatLngBounds} bounds
|
|
783
|
-
* @returns {L.Bounds}
|
|
784
|
-
*
|
|
785
|
-
* @since leaflet-rotate (v0.2)
|
|
786
|
-
*/
|
|
787
|
-
mapBoundsToContainerBounds: function (bounds) {
|
|
788
|
-
if (!this._rotate && mapProto.mapBoundsToContainerBounds) {
|
|
789
|
-
return mapProto.mapBoundsToContainerBounds.apply(this, arguments);
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
// const nw = this.latLngToContainerPoint(bounds.getNorthWest()),
|
|
793
|
-
// ne = this.latLngToContainerPoint(bounds.getNorthEast()),
|
|
794
|
-
// sw = this.latLngToContainerPoint(bounds.getSouthWest()),
|
|
795
|
-
// se = this.latLngToContainerPoint(bounds.getSouthEast());
|
|
796
|
-
|
|
797
|
-
// same as `this.latLngToContainerPoint(latlng)` but with floating point precision
|
|
798
|
-
const origin = this.getPixelOrigin();
|
|
799
|
-
const nw = this.layerPointToContainerPoint(this.project(bounds.getNorthWest())._subtract(origin)),
|
|
800
|
-
ne = this.layerPointToContainerPoint(this.project(bounds.getNorthEast())._subtract(origin)),
|
|
801
|
-
sw = this.layerPointToContainerPoint(this.project(bounds.getSouthWest())._subtract(origin)),
|
|
802
|
-
se = this.layerPointToContainerPoint(this.project(bounds.getSouthEast())._subtract(origin));
|
|
803
|
-
|
|
804
|
-
return L.bounds([
|
|
805
|
-
L.point(Math.min(nw.x, ne.x, se.x, sw.x), Math.min(nw.y, ne.y, se.y, sw.y)), // [ minX, minY ]
|
|
806
|
-
L.point(Math.max(nw.x, ne.x, se.x, sw.x), Math.max(nw.y, ne.y, se.y, sw.y)) // [ maxX, maxY ]
|
|
807
|
-
]);
|
|
808
|
-
},
|
|
809
|
-
|
|
810
|
-
/**
|
|
811
|
-
* Returns geographical bounds visible in the current map view
|
|
812
|
-
*
|
|
813
|
-
* @TODO find out if map bounds calculated by `L.Map::getBounds()`
|
|
814
|
-
* function should match the `rotatePane` or `norotatePane` bounds
|
|
815
|
-
*
|
|
816
|
-
* @see https://github.com/fnicollet/Leaflet/issues/7
|
|
817
|
-
*
|
|
818
|
-
* @returns {L.LatLngBounds}
|
|
819
|
-
*/
|
|
820
|
-
getBounds: function() {
|
|
821
|
-
if (!this._rotate) {
|
|
822
|
-
return mapProto.getBounds.apply(this, arguments);
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
// SEE: https://github.com/fnicollet/Leaflet/pull/22
|
|
826
|
-
//
|
|
827
|
-
// var bounds = this.getPixelBounds(),
|
|
828
|
-
// sw = this.unproject(bounds.getBottomLeft()),
|
|
829
|
-
// ne = this.unproject(bounds.getTopRight());
|
|
830
|
-
// return new LatLngBounds(sw, ne);
|
|
831
|
-
//
|
|
832
|
-
|
|
833
|
-
// LatLngBounds' constructor automatically
|
|
834
|
-
// extends the bounds to fit the passed points
|
|
835
|
-
var size = this.getSize();
|
|
836
|
-
return new L.LatLngBounds([
|
|
837
|
-
this.containerPointToLatLng([0, 0]), // topleft
|
|
838
|
-
this.containerPointToLatLng([size.x, 0]), // topright
|
|
839
|
-
this.containerPointToLatLng([size.x, size.y]), // bottomright
|
|
840
|
-
this.containerPointToLatLng([0, size.y]), // bottomleft
|
|
841
|
-
]);
|
|
842
|
-
},
|
|
843
|
-
|
|
844
|
-
/**
|
|
845
|
-
* Returns the bounds of the current map view in projected pixel
|
|
846
|
-
* coordinates (sometimes useful in layer and overlay implementations).
|
|
847
|
-
*
|
|
848
|
-
* @TODO find out if map bounds calculated by `L.Map::getPixelBounds()`
|
|
849
|
-
* function should match the `rotatePane` or `norotatePane` bounds
|
|
850
|
-
*
|
|
851
|
-
* @see https://github.com/fnicollet/Leaflet/issues/7
|
|
852
|
-
*
|
|
853
|
-
* @returns {L.Bounds}
|
|
854
|
-
*/
|
|
855
|
-
// getPixelBounds(center, zoom) {
|
|
856
|
-
// // const topLeftPoint = map.containerPointToLayerPoint(this._getTopLeftPoint());
|
|
857
|
-
// const topLeftPoint = this._getTopLeftPoint(center, zoom);
|
|
858
|
-
// return new L.Bounds(topLeftPoint, topLeftPoint.add(this.getSize()));
|
|
859
|
-
// },
|
|
860
|
-
|
|
861
|
-
/**
|
|
862
|
-
* Change map rotation
|
|
863
|
-
*
|
|
864
|
-
* @param {number} theta map degrees
|
|
865
|
-
*
|
|
866
|
-
* @since leaflet-rotate (v0.1)
|
|
867
|
-
*/
|
|
868
|
-
setBearing: function(theta) {
|
|
869
|
-
if (!L.Browser.any3d || !this._rotate) { return; }
|
|
870
|
-
|
|
871
|
-
var bearing = L.Util.wrapNum(theta, [0, 360]) * L.DomUtil.DEG_TO_RAD,
|
|
872
|
-
center = this._getPixelCenter(),
|
|
873
|
-
oldPos = this._getRotatePanePos().rotateFrom(-this._bearing, center),
|
|
874
|
-
newPos = oldPos.rotateFrom(bearing, center);
|
|
875
|
-
|
|
876
|
-
// CSS transform
|
|
877
|
-
L.DomUtil.setPosition(this._rotatePane, oldPos, bearing, center);
|
|
878
|
-
|
|
879
|
-
this._pivot = center;
|
|
880
|
-
this._bearing = bearing;
|
|
881
|
-
this._rotatePanePos = newPos;
|
|
882
|
-
|
|
883
|
-
this.fire('rotate');
|
|
884
|
-
},
|
|
885
|
-
|
|
886
|
-
/**
|
|
887
|
-
* Get current map rotation
|
|
888
|
-
*
|
|
889
|
-
* @returns {number} theta map degrees
|
|
890
|
-
*
|
|
891
|
-
* @since leaflet-rotate (v0.1)
|
|
892
|
-
*/
|
|
893
|
-
getBearing: function() {
|
|
894
|
-
return this._bearing * L.DomUtil.RAD_TO_DEG;
|
|
895
|
-
},
|
|
896
|
-
|
|
897
|
-
/**
|
|
898
|
-
* Creates a new [map pane](#map-pane) with the given name if it doesn't
|
|
899
|
-
* exist already, then returns it. The pane is created as a child of
|
|
900
|
-
* `container`, or as a child of the main map pane if not set.
|
|
901
|
-
*
|
|
902
|
-
* @param {String} name leaflet pane
|
|
903
|
-
* @param {HTMLElement} [container] parent element
|
|
904
|
-
* @returns {HTMLElement} pane container
|
|
905
|
-
*/
|
|
906
|
-
// createPane: function(name, container) {
|
|
907
|
-
// if (!this._rotate || name == 'mapPane') {
|
|
908
|
-
// return mapProto.createPane.apply(this, arguments);
|
|
909
|
-
// }
|
|
910
|
-
// // init "rotatePane"
|
|
911
|
-
// if (!this._rotatePane) {
|
|
912
|
-
// // this._pivot = this.getSize().divideBy(2);
|
|
913
|
-
// this._rotatePane = mapProto.createPane.call(this, 'rotatePane', this._mapPane);
|
|
914
|
-
// L.DomUtil.setPosition(this._rotatePane, new L.Point(0, 0), this._bearing, this._pivot);
|
|
915
|
-
// }
|
|
916
|
-
// return mapProto.createPane.call(this, name, container || this._rotatePane);
|
|
917
|
-
// },
|
|
918
|
-
|
|
919
|
-
/**
|
|
920
|
-
* Panes are DOM elements used to control the ordering of layers on
|
|
921
|
-
* the map. You can access panes with [`map.getPane`](#map-getpane)
|
|
922
|
-
* or [`map.getPanes`](#map-getpanes) methods. New panes can be created
|
|
923
|
-
* with the [`map.createPane`](#map-createpane) method.
|
|
924
|
-
*
|
|
925
|
-
* Every map has the following default panes that differ only in zIndex:
|
|
926
|
-
*
|
|
927
|
-
* - mapPane [HTMLElement = 'auto'] - Pane that contains all other map panes
|
|
928
|
-
* - tilePane [HTMLElement = 2] - Pane for tile layers
|
|
929
|
-
* - overlayPane [HTMLElement = 4] - Pane for overlays like polylines and polygons
|
|
930
|
-
* - shadowPane [HTMLElement = 5] - Pane for overlay shadows (e.g. marker shadows)
|
|
931
|
-
* - markerPane [HTMLElement = 6] - Pane for marker icons
|
|
932
|
-
* - tooltipPane [HTMLElement = 650] - Pane for tooltips.
|
|
933
|
-
* - popupPane [HTMLElement = 700] - Pane for popups.
|
|
934
|
-
*/
|
|
935
|
-
_initPanes: function() {
|
|
936
|
-
var panes = this._panes = {};
|
|
937
|
-
this._paneRenderers = {};
|
|
938
|
-
|
|
939
|
-
this._mapPane = this.createPane('mapPane', this._container);
|
|
940
|
-
L.DomUtil.setPosition(this._mapPane, new L.Point(0, 0));
|
|
941
|
-
|
|
942
|
-
if (this._rotate) {
|
|
943
|
-
this._rotatePane = this.createPane('rotatePane', this._mapPane);
|
|
944
|
-
this._norotatePane = this.createPane('norotatePane', this._mapPane);
|
|
945
|
-
// rotatePane
|
|
946
|
-
this.createPane('tilePane', this._rotatePane);
|
|
947
|
-
this.createPane('overlayPane', this._rotatePane);
|
|
948
|
-
// norotatePane
|
|
949
|
-
this.createPane('shadowPane', this._norotatePane);
|
|
950
|
-
this.createPane('markerPane', this._norotatePane);
|
|
951
|
-
this.createPane('tooltipPane', this._norotatePane);
|
|
952
|
-
this.createPane('popupPane', this._norotatePane);
|
|
953
|
-
} else {
|
|
954
|
-
this.createPane('tilePane');
|
|
955
|
-
this.createPane('overlayPane');
|
|
956
|
-
this.createPane('shadowPane');
|
|
957
|
-
this.createPane('markerPane');
|
|
958
|
-
this.createPane('tooltipPane');
|
|
959
|
-
this.createPane('popupPane');
|
|
960
|
-
}
|
|
961
|
-
|
|
962
|
-
if (!this.options.markerZoomAnimation) {
|
|
963
|
-
L.DomUtil.addClass(panes.markerPane, 'leaflet-zoom-hide');
|
|
964
|
-
L.DomUtil.addClass(panes.shadowPane, 'leaflet-zoom-hide');
|
|
965
|
-
}
|
|
966
|
-
},
|
|
967
|
-
|
|
968
|
-
/**
|
|
969
|
-
* Pans the map the minimum amount to make the `latlng` visible. Use
|
|
970
|
-
* padding options to fit the display to more restricted bounds.
|
|
971
|
-
* If `latlng` is already within the (optionally padded) display bounds,
|
|
972
|
-
* the map will not be panned.
|
|
973
|
-
*
|
|
974
|
-
* @see https://github.com/Raruto/leaflet-rotate/issues/18
|
|
975
|
-
*
|
|
976
|
-
* @param {L.LatLng} latlng coordinates
|
|
977
|
-
* @param {Object} [options={}] padding options
|
|
978
|
-
*
|
|
979
|
-
* @returns {L.Map} current map instance
|
|
980
|
-
*/
|
|
981
|
-
panInside(latlng, options) {
|
|
982
|
-
if (!this._rotate || Math.abs(this._bearing).toFixed(1) < 0.1) {
|
|
983
|
-
return mapProto.panInside.apply(this, arguments);
|
|
984
|
-
}
|
|
985
|
-
|
|
986
|
-
options = options || {};
|
|
987
|
-
|
|
988
|
-
const paddingTL = L.point(options.paddingTopLeft || options.padding || [0, 0]),
|
|
989
|
-
paddingBR = L.point(options.paddingBottomRight || options.padding || [0, 0]),
|
|
990
|
-
/** @TODO use mapProto.panInside */
|
|
991
|
-
// pixelPoint = this.project(latlng),
|
|
992
|
-
// pixelBounds = this.getPixelBounds(),
|
|
993
|
-
// pixelCenter = this.project(this.getCenter()),
|
|
994
|
-
rect = this._container.getBoundingClientRect(),
|
|
995
|
-
pixelPoint = this.latLngToContainerPoint(latlng),
|
|
996
|
-
pixelBounds = L.bounds([ L.point(rect), L.point(rect).add(this.getSize()) ]),
|
|
997
|
-
pixelCenter = pixelBounds.getCenter(),
|
|
998
|
-
//
|
|
999
|
-
paddedBounds = L.bounds([pixelBounds.min.add(paddingTL), pixelBounds.max.subtract(paddingBR)]),
|
|
1000
|
-
paddedSize = paddedBounds.getSize();
|
|
1001
|
-
|
|
1002
|
-
if (!paddedBounds.contains(pixelPoint)) {
|
|
1003
|
-
this._enforcingBounds = true;
|
|
1004
|
-
const centerOffset = pixelPoint.subtract(paddedBounds.getCenter());
|
|
1005
|
-
const offset = paddedBounds.extend(pixelPoint).getSize().subtract(paddedSize);
|
|
1006
|
-
pixelCenter.x += centerOffset.x < 0 ? -offset.x : offset.x;
|
|
1007
|
-
pixelCenter.y += centerOffset.y < 0 ? -offset.y : offset.y;
|
|
1008
|
-
/** @TODO use mapProto.panInside */
|
|
1009
|
-
// this.panTo(this.unproject(pixelCenter), options);
|
|
1010
|
-
this.panTo(this.containerPointToLatLng(pixelCenter), options);
|
|
1011
|
-
//
|
|
1012
|
-
this._enforcingBounds = false;
|
|
1013
|
-
}
|
|
1014
|
-
return this;
|
|
1015
|
-
},
|
|
1016
|
-
|
|
1017
|
-
/**
|
|
1018
|
-
* Pans the map to the closest view that would lie inside the given bounds
|
|
1019
|
-
* (if it's not already), controlling the animation using the options specific,
|
|
1020
|
-
* if any.
|
|
1021
|
-
*
|
|
1022
|
-
* @TODO check if map bounds calculated by `L.Map::panInsideBounds()`
|
|
1023
|
-
* function should match the `rotatePane` or `norotatePane` bounds
|
|
1024
|
-
*
|
|
1025
|
-
* @see https://github.com/fnicollet/Leaflet/issues/7
|
|
1026
|
-
*
|
|
1027
|
-
* @param {L.LatLngBounds} bounds coordinates
|
|
1028
|
-
* @param {Object} [options] pan options
|
|
1029
|
-
* @returns {L.Map} current map instance
|
|
1030
|
-
*/
|
|
1031
|
-
// panInsideBounds: function (bounds, options) {
|
|
1032
|
-
// this._enforcingBounds = true;
|
|
1033
|
-
// var center = this.getCenter(),
|
|
1034
|
-
// newCenter = this._limitCenter(center, this._zoom, L.latLngBounds(bounds));
|
|
1035
|
-
//
|
|
1036
|
-
// if (!center.equals(newCenter)) {
|
|
1037
|
-
// this.panTo(newCenter, options);
|
|
1038
|
-
// }
|
|
1039
|
-
//
|
|
1040
|
-
// this._enforcingBounds = false;
|
|
1041
|
-
// return this;
|
|
1042
|
-
// },
|
|
1043
|
-
|
|
1044
|
-
// adjust center for view to get inside bounds
|
|
1045
|
-
// _limitCenter(center, zoom, bounds) {
|
|
1046
|
-
//
|
|
1047
|
-
// if (!bounds) { return center; }
|
|
1048
|
-
//
|
|
1049
|
-
// const centerPoint = this.project(center, zoom),
|
|
1050
|
-
// viewHalf = this.getSize().divideBy(2),
|
|
1051
|
-
// viewBounds = new Bounds(centerPoint.subtract(viewHalf), centerPoint.add(viewHalf)),
|
|
1052
|
-
// offset = this._getBoundsOffset(viewBounds, bounds, zoom);
|
|
1053
|
-
//
|
|
1054
|
-
// // If offset is less than a pixel, ignore.
|
|
1055
|
-
// // This prevents unstable projections from getting into
|
|
1056
|
-
// // an infinite loop of tiny offsets.
|
|
1057
|
-
// if (Math.abs(offset.x) <= 1 && Math.abs(offset.y) <= 1) {
|
|
1058
|
-
// return center;
|
|
1059
|
-
// }
|
|
1060
|
-
//
|
|
1061
|
-
// return this.unproject(centerPoint.add(offset), zoom);
|
|
1062
|
-
// },
|
|
1063
|
-
|
|
1064
|
-
// @method flyToBounds(bounds: LatLngBounds, options?: fitBounds options): this
|
|
1065
|
-
// Sets the view of the map with a smooth animation like [`flyTo`](#map-flyto),
|
|
1066
|
-
// but takes a bounds parameter like [`fitBounds`](#map-fitbounds).
|
|
1067
|
-
// flyToBounds(bounds, options) {
|
|
1068
|
-
// const target = this._getBoundsCenterZoom(bounds, options);
|
|
1069
|
-
// return this.flyTo(target.center, target.zoom, options);
|
|
1070
|
-
// },
|
|
1071
|
-
|
|
1072
|
-
// _getBoundsCenterZoom(bounds, options) {
|
|
1073
|
-
//
|
|
1074
|
-
// options = options || {};
|
|
1075
|
-
// bounds = bounds.getBounds ? bounds.getBounds() : toLatLngBounds(bounds);
|
|
1076
|
-
//
|
|
1077
|
-
// const paddingTL = L.point(options.paddingTopLeft || options.padding || [0, 0]),
|
|
1078
|
-
// paddingBR = L.point(options.paddingBottomRight || options.padding || [0, 0]);
|
|
1079
|
-
//
|
|
1080
|
-
// let zoom = this.getBoundsZoom(bounds, false, paddingTL.add(paddingBR));
|
|
1081
|
-
//
|
|
1082
|
-
// zoom = (typeof options.maxZoom === 'number') ? Math.min(options.maxZoom, zoom) : zoom;
|
|
1083
|
-
//
|
|
1084
|
-
// if (zoom === Infinity) {
|
|
1085
|
-
// return { center: bounds.getCenter(), zoom };
|
|
1086
|
-
// }
|
|
1087
|
-
//
|
|
1088
|
-
// return { center, zoom };
|
|
1089
|
-
//
|
|
1090
|
-
// },
|
|
1091
|
-
|
|
1092
|
-
/**
|
|
1093
|
-
* Returns the maximum zoom level on which the given bounds fit to the map
|
|
1094
|
-
* view in its entirety. If `inside` (optional) is set to `true`, the method
|
|
1095
|
-
* instead returns the minimum zoom level on which the map view fits into
|
|
1096
|
-
* the given bounds in its entirety.
|
|
1097
|
-
*
|
|
1098
|
-
* @param {L.LatLngBounds} bounds
|
|
1099
|
-
* @param {Boolean} [inside=false]
|
|
1100
|
-
* @param {L.Point} [padding=[0,0]]
|
|
1101
|
-
*
|
|
1102
|
-
* @returns {Number} zoom level
|
|
1103
|
-
*/
|
|
1104
|
-
getBoundsZoom(bounds, inside, padding) {
|
|
1105
|
-
if (!this._rotate || Math.abs(this._bearing).toFixed(1) < 0.1) {
|
|
1106
|
-
return mapProto.getBoundsZoom.apply(this, arguments);
|
|
1107
|
-
}
|
|
1108
|
-
|
|
1109
|
-
bounds = L.latLngBounds(bounds);
|
|
1110
|
-
padding = L.point(padding || [0, 0]);
|
|
1111
|
-
|
|
1112
|
-
let zoom = this.getZoom() || 0;
|
|
1113
|
-
const min = this.getMinZoom(),
|
|
1114
|
-
max = this.getMaxZoom(),
|
|
1115
|
-
/** @TODO use mapProto.getBoundsZoom */
|
|
1116
|
-
// nw = bounds.getNorthWest(),
|
|
1117
|
-
// se = bounds.getSouthEast(),
|
|
1118
|
-
// size = this.getSize().subtract(padding),
|
|
1119
|
-
// boundsSize = L.bounds(this.project(se, zoom), this.project(nw, zoom)).getSize(),
|
|
1120
|
-
size = this.getSize().subtract(padding),
|
|
1121
|
-
boundsSize = this.mapBoundsToContainerBounds(bounds).getSize(),
|
|
1122
|
-
snap = this.options.zoomSnap,
|
|
1123
|
-
scalex = size.x / boundsSize.x,
|
|
1124
|
-
scaley = size.y / boundsSize.y,
|
|
1125
|
-
scale = inside ? Math.max(scalex, scaley) : Math.min(scalex, scaley);
|
|
1126
|
-
|
|
1127
|
-
zoom = this.getScaleZoom(scale, zoom);
|
|
1128
|
-
|
|
1129
|
-
if (snap) {
|
|
1130
|
-
zoom = Math.round(zoom / (snap / 100)) * (snap / 100); // don't jump if within 1% of a snap level
|
|
1131
|
-
zoom = inside ? Math.ceil(zoom / snap) * snap : Math.floor(zoom / snap) * snap;
|
|
1132
|
-
}
|
|
1133
|
-
|
|
1134
|
-
return Math.max(min, Math.min(max, zoom));
|
|
1135
|
-
},
|
|
1136
|
-
|
|
1137
|
-
/**
|
|
1138
|
-
* Layer point of the current center
|
|
1139
|
-
*
|
|
1140
|
-
* @returns {L.Point} layer center
|
|
1141
|
-
*/
|
|
1142
|
-
// _getCenterLayerPoint: function () {
|
|
1143
|
-
// return this.containerPointToLayerPoint(this.getSize()._divideBy(2));
|
|
1144
|
-
// },
|
|
1145
|
-
|
|
1146
|
-
/**
|
|
1147
|
-
* Offset of the specified place to the current center in pixels
|
|
1148
|
-
*
|
|
1149
|
-
* @param {L.LatLng} latlng map coordinates
|
|
1150
|
-
*/
|
|
1151
|
-
_getCenterOffset: function(latlng) {
|
|
1152
|
-
var centerOffset = mapProto._getCenterOffset.apply(this, arguments);
|
|
1153
|
-
if (this._rotate) {
|
|
1154
|
-
centerOffset = centerOffset.rotate(this._bearing);
|
|
1155
|
-
}
|
|
1156
|
-
return centerOffset;
|
|
1157
|
-
},
|
|
1158
|
-
|
|
1159
|
-
/**
|
|
1160
|
-
* @since leaflet-rotate (v0.1)
|
|
1161
|
-
*/
|
|
1162
|
-
_getRotatePanePos: function() {
|
|
1163
|
-
return this._rotatePanePos || new L.Point(0, 0);
|
|
1164
|
-
// return L.DomUtil.getPosition(this._rotatePane) || new L.Point(0, 0);
|
|
1165
|
-
},
|
|
1166
|
-
|
|
1167
|
-
// _latLngToNewLayerPoint(latlng, zoom, center) {
|
|
1168
|
-
// const topLeft = this._getNewPixelOrigin(center, zoom);
|
|
1169
|
-
// return this.project(latlng, zoom)._subtract(topLeft);
|
|
1170
|
-
//},
|
|
1171
|
-
|
|
1172
|
-
_getNewPixelOrigin: function(center, zoom) {
|
|
1173
|
-
if (!this._rotate) {
|
|
1174
|
-
return mapProto._getNewPixelOrigin.apply(this, arguments);
|
|
1175
|
-
}
|
|
1176
|
-
var viewHalf = this.getSize()._divideBy(2);
|
|
1177
|
-
return this.project(center, zoom)
|
|
1178
|
-
.rotate(this._bearing)
|
|
1179
|
-
._subtract(viewHalf)
|
|
1180
|
-
._add(this._getMapPanePos())
|
|
1181
|
-
._add(this._getRotatePanePos())
|
|
1182
|
-
.rotate(-this._bearing)
|
|
1183
|
-
._round();
|
|
1184
|
-
},
|
|
1185
|
-
|
|
1186
|
-
/**
|
|
1187
|
-
* @since leaflet-rotate (v0.2)
|
|
1188
|
-
*
|
|
1189
|
-
* @see src\layer\tile\GridLayer::_getTiledPixelBounds()
|
|
1190
|
-
*/
|
|
1191
|
-
_getNewPixelBounds: function(center, zoom) {
|
|
1192
|
-
center = center || this.getCenter();
|
|
1193
|
-
zoom = zoom || this.getZoom();
|
|
1194
|
-
if (!this._rotate && mapProto._getNewPixelBounds) {
|
|
1195
|
-
return mapProto._getNewPixelBounds.apply(this, arguments);
|
|
1196
|
-
}
|
|
1197
|
-
var mapZoom = this._animatingZoom ? Math.max(this._animateToZoom, this.getZoom()) : this.getZoom(),
|
|
1198
|
-
scale = this.getZoomScale(mapZoom, zoom),
|
|
1199
|
-
pixelCenter = this.project(center, zoom).floor(),
|
|
1200
|
-
size = this.getSize(),
|
|
1201
|
-
halfSize = new L.Bounds([
|
|
1202
|
-
this.containerPointToLayerPoint([0, 0]).floor(),
|
|
1203
|
-
this.containerPointToLayerPoint([size.x, 0]).floor(),
|
|
1204
|
-
this.containerPointToLayerPoint([0, size.y]).floor(),
|
|
1205
|
-
this.containerPointToLayerPoint([size.x, size.y]).floor()
|
|
1206
|
-
]).getSize().divideBy(scale * 2);
|
|
1207
|
-
|
|
1208
|
-
return new L.Bounds(pixelCenter.subtract(halfSize), pixelCenter.add(halfSize));
|
|
1209
|
-
},
|
|
1210
|
-
|
|
1211
|
-
/**
|
|
1212
|
-
* @since leaflet-rotate (v0.2)
|
|
1213
|
-
*
|
|
1214
|
-
* @return {L.Point} map pivot point (center)
|
|
1215
|
-
*/
|
|
1216
|
-
_getPixelCenter: function() {
|
|
1217
|
-
if (!this._rotate && mapProto._getPixelCenter) {
|
|
1218
|
-
return mapProto._getPixelCenter.apply(this, arguments);
|
|
1219
|
-
}
|
|
1220
|
-
return this.getSize()._divideBy(2)._subtract(this._getMapPanePos());
|
|
1221
|
-
},
|
|
1222
|
-
|
|
1223
|
-
/**
|
|
1224
|
-
* @since leaflet-rotate (v0.2)
|
|
1225
|
-
*
|
|
1226
|
-
* @see src\layer\vector\Renderer::_update()
|
|
1227
|
-
*/
|
|
1228
|
-
_getPaddedPixelBounds: function(padding) {
|
|
1229
|
-
if (!this._rotate && mapProto._getPaddedPixelBounds) {
|
|
1230
|
-
return mapProto._getPaddedPixelBounds.apply(this, arguments);
|
|
1231
|
-
}
|
|
1232
|
-
var p = padding,
|
|
1233
|
-
size = this.getSize(),
|
|
1234
|
-
padMin = size.multiplyBy(-p),
|
|
1235
|
-
padMax = size.multiplyBy(1 + p);
|
|
1236
|
-
//min = this.containerPointToLayerPoint(size.multiplyBy(-p)).round();
|
|
1237
|
-
|
|
1238
|
-
return new L.Bounds([
|
|
1239
|
-
this.containerPointToLayerPoint([padMin.x, padMin.y]).floor(),
|
|
1240
|
-
this.containerPointToLayerPoint([padMin.x, padMax.y]).floor(),
|
|
1241
|
-
this.containerPointToLayerPoint([padMax.x, padMin.y]).floor(),
|
|
1242
|
-
this.containerPointToLayerPoint([padMax.x, padMax.y]).floor()
|
|
1243
|
-
]);
|
|
1244
|
-
},
|
|
1245
|
-
|
|
1246
|
-
_handleGeolocationResponse: function(pos) {
|
|
1247
|
-
if (!this._container._leaflet_id) { return; }
|
|
1248
|
-
|
|
1249
|
-
var lat = pos.coords.latitude,
|
|
1250
|
-
lng = pos.coords.longitude,
|
|
1251
|
-
/** @TODO use mapProto._handleGeolocationResponse */
|
|
1252
|
-
hdg = pos.coords.heading,
|
|
1253
|
-
latlng = new L.LatLng(lat, lng),
|
|
1254
|
-
bounds = latlng.toBounds(pos.coords.accuracy),
|
|
1255
|
-
options = this._locateOptions;
|
|
1256
|
-
|
|
1257
|
-
if (options.setView) {
|
|
1258
|
-
var zoom = this.getBoundsZoom(bounds);
|
|
1259
|
-
this.setView(latlng, options.maxZoom ? Math.min(zoom, options.maxZoom) : zoom);
|
|
1260
|
-
}
|
|
1261
|
-
|
|
1262
|
-
var data = {
|
|
1263
|
-
latlng: latlng,
|
|
1264
|
-
bounds: bounds,
|
|
1265
|
-
timestamp: pos.timestamp,
|
|
1266
|
-
/** @TODO use mapProto._handleGeolocationResponse */
|
|
1267
|
-
heading: hdg
|
|
1268
|
-
};
|
|
1269
|
-
|
|
1270
|
-
for (var i in pos.coords) {
|
|
1271
|
-
if (typeof pos.coords[i] === 'number') {
|
|
1272
|
-
data[i] = pos.coords[i];
|
|
1273
|
-
}
|
|
1274
|
-
}
|
|
1275
|
-
|
|
1276
|
-
// @event locationfound: LocationEvent
|
|
1277
|
-
// Fired when geolocation (using the [`locate`](#map-locate) method)
|
|
1278
|
-
// went successfully.
|
|
1279
|
-
this.fire('locationfound', data);
|
|
1280
|
-
},
|
|
1281
|
-
|
|
1282
|
-
/**
|
|
1283
|
-
* @see https://github.com/ronikar/Leaflet/blob/5c480ef959b947c3beed7065425a5a36c486262b/src/geo/LatLngBounds.js#L253-L264
|
|
1284
|
-
*
|
|
1285
|
-
* @param {L.Bounds} points
|
|
1286
|
-
* @returns {L.Bounds}
|
|
1287
|
-
*/
|
|
1288
|
-
// toCircumscribedBounds(points) {
|
|
1289
|
-
// var minX = points.reduce(function (pv, v) { return Math.min(pv, v.x); }, points[0].x),
|
|
1290
|
-
// maxX = points.reduce(function (pv, v) { return Math.max(pv, v.x); }, points[0].x),
|
|
1291
|
-
// minY = points.reduce(function (pv, v) { return Math.min(pv, v.y); }, points[0].y),
|
|
1292
|
-
// maxY = points.reduce(function (pv, v) { return Math.max(pv, v.y); }, points[0].y);
|
|
1293
|
-
//
|
|
1294
|
-
// return L.bounds(L.point(minX, minY), L.point(maxX, maxY));
|
|
1295
|
-
// },
|
|
1296
|
-
|
|
1297
|
-
});
|
|
1298
|
-
|
|
458
|
+
_updateTransform(center, zoom) {
|
|
459
|
+
if (L.version.startsWith("2.")) {
|
|
460
|
+
if (this._map._rotate) {
|
|
461
|
+
const scale2 = this._map.getZoomScale(zoom, this._zoom), offset2 = this._topLeftPoint.multiplyBy(scale2).subtract(this._map._getNewPixelOrigin(center, zoom));
|
|
462
|
+
L.DomUtil.setTransform(this._container, offset2, scale2);
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
return rendererBase._updateTransform.apply(this, arguments);
|
|
466
|
+
}
|
|
467
|
+
if (!this._map._rotate) {
|
|
468
|
+
return rendererProto._updateTransform.apply(this, arguments);
|
|
469
|
+
}
|
|
470
|
+
if (zoom === this._zoom) {
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
const scale = this._map.getZoomScale(zoom, this._zoom), offset = this._map._latLngToNewLayerPoint(this._topLeft, zoom, center);
|
|
474
|
+
L.DomUtil.setTransform(this._container, offset, scale);
|
|
475
|
+
},
|
|
476
|
+
_onMoveEnd(ev) {
|
|
477
|
+
if (!L.version.startsWith("2.") || !this._map._rotate) {
|
|
478
|
+
return rendererBase._onMoveEnd.apply(this, arguments);
|
|
479
|
+
}
|
|
480
|
+
this._bounds = this._map._getPaddedPixelBounds(this.options.padding);
|
|
481
|
+
this._topLeft = this._map.layerPointToLatLng(this._bounds.min);
|
|
482
|
+
this._center = this._map.getCenter();
|
|
483
|
+
this._zoom = this._map.getZoom();
|
|
484
|
+
this._topLeftPoint = this._map._getNewPixelOrigin(this._center, this._zoom).add(this._bounds.min);
|
|
485
|
+
this._updateTransform(this._center, this._zoom);
|
|
486
|
+
this._resizeContainer();
|
|
487
|
+
this._onSettled(ev);
|
|
488
|
+
},
|
|
489
|
+
_resizeContainer() {
|
|
490
|
+
if (!L.version.startsWith("2.") || !this._map._rotate || !this._bounds) {
|
|
491
|
+
return rendererBase._resizeContainer.apply(this, arguments);
|
|
492
|
+
}
|
|
493
|
+
const size = this._bounds.getSize();
|
|
494
|
+
this._container.style.width = size.x + "px";
|
|
495
|
+
this._container.style.height = size.y + "px";
|
|
496
|
+
return size;
|
|
497
|
+
},
|
|
498
|
+
// getEvents() {
|
|
499
|
+
// const events = {
|
|
500
|
+
// viewreset: this._reset,
|
|
501
|
+
// zoom: this._onZoom,
|
|
502
|
+
// moveend: this._update,
|
|
503
|
+
// zoomend: this._onZoomEnd
|
|
504
|
+
// };
|
|
505
|
+
// if (this._zoomAnimated) {
|
|
506
|
+
// events.zoomanim = this._onAnimZoom;
|
|
507
|
+
// }
|
|
508
|
+
// return events;
|
|
509
|
+
// },
|
|
510
|
+
// _onAnimZoom(ev) {
|
|
511
|
+
// this._updateTransform(ev.center, ev.zoom);
|
|
512
|
+
// },
|
|
513
|
+
// _onZoom() {
|
|
514
|
+
// this._updateTransform(this._map.getCenter(), this._map.getZoom());
|
|
515
|
+
// },
|
|
516
|
+
// _onZoomEnd() {
|
|
517
|
+
// for (const id in this._layers) {
|
|
518
|
+
// this._layers[id]._project();
|
|
519
|
+
// }
|
|
520
|
+
// },
|
|
521
|
+
// _reset() {
|
|
522
|
+
// this._update();
|
|
523
|
+
// this._updateTransform(this._center, this._zoom);
|
|
524
|
+
// for (const id in this._layers) {
|
|
525
|
+
// this._layers[id]._reset();
|
|
526
|
+
// }
|
|
527
|
+
// },
|
|
528
|
+
// _updatePaths() {
|
|
529
|
+
// for (const id in this._layers) {
|
|
530
|
+
// this._layers[id]._update();
|
|
531
|
+
// }
|
|
532
|
+
// },
|
|
533
|
+
_update() {
|
|
534
|
+
if (!this._map._rotate) {
|
|
535
|
+
return rendererProto._update.apply(this, arguments);
|
|
536
|
+
}
|
|
537
|
+
this._bounds = this._map._getPaddedPixelBounds(this.options.padding);
|
|
538
|
+
this._topLeft = this._map.layerPointToLatLng(this._bounds.min);
|
|
539
|
+
this._center = this._map.getCenter();
|
|
540
|
+
this._zoom = this._map.getZoom();
|
|
541
|
+
}
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
// src/map/Map.js
|
|
545
|
+
var mapProto = Object.defineProperties({}, Object.getOwnPropertyDescriptors(L.Map.prototype));
|
|
546
|
+
L.Map.mergeOptions({ rotate: false, bearing: 0 });
|
|
547
|
+
L.Map.include({
|
|
548
|
+
_animateZoomNoDelay(center, zoom) {
|
|
549
|
+
if (!this._mapPane) {
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
552
|
+
this._animatingZoom = true;
|
|
553
|
+
this._animateToCenter = center;
|
|
554
|
+
this._animateToZoom = zoom;
|
|
555
|
+
this._move(center, zoom, void 0, true);
|
|
556
|
+
this._onZoomTransitionEnd();
|
|
557
|
+
},
|
|
1299
558
|
/**
|
|
1300
|
-
*
|
|
559
|
+
* @param {(HTMLElement|String)} id html selector
|
|
560
|
+
* @param {Object} [options={}] leaflet map options
|
|
561
|
+
*/
|
|
562
|
+
initialize(id, options) {
|
|
563
|
+
if (options.rotate) {
|
|
564
|
+
this._rotate = true;
|
|
565
|
+
this._bearing = 0;
|
|
566
|
+
}
|
|
567
|
+
mapProto.initialize.apply(this, arguments);
|
|
568
|
+
if (this.options.rotate) {
|
|
569
|
+
this.setBearing(this.options.bearing);
|
|
570
|
+
}
|
|
571
|
+
},
|
|
572
|
+
/**
|
|
573
|
+
* Given a pixel coordinate relative to the map container,
|
|
574
|
+
* returns the corresponding pixel coordinate relative to
|
|
575
|
+
* the [origin pixel](#map-getpixelorigin).
|
|
1301
576
|
*
|
|
1302
|
-
* @
|
|
577
|
+
* @param {L.Point} point pixel screen coordinates
|
|
578
|
+
* @returns {L.Point} transformed pixel point
|
|
1303
579
|
*/
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
if ('ondeviceorientationabsolute' in window) {
|
|
1311
|
-
this.__deviceOrientationEvent = 'deviceorientationabsolute';
|
|
1312
|
-
} else if('ondeviceorientation' in window) {
|
|
1313
|
-
this.__deviceOrientationEvent = 'deviceorientation';
|
|
1314
|
-
}
|
|
1315
|
-
this._throttled = L.Util.throttle(this._onDeviceOrientation, 100, this);
|
|
1316
|
-
},
|
|
1317
|
-
|
|
1318
|
-
addHooks: function() {
|
|
1319
|
-
if (this._map._rotate && this.__deviceOrientationEvent) {
|
|
1320
|
-
L.DomEvent.on(window, this.__deviceOrientationEvent, this._throttled, this);
|
|
1321
|
-
} else {
|
|
1322
|
-
// L.Map.CompassBearing handler will be automatically
|
|
1323
|
-
// disabled if device orientation is not supported.
|
|
1324
|
-
this.disable();
|
|
1325
|
-
}
|
|
1326
|
-
},
|
|
1327
|
-
|
|
1328
|
-
removeHooks: function() {
|
|
1329
|
-
if (this._map._rotate && this.__deviceOrientationEvent) {
|
|
1330
|
-
L.DomEvent.off(window, this.__deviceOrientationEvent, this._throttled, this);
|
|
1331
|
-
}
|
|
1332
|
-
},
|
|
1333
|
-
|
|
1334
|
-
/**
|
|
1335
|
-
* `DeviceOrientationEvent.absolute` - Indicates whether the device is providing absolute
|
|
1336
|
-
* orientation values (relatives to Magnetic North) or
|
|
1337
|
-
* using some arbitrary frame determined by the device.
|
|
1338
|
-
*
|
|
1339
|
-
* `DeviceOrientationEvent.alpha` - Returns the rotation of the device around the Z axis;
|
|
1340
|
-
* that is, the number of degrees by which the device is
|
|
1341
|
-
* being twisted around the center of the screen.
|
|
1342
|
-
*
|
|
1343
|
-
* `window.orientation` - Returns the screen orientation in degrees (in 90-degree increments)
|
|
1344
|
-
* of the viewport relative to the device's natural orientation.
|
|
1345
|
-
* Its only possible values are -90, 0, 90, and 180. Positive
|
|
1346
|
-
* values are counterclockwise; negative values are clockwise.
|
|
1347
|
-
*
|
|
1348
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/DeviceOrientationEvent/absolute
|
|
1349
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/DeviceOrientationEvent/alpha
|
|
1350
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window/orientation
|
|
1351
|
-
*/
|
|
1352
|
-
_onDeviceOrientation: function(e) {
|
|
1353
|
-
var angle = e.webkitCompassHeading || e.alpha;
|
|
1354
|
-
var deviceOrientation = 0;
|
|
1355
|
-
|
|
1356
|
-
// Safari iOS
|
|
1357
|
-
if (!e.absolute && e.webkitCompassHeading) {
|
|
1358
|
-
angle = 360 - angle;
|
|
1359
|
-
}
|
|
1360
|
-
|
|
1361
|
-
// Older browsers
|
|
1362
|
-
if (!e.absolute && 'undefined' !== typeof window.orientation) {
|
|
1363
|
-
deviceOrientation = window.orientation;
|
|
1364
|
-
}
|
|
1365
|
-
|
|
1366
|
-
this._map.setBearing(angle - deviceOrientation);
|
|
1367
|
-
},
|
|
1368
|
-
|
|
1369
|
-
});
|
|
1370
|
-
|
|
580
|
+
containerPointToLayerPoint(point) {
|
|
581
|
+
if (!this._rotate) {
|
|
582
|
+
return mapProto.containerPointToLayerPoint.apply(this, arguments);
|
|
583
|
+
}
|
|
584
|
+
return toPoint(point).subtract(this._getMapPanePos()).rotateFrom(-this._bearing, this._getRotatePanePos()).subtract(this._getRotatePanePos());
|
|
585
|
+
},
|
|
1371
586
|
/**
|
|
1372
|
-
*
|
|
587
|
+
* Given a pixel coordinate relative to the [origin pixel](#map-getpixelorigin),
|
|
588
|
+
* returns the corresponding pixel coordinate relative to the map container.
|
|
1373
589
|
*
|
|
1374
|
-
* @
|
|
590
|
+
* @param {L.Point} point pixel screen coordinates
|
|
591
|
+
* @returns {L.Point} transformed pixel point
|
|
1375
592
|
*/
|
|
1376
|
-
|
|
1377
|
-
|
|
593
|
+
layerPointToContainerPoint(point) {
|
|
594
|
+
if (!this._rotate) {
|
|
595
|
+
return mapProto.layerPointToContainerPoint.apply(this, arguments);
|
|
596
|
+
}
|
|
597
|
+
return toPoint(point).add(this._getRotatePanePos()).rotateFrom(this._bearing, this._getRotatePanePos()).add(this._getMapPanePos());
|
|
598
|
+
},
|
|
1378
599
|
/**
|
|
1379
|
-
*
|
|
600
|
+
* Converts a coordinate from the rotated pane reference system
|
|
601
|
+
* to the reference system of the not rotated map pane.
|
|
1380
602
|
*
|
|
1381
|
-
*
|
|
603
|
+
* (rotatePane) --> (mapPane)
|
|
604
|
+
* (rotatePane) --> (norotatePane)
|
|
605
|
+
*
|
|
606
|
+
* @param {L.Point} point pixel screen coordinates
|
|
607
|
+
* @returns {L.Point}
|
|
608
|
+
*
|
|
609
|
+
* @since leaflet-rotate (v0.1)
|
|
1382
610
|
*/
|
|
1383
|
-
|
|
611
|
+
rotatedPointToMapPanePoint(point) {
|
|
612
|
+
return toPoint(point).rotate(this._bearing)._add(this._getRotatePanePos());
|
|
613
|
+
},
|
|
1384
614
|
/**
|
|
1385
|
-
*
|
|
1386
|
-
*
|
|
615
|
+
* Converts a coordinate from the not rotated map pane reference system
|
|
616
|
+
* to the reference system of the rotated pane.
|
|
617
|
+
*
|
|
618
|
+
* (mapPane) --> (rotatePane)
|
|
619
|
+
* (norotatePane) --> (rotatePane)
|
|
620
|
+
*
|
|
621
|
+
* @param {L.Point} point pixel screen coordinates
|
|
622
|
+
*
|
|
623
|
+
* @since leaflet-rotate (v0.1)
|
|
1387
624
|
*/
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
*
|
|
1399
|
-
* @see https://developer.mozilla.org/docs/Web/API/MutationObserver
|
|
1400
|
-
*/
|
|
1401
|
-
trackContainerMutation: false
|
|
1402
|
-
|
|
1403
|
-
});
|
|
1404
|
-
|
|
1405
|
-
L.Map.ContainerMutation = L.Handler.extend({
|
|
1406
|
-
|
|
1407
|
-
addHooks: function() {
|
|
1408
|
-
// if (!L.Browser.mutation) { return; }
|
|
1409
|
-
if (!this._observer) {
|
|
1410
|
-
this._observer = new MutationObserver(L.Util.bind(this._map.invalidateSize, this._map));
|
|
1411
|
-
}
|
|
1412
|
-
this._observer.observe(this._map.getContainer(), {
|
|
1413
|
-
childList: false,
|
|
1414
|
-
attributes: true,
|
|
1415
|
-
characterData: false,
|
|
1416
|
-
subtree: false,
|
|
1417
|
-
attributeFilter: ['style']
|
|
1418
|
-
});
|
|
1419
|
-
},
|
|
1420
|
-
|
|
1421
|
-
removeHooks: function() {
|
|
1422
|
-
// if (!L.Browser.mutation) { return; }
|
|
1423
|
-
this._observer.disconnect();
|
|
1424
|
-
},
|
|
1425
|
-
|
|
1426
|
-
});
|
|
1427
|
-
|
|
625
|
+
mapPanePointToRotatedPoint(point) {
|
|
626
|
+
return toPoint(point)._subtract(this._getRotatePanePos()).rotate(-this._bearing);
|
|
627
|
+
},
|
|
628
|
+
// latLngToLayerPoint(latlng) {
|
|
629
|
+
// const projectedPoint = this.project(L.latLng(latlng))._round();
|
|
630
|
+
// return projectedPoint._subtract(this.getPixelOrigin());
|
|
631
|
+
// },
|
|
632
|
+
// latLngToContainerPoint(latlng) {
|
|
633
|
+
// return this.layerPointToContainerPoint(this.latLngToLayerPoint(toLatLng(latlng)));
|
|
634
|
+
// },
|
|
1428
635
|
/**
|
|
1429
|
-
*
|
|
636
|
+
* Given latlng bounds, returns the bounds in projected pixel
|
|
637
|
+
* relative to the map container.
|
|
638
|
+
*
|
|
639
|
+
* @see https://github.com/ronikar/Leaflet/blob/5c480ef959b947c3beed7065425a5a36c486262b/src/map/Map.js#L1114-L1135
|
|
1430
640
|
*
|
|
1431
|
-
* @
|
|
641
|
+
* @param {L.LatLngBounds} bounds
|
|
642
|
+
* @returns {L.Bounds}
|
|
643
|
+
*
|
|
644
|
+
* @since leaflet-rotate (v0.2)
|
|
1432
645
|
*/
|
|
1433
|
-
|
|
1434
|
-
|
|
646
|
+
mapBoundsToContainerBounds(bounds) {
|
|
647
|
+
if (!this._rotate && mapProto.mapBoundsToContainerBounds) {
|
|
648
|
+
return mapProto.mapBoundsToContainerBounds.apply(this, arguments);
|
|
649
|
+
}
|
|
650
|
+
const origin = this.getPixelOrigin();
|
|
651
|
+
const nw = this.layerPointToContainerPoint(this.project(bounds.getNorthWest())._subtract(origin)), ne = this.layerPointToContainerPoint(this.project(bounds.getNorthEast())._subtract(origin)), sw = this.layerPointToContainerPoint(this.project(bounds.getSouthWest())._subtract(origin)), se = this.layerPointToContainerPoint(this.project(bounds.getSouthEast())._subtract(origin));
|
|
652
|
+
return new L.Bounds([
|
|
653
|
+
new L.Point(Math.min(nw.x, ne.x, se.x, sw.x), Math.min(nw.y, ne.y, se.y, sw.y)),
|
|
654
|
+
// [ minX, minY ]
|
|
655
|
+
new L.Point(Math.max(nw.x, ne.x, se.x, sw.x), Math.max(nw.y, ne.y, se.y, sw.y))
|
|
656
|
+
// [ maxX, maxY ]
|
|
657
|
+
]);
|
|
658
|
+
},
|
|
1435
659
|
/**
|
|
1436
|
-
*
|
|
660
|
+
* Returns geographical bounds visible in the current map view
|
|
661
|
+
*
|
|
662
|
+
* @TODO find out if map bounds calculated by `L.Map::getBounds()`
|
|
663
|
+
* function should match the `rotatePane` or `norotatePane` bounds
|
|
1437
664
|
*
|
|
1438
|
-
* @see https://github.com/fnicollet/Leaflet/
|
|
1439
|
-
* @see https://github.com/Leaflet/Leaflet/blob/v1.9.3/src/map/handler/Map.TouchZoom.js
|
|
665
|
+
* @see https://github.com/fnicollet/Leaflet/issues/7
|
|
1440
666
|
*
|
|
1441
|
-
* @
|
|
667
|
+
* @returns {L.LatLngBounds}
|
|
1442
668
|
*/
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
initialize: function(map) {
|
|
1460
|
-
this._map = map;
|
|
1461
|
-
this.rotate = !!this._map.options.touchRotate;
|
|
1462
|
-
this.zoom = !!this._map.options.touchZoom;
|
|
1463
|
-
},
|
|
1464
|
-
|
|
1465
|
-
addHooks: function() {
|
|
1466
|
-
L.DomEvent.on(this._map._container, 'touchstart', this._onTouchStart, this);
|
|
1467
|
-
},
|
|
1468
|
-
|
|
1469
|
-
removeHooks: function() {
|
|
1470
|
-
L.DomEvent.off(this._map._container, 'touchstart', this._onTouchStart, this);
|
|
1471
|
-
},
|
|
1472
|
-
|
|
1473
|
-
_onTouchStart: function(e) {
|
|
1474
|
-
var map = this._map;
|
|
1475
|
-
|
|
1476
|
-
if (!e.touches || e.touches.length !== 2 || map._animatingZoom || this._zooming || this._rotating) { return; }
|
|
1477
|
-
|
|
1478
|
-
var p1 = map.mouseEventToContainerPoint(e.touches[0]),
|
|
1479
|
-
p2 = map.mouseEventToContainerPoint(e.touches[1]),
|
|
1480
|
-
vector = p1.subtract(p2);
|
|
1481
|
-
|
|
1482
|
-
this._centerPoint = map.getSize()._divideBy(2);
|
|
1483
|
-
this._startLatLng = map.containerPointToLatLng(this._centerPoint);
|
|
1484
|
-
|
|
1485
|
-
if (this.zoom) {
|
|
1486
|
-
if (map.options.touchZoom !== 'center') {
|
|
1487
|
-
this._pinchStartLatLng = map.containerPointToLatLng(p1.add(p2)._divideBy(2));
|
|
1488
|
-
}
|
|
1489
|
-
this._startDist = p1.distanceTo(p2);
|
|
1490
|
-
this._startZoom = map.getZoom();
|
|
1491
|
-
this._zooming = true;
|
|
1492
|
-
} else {
|
|
1493
|
-
this._zooming = false;
|
|
1494
|
-
}
|
|
1495
|
-
|
|
1496
|
-
if (this.rotate) {
|
|
1497
|
-
this._startTheta = Math.atan(vector.x / vector.y);
|
|
1498
|
-
this._startBearing = map.getBearing();
|
|
1499
|
-
if (vector.y < 0) { this._startBearing += 180; }
|
|
1500
|
-
this._rotating = true;
|
|
1501
|
-
} else {
|
|
1502
|
-
this._rotating = false;
|
|
1503
|
-
}
|
|
1504
|
-
|
|
1505
|
-
this._moved = false;
|
|
1506
|
-
|
|
1507
|
-
map._stop();
|
|
1508
|
-
|
|
1509
|
-
L.DomEvent
|
|
1510
|
-
.on(document, 'touchmove', this._onTouchMove, this)
|
|
1511
|
-
.on(document, 'touchend touchcancel', this._onTouchEnd, this);
|
|
1512
|
-
|
|
1513
|
-
L.DomEvent.preventDefault(e);
|
|
1514
|
-
},
|
|
1515
|
-
|
|
1516
|
-
_onTouchMove: function(e) {
|
|
1517
|
-
if (!e.touches || e.touches.length !== 2 || !(this._zooming || this._rotating)) { return; }
|
|
1518
|
-
|
|
1519
|
-
var map = this._map,
|
|
1520
|
-
p1 = map.mouseEventToContainerPoint(e.touches[0]),
|
|
1521
|
-
p2 = map.mouseEventToContainerPoint(e.touches[1]),
|
|
1522
|
-
vector = p1.subtract(p2),
|
|
1523
|
-
scale = p1.distanceTo(p2) / this._startDist,
|
|
1524
|
-
delta;
|
|
1525
|
-
|
|
1526
|
-
if (this._rotating) {
|
|
1527
|
-
var theta = Math.atan(vector.x / vector.y);
|
|
1528
|
-
var bearingDelta = (theta - this._startTheta) * L.DomUtil.RAD_TO_DEG;
|
|
1529
|
-
if (vector.y < 0) { bearingDelta += 180; }
|
|
1530
|
-
if (bearingDelta) {
|
|
1531
|
-
/**
|
|
1532
|
-
* @TODO the pivot should be the last touch point,
|
|
1533
|
-
* but zoomAnimation manages to overwrite the rotate
|
|
1534
|
-
* pane position. Maybe related to #3529.
|
|
1535
|
-
*
|
|
1536
|
-
* @see https://github.com/Leaflet/Leaflet/pull/3529
|
|
1537
|
-
* @see https://github.com/fnicollet/Leaflet/commit/a77af51a6b10f308d1b9a16552091d1d0aee8834
|
|
1538
|
-
*/
|
|
1539
|
-
map.setBearing(this._startBearing - bearingDelta);
|
|
1540
|
-
}
|
|
1541
|
-
}
|
|
1542
|
-
|
|
1543
|
-
if (this._zooming) {
|
|
1544
|
-
this._zoom = map.getScaleZoom(scale, this._startZoom);
|
|
1545
|
-
|
|
1546
|
-
if (!map.options.bounceAtZoomLimits && (
|
|
1547
|
-
(this._zoom < map.getMinZoom() && scale < 1) ||
|
|
1548
|
-
(this._zoom > map.getMaxZoom() && scale > 1))) {
|
|
1549
|
-
this._zoom = map._limitZoom(this._zoom);
|
|
1550
|
-
}
|
|
1551
|
-
|
|
1552
|
-
if (map.options.touchZoom === 'center') {
|
|
1553
|
-
this._center = this._startLatLng;
|
|
1554
|
-
if (scale === 1) { return; }
|
|
1555
|
-
} else {
|
|
1556
|
-
// Get delta from pinch to center, so centerLatLng is delta applied to initial pinchLatLng
|
|
1557
|
-
delta = p1._add(p2)._divideBy(2)._subtract(this._centerPoint);
|
|
1558
|
-
if (scale === 1 && delta.x === 0 && delta.y === 0) { return; }
|
|
1559
|
-
|
|
1560
|
-
var alpha = -map.getBearing() * L.DomUtil.DEG_TO_RAD;
|
|
1561
|
-
|
|
1562
|
-
this._center = map.unproject(map.project(this._pinchStartLatLng).subtract(delta.rotate(alpha)));
|
|
1563
|
-
}
|
|
1564
|
-
|
|
1565
|
-
}
|
|
1566
|
-
|
|
1567
|
-
if (!this._moved) {
|
|
1568
|
-
map._moveStart(true, false);
|
|
1569
|
-
this._moved = true;
|
|
1570
|
-
}
|
|
1571
|
-
|
|
1572
|
-
L.Util.cancelAnimFrame(this._animRequest);
|
|
1573
|
-
|
|
1574
|
-
var moveFn = map._move.bind(map, this._center, this._zoom, { pinch: true, round: false }, undefined);
|
|
1575
|
-
this._animRequest = L.Util.requestAnimFrame(moveFn, this, true);
|
|
1576
|
-
|
|
1577
|
-
L.DomEvent.preventDefault(e);
|
|
1578
|
-
},
|
|
1579
|
-
|
|
1580
|
-
_onTouchEnd: function() {
|
|
1581
|
-
if (!this._moved || !(this._zooming || this._rotating)) {
|
|
1582
|
-
this._zooming = false;
|
|
1583
|
-
return;
|
|
1584
|
-
}
|
|
1585
|
-
|
|
1586
|
-
this._zooming = false;
|
|
1587
|
-
this._rotating = false;
|
|
1588
|
-
L.Util.cancelAnimFrame(this._animRequest);
|
|
1589
|
-
|
|
1590
|
-
L.DomEvent
|
|
1591
|
-
.off(document, 'touchmove', this._onTouchMove, this)
|
|
1592
|
-
.off(document, 'touchend touchcancel', this._onTouchEnd, this);
|
|
1593
|
-
|
|
1594
|
-
if (this.zoom) {
|
|
1595
|
-
// Pinch updates GridLayers' levels only when zoomSnap is off, so zoomSnap becomes noUpdate.
|
|
1596
|
-
if (this._map.options.zoomAnimation) {
|
|
1597
|
-
this._map._animateZoom(this._center, this._map._limitZoom(this._zoom), true, this._map.options.zoomSnap);
|
|
1598
|
-
} else {
|
|
1599
|
-
this._map._resetView(this._center, this._map._limitZoom(this._zoom));
|
|
1600
|
-
}
|
|
1601
|
-
}
|
|
1602
|
-
},
|
|
1603
|
-
|
|
1604
|
-
});
|
|
1605
|
-
|
|
669
|
+
getBounds() {
|
|
670
|
+
if (!this._rotate) {
|
|
671
|
+
return mapProto.getBounds.apply(this, arguments);
|
|
672
|
+
}
|
|
673
|
+
const size = this.getSize();
|
|
674
|
+
return new L.LatLngBounds([
|
|
675
|
+
this.containerPointToLatLng([0, 0]),
|
|
676
|
+
// topleft
|
|
677
|
+
this.containerPointToLatLng([size.x, 0]),
|
|
678
|
+
// topright
|
|
679
|
+
this.containerPointToLatLng([size.x, size.y]),
|
|
680
|
+
// bottomright
|
|
681
|
+
this.containerPointToLatLng([0, size.y])
|
|
682
|
+
// bottomleft
|
|
683
|
+
]);
|
|
684
|
+
},
|
|
1606
685
|
/**
|
|
1607
|
-
*
|
|
686
|
+
* Returns the bounds of the current map view in projected pixel
|
|
687
|
+
* coordinates (sometimes useful in layer and overlay implementations).
|
|
688
|
+
*
|
|
689
|
+
* @TODO find out if map bounds calculated by `L.Map::getPixelBounds()`
|
|
690
|
+
* function should match the `rotatePane` or `norotatePane` bounds
|
|
691
|
+
*
|
|
692
|
+
* @see https://github.com/fnicollet/Leaflet/issues/7
|
|
1608
693
|
*
|
|
1609
|
-
* @
|
|
694
|
+
* @returns {L.Bounds}
|
|
1610
695
|
*/
|
|
1611
|
-
|
|
1612
|
-
|
|
696
|
+
// getPixelBounds(center, zoom) {
|
|
697
|
+
// // const topLeftPoint = map.containerPointToLayerPoint(this._getTopLeftPoint());
|
|
698
|
+
// const topLeftPoint = this._getTopLeftPoint(center, zoom);
|
|
699
|
+
// return new L.Bounds(topLeftPoint, topLeftPoint.add(this.getSize()));
|
|
700
|
+
// },
|
|
1613
701
|
/**
|
|
1614
|
-
*
|
|
702
|
+
* Change map rotation
|
|
703
|
+
*
|
|
704
|
+
* @param {number} theta map degrees
|
|
705
|
+
* @param {Object} [options] animation options
|
|
706
|
+
* @param {boolean} [options.animate=false]
|
|
707
|
+
* @param {number} [options.duration=0.25] animation duration in seconds
|
|
708
|
+
* @param {number} [options.easeLinearity=0.5]
|
|
1615
709
|
*
|
|
1616
|
-
* @
|
|
710
|
+
* @since leaflet-rotate (v0.1)
|
|
1617
711
|
*/
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
712
|
+
setBearing(theta, options) {
|
|
713
|
+
if (!this._rotate) {
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
716
|
+
if (options && options.animate) {
|
|
717
|
+
this._bearingAnimationId = (this._bearingAnimationId || 0) + 1;
|
|
718
|
+
const animationId = this._bearingAnimationId;
|
|
719
|
+
if (this._bearingAnimationFrame) {
|
|
720
|
+
cancelAnimationFrame(this._bearingAnimationFrame);
|
|
721
|
+
}
|
|
722
|
+
const startBearing = this.getBearing(), endBearing = L.Util.wrapNum(theta, [0, 360]), delta = (endBearing - startBearing + 540) % 360 - 180, duration = Math.max(0, options.duration == null ? 0.25 : options.duration) * 1e3, easeLinearity = Math.max(options.easeLinearity || 0.5, 0.2), startTime = performance.now();
|
|
723
|
+
const animate = function() {
|
|
724
|
+
if (!this._mapPane) {
|
|
725
|
+
delete this._bearingAnimationFrame;
|
|
726
|
+
return;
|
|
727
|
+
}
|
|
728
|
+
const progress = duration ? Math.min((performance.now() - startTime) / duration, 1) : 1, eased = 1 - Math.pow(1 - progress, 1 / easeLinearity);
|
|
729
|
+
this._setBearing(progress === 1 ? endBearing : startBearing + delta * eased);
|
|
730
|
+
if (this._bearingAnimationId !== animationId) {
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
if (progress < 1) {
|
|
734
|
+
this._bearingAnimationFrame = requestAnimationFrame(animate.bind(this));
|
|
735
|
+
} else {
|
|
736
|
+
delete this._bearingAnimationFrame;
|
|
737
|
+
}
|
|
738
|
+
};
|
|
739
|
+
this._bearingAnimationFrame = requestAnimationFrame(animate.bind(this));
|
|
740
|
+
return;
|
|
741
|
+
}
|
|
742
|
+
this._bearingAnimationId = (this._bearingAnimationId || 0) + 1;
|
|
743
|
+
if (this._bearingAnimationFrame) {
|
|
744
|
+
cancelAnimationFrame(this._bearingAnimationFrame);
|
|
745
|
+
delete this._bearingAnimationFrame;
|
|
746
|
+
}
|
|
747
|
+
this._setBearing(theta);
|
|
748
|
+
},
|
|
749
|
+
_setBearing(theta) {
|
|
750
|
+
const bearing = L.Util.wrapNum(theta, [0, 360]) * (Math.PI / 180), center = this._getPixelCenter(), oldPos = this._getRotatePanePos().rotateFrom(-this._bearing, center), newPos = oldPos.rotateFrom(bearing, center);
|
|
751
|
+
L.DomUtil.setPosition(this._rotatePane, oldPos, bearing, center);
|
|
752
|
+
this._pivot = center;
|
|
753
|
+
this._bearing = bearing;
|
|
754
|
+
this._rotatePanePos = newPos;
|
|
755
|
+
this.fire("rotate");
|
|
756
|
+
},
|
|
1643
757
|
/**
|
|
1644
|
-
*
|
|
758
|
+
* Get current map rotation
|
|
759
|
+
*
|
|
760
|
+
* @returns {number} theta map degrees
|
|
1645
761
|
*
|
|
1646
|
-
* @
|
|
762
|
+
* @since leaflet-rotate (v0.1)
|
|
1647
763
|
*/
|
|
1648
|
-
|
|
1649
|
-
|
|
764
|
+
getBearing() {
|
|
765
|
+
return this._bearing * (180 / Math.PI);
|
|
766
|
+
},
|
|
1650
767
|
/**
|
|
1651
|
-
*
|
|
768
|
+
* Creates a new [map pane](#map-pane) with the given name if it doesn't
|
|
769
|
+
* exist already, then returns it. The pane is created as a child of
|
|
770
|
+
* `container`, or as a child of the main map pane if not set.
|
|
1652
771
|
*
|
|
1653
|
-
* @
|
|
772
|
+
* @param {String} name leaflet pane
|
|
773
|
+
* @param {HTMLElement} [container] parent element
|
|
774
|
+
* @returns {HTMLElement} pane container
|
|
1654
775
|
*/
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
}
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
addHooks: function() {
|
|
1669
|
-
L.DomEvent.on(this._map._container, "wheel", this._handleShiftScroll, this);
|
|
1670
|
-
// this._map.shiftKeyRotate.enable();
|
|
1671
|
-
this._map.shiftKeyRotate.rotate = true;
|
|
1672
|
-
},
|
|
1673
|
-
|
|
1674
|
-
removeHooks: function() {
|
|
1675
|
-
L.DomEvent.off(this._map._container, "wheel", this._handleShiftScroll, this);
|
|
1676
|
-
this._map.shiftKeyRotate.rotate = false;
|
|
1677
|
-
},
|
|
1678
|
-
|
|
1679
|
-
_handleShiftScroll: function(e) {
|
|
1680
|
-
if (e.shiftKey) {
|
|
1681
|
-
e.preventDefault();
|
|
1682
|
-
this._map.scrollWheelZoom.disable();
|
|
1683
|
-
this._map.setBearing((this._map._bearing * L.DomUtil.RAD_TO_DEG) + Math.sign(e.deltaY) * 5);
|
|
1684
|
-
} else {
|
|
1685
|
-
this._map.scrollWheelZoom.enable();
|
|
1686
|
-
}
|
|
1687
|
-
},
|
|
1688
|
-
|
|
1689
|
-
});
|
|
1690
|
-
|
|
776
|
+
// createPane(name, container) {
|
|
777
|
+
// if (!this._rotate || name == 'mapPane') {
|
|
778
|
+
// return mapProto.createPane.apply(this, arguments);
|
|
779
|
+
// }
|
|
780
|
+
// // init "rotatePane"
|
|
781
|
+
// if (!this._rotatePane) {
|
|
782
|
+
// // this._pivot = this.getSize().divideBy(2);
|
|
783
|
+
// this._rotatePane = mapProto.createPane.call(this, 'rotatePane', this._mapPane);
|
|
784
|
+
// L.DomUtil.setPosition(this._rotatePane, new L.Point(0, 0), this._bearing, this._pivot);
|
|
785
|
+
// }
|
|
786
|
+
// return mapProto.createPane.call(this, name, container || this._rotatePane);
|
|
787
|
+
// },
|
|
1691
788
|
/**
|
|
1692
|
-
*
|
|
789
|
+
* Panes are DOM elements used to control the ordering of layers on
|
|
790
|
+
* the map. You can access panes with [`map.getPane`](#map-getpane)
|
|
791
|
+
* or [`map.getPanes`](#map-getpanes) methods. New panes can be created
|
|
792
|
+
* with the [`map.createPane`](#map-createpane) method.
|
|
793
|
+
*
|
|
794
|
+
* Every map has the following default panes that differ only in zIndex:
|
|
1693
795
|
*
|
|
1694
|
-
*
|
|
796
|
+
* - mapPane [HTMLElement = 'auto'] - Pane that contains all other map panes
|
|
797
|
+
* - tilePane [HTMLElement = 2] - Pane for tile layers
|
|
798
|
+
* - overlayPane [HTMLElement = 4] - Pane for overlays like polylines and polygons
|
|
799
|
+
* - shadowPane [HTMLElement = 5] - Pane for overlay shadows (e.g. marker shadows)
|
|
800
|
+
* - markerPane [HTMLElement = 6] - Pane for marker icons
|
|
801
|
+
* - tooltipPane [HTMLElement = 650] - Pane for tooltips.
|
|
802
|
+
* - popupPane [HTMLElement = 700] - Pane for popups.
|
|
1695
803
|
*/
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
804
|
+
_initPanes() {
|
|
805
|
+
const panes = this._panes = {};
|
|
806
|
+
this._paneRenderers = {};
|
|
807
|
+
this._mapPane = this.createPane("mapPane", this._container);
|
|
808
|
+
L.DomUtil.setPosition(this._mapPane, new L.Point(0, 0));
|
|
809
|
+
if (this._rotate) {
|
|
810
|
+
this._rotatePane = this.createPane("rotatePane", this._mapPane);
|
|
811
|
+
this._norotatePane = this.createPane("norotatePane", this._mapPane);
|
|
812
|
+
if (L.version.startsWith("2.")) {
|
|
813
|
+
this._rotatePane.style.transformOrigin = "0 0";
|
|
1703
814
|
}
|
|
1704
|
-
|
|
1705
|
-
|
|
815
|
+
this.createPane("tilePane", this._rotatePane);
|
|
816
|
+
this.createPane("overlayPane", this._rotatePane);
|
|
817
|
+
this.createPane("shadowPane", this._norotatePane);
|
|
818
|
+
this.createPane("markerPane", this._norotatePane);
|
|
819
|
+
this.createPane("tooltipPane", this._norotatePane);
|
|
820
|
+
this.createPane("popupPane", this._norotatePane);
|
|
821
|
+
} else {
|
|
822
|
+
this.createPane("tilePane");
|
|
823
|
+
this.createPane("overlayPane");
|
|
824
|
+
this.createPane("shadowPane");
|
|
825
|
+
this.createPane("markerPane");
|
|
826
|
+
this.createPane("tooltipPane");
|
|
827
|
+
this.createPane("popupPane");
|
|
828
|
+
}
|
|
829
|
+
if (!this.options.markerZoomAnimation) {
|
|
830
|
+
panes.markerPane.classList.add("leaflet-zoom-hide");
|
|
831
|
+
panes.shadowPane.classList.add("leaflet-zoom-hide");
|
|
832
|
+
}
|
|
833
|
+
},
|
|
1706
834
|
/**
|
|
1707
|
-
*
|
|
835
|
+
* Pans the map the minimum amount to make the `latlng` visible. Use
|
|
836
|
+
* padding options to fit the display to more restricted bounds.
|
|
837
|
+
* If `latlng` is already within the (optionally padded) display bounds,
|
|
838
|
+
* the map will not be panned.
|
|
839
|
+
*
|
|
840
|
+
* @see https://github.com/Raruto/leaflet-rotate/issues/18
|
|
1708
841
|
*
|
|
1709
|
-
* @
|
|
842
|
+
* @param {L.LatLng} latlng coordinates
|
|
843
|
+
* @param {Object} [options={}] padding options
|
|
1710
844
|
*
|
|
1711
|
-
* @
|
|
845
|
+
* @returns {L.Map} current map instance
|
|
1712
846
|
*/
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
* Set it to false if you don't want the map to
|
|
1731
|
-
* zoom beyond min/max zoom and then bounce back
|
|
1732
|
-
* when pinch-zooming.
|
|
1733
|
-
*
|
|
1734
|
-
* @type {Boolean}
|
|
1735
|
-
*/
|
|
1736
|
-
bounceAtZoomLimits: false,
|
|
1737
|
-
|
|
1738
|
-
});
|
|
1739
|
-
|
|
1740
|
-
L.Map.TouchZoom = L.Handler.extend({
|
|
1741
|
-
|
|
1742
|
-
addHooks: function() {
|
|
1743
|
-
L.DomUtil.addClass(this._map._container, 'leaflet-touch-zoom');
|
|
1744
|
-
this._map.touchGestures.enable();
|
|
1745
|
-
this._map.touchGestures.zoom = true;
|
|
1746
|
-
},
|
|
1747
|
-
|
|
1748
|
-
removeHooks: function() {
|
|
1749
|
-
L.DomUtil.removeClass(this._map._container, 'leaflet-touch-zoom');
|
|
1750
|
-
this._map.touchGestures.zoom = false;
|
|
1751
|
-
},
|
|
1752
|
-
|
|
1753
|
-
});
|
|
1754
|
-
|
|
847
|
+
panInside(latlng, options) {
|
|
848
|
+
if (!this._rotate || Math.abs(this._bearing).toFixed(1) < 0.1) {
|
|
849
|
+
return mapProto.panInside.apply(this, arguments);
|
|
850
|
+
}
|
|
851
|
+
options = options || {};
|
|
852
|
+
const paddingTL = toPoint(options.paddingTopLeft || options.padding || [0, 0]), paddingBR = toPoint(options.paddingBottomRight || options.padding || [0, 0]), pixelPoint = this.latLngToContainerPoint(latlng), pixelBounds = new L.Bounds([new L.Point(0, 0), this.getSize()]), pixelCenter = pixelBounds.getCenter(), paddedBounds = new L.Bounds([pixelBounds.min.add(paddingTL), pixelBounds.max.subtract(paddingBR)]), paddedSize = paddedBounds.getSize();
|
|
853
|
+
if (!paddedBounds.contains(pixelPoint)) {
|
|
854
|
+
this._enforcingBounds = true;
|
|
855
|
+
const centerOffset = pixelPoint.subtract(paddedBounds.getCenter());
|
|
856
|
+
const offset = paddedBounds.extend(pixelPoint).getSize().subtract(paddedSize);
|
|
857
|
+
pixelCenter.x += centerOffset.x < 0 ? -offset.x : offset.x;
|
|
858
|
+
pixelCenter.y += centerOffset.y < 0 ? -offset.y : offset.y;
|
|
859
|
+
this.panTo(this.containerPointToLatLng(pixelCenter), options);
|
|
860
|
+
this._enforcingBounds = false;
|
|
861
|
+
}
|
|
862
|
+
return this;
|
|
863
|
+
},
|
|
1755
864
|
/**
|
|
1756
|
-
*
|
|
865
|
+
* Pans the map to the closest view that would lie inside the given bounds
|
|
866
|
+
* (if it's not already), controlling the animation using the options specific,
|
|
867
|
+
* if any.
|
|
868
|
+
*
|
|
869
|
+
* @TODO check if map bounds calculated by `L.Map::panInsideBounds()`
|
|
870
|
+
* function should match the `rotatePane` or `norotatePane` bounds
|
|
871
|
+
*
|
|
872
|
+
* @see https://github.com/fnicollet/Leaflet/issues/7
|
|
1757
873
|
*
|
|
1758
|
-
* @
|
|
874
|
+
* @param {L.LatLngBounds} bounds coordinates
|
|
875
|
+
* @param {Object} [options] pan options
|
|
876
|
+
* @returns {L.Map} current map instance
|
|
1759
877
|
*/
|
|
1760
|
-
|
|
1761
|
-
|
|
878
|
+
// panInsideBounds(bounds, options) {
|
|
879
|
+
// this._enforcingBounds = true;
|
|
880
|
+
// const center = this.getCenter(),
|
|
881
|
+
// newCenter = this._limitCenter(center, this._zoom, L.latLngBounds(bounds));
|
|
882
|
+
//
|
|
883
|
+
// if (!center.equals(newCenter)) {
|
|
884
|
+
// this.panTo(newCenter, options);
|
|
885
|
+
// }
|
|
886
|
+
//
|
|
887
|
+
// this._enforcingBounds = false;
|
|
888
|
+
// return this;
|
|
889
|
+
// },
|
|
890
|
+
// adjust center for view to get inside bounds
|
|
891
|
+
// _limitCenter(center, zoom, bounds) {
|
|
892
|
+
//
|
|
893
|
+
// if (!bounds) { return center; }
|
|
894
|
+
//
|
|
895
|
+
// const centerPoint = this.project(center, zoom),
|
|
896
|
+
// viewHalf = this.getSize().divideBy(2),
|
|
897
|
+
// viewBounds = new Bounds(centerPoint.subtract(viewHalf), centerPoint.add(viewHalf)),
|
|
898
|
+
// offset = this._getBoundsOffset(viewBounds, bounds, zoom);
|
|
899
|
+
//
|
|
900
|
+
// // If offset is less than a pixel, ignore.
|
|
901
|
+
// // This prevents unstable projections from getting into
|
|
902
|
+
// // an infinite loop of tiny offsets.
|
|
903
|
+
// if (Math.abs(offset.x) <= 1 && Math.abs(offset.y) <= 1) {
|
|
904
|
+
// return center;
|
|
905
|
+
// }
|
|
906
|
+
//
|
|
907
|
+
// return this.unproject(centerPoint.add(offset), zoom);
|
|
908
|
+
// },
|
|
909
|
+
// @method flyToBounds(bounds: LatLngBounds, options?: fitBounds options): this
|
|
910
|
+
// Sets the view of the map with a smooth animation like [`flyTo`](#map-flyto),
|
|
911
|
+
// but takes a bounds parameter like [`fitBounds`](#map-fitbounds).
|
|
912
|
+
// flyToBounds(bounds, options) {
|
|
913
|
+
// const target = this._getBoundsCenterZoom(bounds, options);
|
|
914
|
+
// return this.flyTo(target.center, target.zoom, options);
|
|
915
|
+
// },
|
|
916
|
+
// _getBoundsCenterZoom(bounds, options) {
|
|
917
|
+
//
|
|
918
|
+
// options = options || {};
|
|
919
|
+
// bounds = bounds.getBounds ? bounds.getBounds() : toLatLngBounds(bounds);
|
|
920
|
+
//
|
|
921
|
+
// const paddingTL = L.point(options.paddingTopLeft || options.padding || [0, 0]),
|
|
922
|
+
// paddingBR = L.point(options.paddingBottomRight || options.padding || [0, 0]);
|
|
923
|
+
//
|
|
924
|
+
// let zoom = this.getBoundsZoom(bounds, false, paddingTL.add(paddingBR));
|
|
925
|
+
//
|
|
926
|
+
// zoom = (typeof options.maxZoom === 'number') ? Math.min(options.maxZoom, zoom) : zoom;
|
|
927
|
+
//
|
|
928
|
+
// if (zoom === Infinity) {
|
|
929
|
+
// return { center: bounds.getCenter(), zoom };
|
|
930
|
+
// }
|
|
931
|
+
//
|
|
932
|
+
// return { center, zoom };
|
|
933
|
+
//
|
|
934
|
+
// },
|
|
1762
935
|
/**
|
|
1763
|
-
*
|
|
936
|
+
* Returns the maximum zoom level on which the given bounds fit to the map
|
|
937
|
+
* view in its entirety. If `inside` (optional) is set to `true`, the method
|
|
938
|
+
* instead returns the minimum zoom level on which the map view fits into
|
|
939
|
+
* the given bounds in its entirety.
|
|
1764
940
|
*
|
|
1765
|
-
*
|
|
1766
|
-
*
|
|
1767
|
-
*
|
|
941
|
+
* @param {L.LatLngBounds} bounds
|
|
942
|
+
* @param {Boolean} [inside=false]
|
|
943
|
+
* @param {L.Point} [padding=[0,0]]
|
|
1768
944
|
*
|
|
1769
|
-
* @
|
|
945
|
+
* @returns {Number} zoom level
|
|
1770
946
|
*/
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
var bearing = map.getBearing();
|
|
1890
|
-
|
|
1891
|
-
this._arrow.style.transform = 'rotate(' + bearing + 'deg)';
|
|
1892
|
-
|
|
1893
|
-
if (bearing && this.options.closeOnZeroBearing) {
|
|
1894
|
-
this._container.style.display = 'block';
|
|
1895
|
-
}
|
|
1896
|
-
|
|
1897
|
-
// Compass mode
|
|
1898
|
-
if (map.compassBearing.enabled()) {
|
|
1899
|
-
this._link.style.backgroundColor = 'orange';
|
|
1900
|
-
}
|
|
1901
|
-
|
|
1902
|
-
// Touch mode
|
|
1903
|
-
else if (map.touchRotate.enabled()) {
|
|
1904
|
-
this._link.style.backgroundColor = null;
|
|
1905
|
-
}
|
|
1906
|
-
|
|
1907
|
-
// Locked mode
|
|
1908
|
-
else {
|
|
1909
|
-
this._link.style.backgroundColor = 'grey';
|
|
1910
|
-
if (0 === bearing && this.options.closeOnZeroBearing) {
|
|
1911
|
-
this._container.style.display = 'none';
|
|
1912
|
-
}
|
|
1913
|
-
}
|
|
1914
|
-
}
|
|
1915
|
-
},
|
|
1916
|
-
|
|
1917
|
-
});
|
|
1918
|
-
|
|
1919
|
-
L.control.rotate = function(options) {
|
|
1920
|
-
return new L.Control.Rotate(options);
|
|
1921
|
-
};
|
|
1922
|
-
|
|
1923
|
-
L.Map.mergeOptions({
|
|
1924
|
-
rotateControl: true,
|
|
1925
|
-
});
|
|
1926
|
-
|
|
1927
|
-
L.Map.addInitHook(function() {
|
|
1928
|
-
if (this.options.rotateControl) {
|
|
1929
|
-
var options = typeof this.options.rotateControl === 'object' ? this.options.rotateControl : {};
|
|
1930
|
-
this.rotateControl = L.control.rotate(options);
|
|
1931
|
-
this.addControl(this.rotateControl);
|
|
947
|
+
getBoundsZoom(bounds, inside, padding) {
|
|
948
|
+
if (!this._rotate || Math.abs(this._bearing).toFixed(1) < 0.1) {
|
|
949
|
+
return mapProto.getBoundsZoom.apply(this, arguments);
|
|
950
|
+
}
|
|
951
|
+
bounds = bounds instanceof L.LatLngBounds ? bounds : new L.LatLngBounds(bounds);
|
|
952
|
+
padding = toPoint(padding || [0, 0]);
|
|
953
|
+
let zoom = this.getZoom() || 0;
|
|
954
|
+
const min = this.getMinZoom(), max = this.getMaxZoom(), size = this.getSize().subtract(padding), boundsSize = this.mapBoundsToContainerBounds(bounds).getSize(), snap = this.options.zoomSnap, scalex = size.x / boundsSize.x, scaley = size.y / boundsSize.y, scale = inside ? Math.max(scalex, scaley) : Math.min(scalex, scaley);
|
|
955
|
+
zoom = this.getScaleZoom(scale, zoom);
|
|
956
|
+
if (snap) {
|
|
957
|
+
zoom = Math.round(zoom / (snap / 100)) * (snap / 100);
|
|
958
|
+
zoom = inside ? Math.ceil(zoom / snap) * snap : Math.floor(zoom / snap) * snap;
|
|
959
|
+
}
|
|
960
|
+
return Math.max(min, Math.min(max, zoom));
|
|
961
|
+
},
|
|
962
|
+
/**
|
|
963
|
+
* Layer point of the current center
|
|
964
|
+
*
|
|
965
|
+
* @returns {L.Point} layer center
|
|
966
|
+
*/
|
|
967
|
+
// _getCenterLayerPoint() {
|
|
968
|
+
// return this.containerPointToLayerPoint(this.getSize()._divideBy(2));
|
|
969
|
+
// },
|
|
970
|
+
/**
|
|
971
|
+
* Offset of the specified place to the current center in pixels
|
|
972
|
+
*
|
|
973
|
+
* @param {L.LatLng} latlng map coordinates
|
|
974
|
+
*/
|
|
975
|
+
_getCenterOffset(latlng) {
|
|
976
|
+
let centerOffset = mapProto._getCenterOffset.apply(this, arguments);
|
|
977
|
+
if (this._rotate) {
|
|
978
|
+
centerOffset = centerOffset.rotate(this._bearing);
|
|
979
|
+
}
|
|
980
|
+
return centerOffset;
|
|
981
|
+
},
|
|
982
|
+
/**
|
|
983
|
+
* @since leaflet-rotate (v0.1)
|
|
984
|
+
*/
|
|
985
|
+
_getRotatePanePos() {
|
|
986
|
+
return this._rotatePanePos || new L.Point(0, 0);
|
|
987
|
+
},
|
|
988
|
+
// _latLngToNewLayerPoint(latlng, zoom, center) {
|
|
989
|
+
// const topLeft = this._getNewPixelOrigin(center, zoom);
|
|
990
|
+
// return this.project(latlng, zoom)._subtract(topLeft);
|
|
991
|
+
//},
|
|
992
|
+
_getNewPixelOrigin(center, zoom) {
|
|
993
|
+
if (!this._rotate || L.version.startsWith("2.")) {
|
|
994
|
+
return mapProto._getNewPixelOrigin.apply(this, arguments);
|
|
995
|
+
}
|
|
996
|
+
const viewHalf = this.getSize()._divideBy(2);
|
|
997
|
+
return this.project(center, zoom).rotate(this._bearing)._subtract(viewHalf)._add(this._getMapPanePos())._add(this._getRotatePanePos()).rotate(-this._bearing)._round();
|
|
998
|
+
},
|
|
999
|
+
/**
|
|
1000
|
+
* @since leaflet-rotate (v0.2)
|
|
1001
|
+
*
|
|
1002
|
+
* @see src\layer\tile\GridLayer::_getTiledPixelBounds()
|
|
1003
|
+
*/
|
|
1004
|
+
_getNewPixelBounds(center, zoom) {
|
|
1005
|
+
center = center || this.getCenter();
|
|
1006
|
+
zoom = zoom || this.getZoom();
|
|
1007
|
+
if (!this._rotate && mapProto._getNewPixelBounds) {
|
|
1008
|
+
return mapProto._getNewPixelBounds.apply(this, arguments);
|
|
1009
|
+
}
|
|
1010
|
+
const mapZoom = this._animatingZoom ? Math.max(this._animateToZoom, this.getZoom()) : this.getZoom(), scale = this.getZoomScale(mapZoom, zoom), pixelCenter = this.project(center, zoom).floor(), size = this.getSize(), halfSize = new L.Bounds([
|
|
1011
|
+
this.containerPointToLayerPoint([0, 0]).floor(),
|
|
1012
|
+
this.containerPointToLayerPoint([size.x, 0]).floor(),
|
|
1013
|
+
this.containerPointToLayerPoint([0, size.y]).floor(),
|
|
1014
|
+
this.containerPointToLayerPoint([size.x, size.y]).floor()
|
|
1015
|
+
]).getSize().divideBy(scale * 2);
|
|
1016
|
+
return new L.Bounds(pixelCenter.subtract(halfSize), pixelCenter.add(halfSize));
|
|
1017
|
+
},
|
|
1018
|
+
/**
|
|
1019
|
+
* @since leaflet-rotate (v0.2)
|
|
1020
|
+
*
|
|
1021
|
+
* @return {L.Point} map pivot point (center)
|
|
1022
|
+
*/
|
|
1023
|
+
_getPixelCenter() {
|
|
1024
|
+
if (!this._rotate && mapProto._getPixelCenter) {
|
|
1025
|
+
return mapProto._getPixelCenter.apply(this, arguments);
|
|
1026
|
+
}
|
|
1027
|
+
return this.getSize()._divideBy(2)._subtract(this._getMapPanePos());
|
|
1028
|
+
},
|
|
1029
|
+
/**
|
|
1030
|
+
* @since leaflet-rotate (v0.2)
|
|
1031
|
+
*
|
|
1032
|
+
* @see src\layer\vector\Renderer::_update()
|
|
1033
|
+
*/
|
|
1034
|
+
_getPaddedPixelBounds(padding) {
|
|
1035
|
+
if (!this._rotate && mapProto._getPaddedPixelBounds) {
|
|
1036
|
+
return mapProto._getPaddedPixelBounds.apply(this, arguments);
|
|
1037
|
+
}
|
|
1038
|
+
const p = padding, size = this.getSize(), padMin = size.multiplyBy(-p), padMax = size.multiplyBy(1 + p);
|
|
1039
|
+
return new L.Bounds([
|
|
1040
|
+
this.containerPointToLayerPoint([padMin.x, padMin.y]).floor(),
|
|
1041
|
+
this.containerPointToLayerPoint([padMin.x, padMax.y]).floor(),
|
|
1042
|
+
this.containerPointToLayerPoint([padMax.x, padMin.y]).floor(),
|
|
1043
|
+
this.containerPointToLayerPoint([padMax.x, padMax.y]).floor()
|
|
1044
|
+
]);
|
|
1045
|
+
},
|
|
1046
|
+
_handleGeolocationResponse(pos) {
|
|
1047
|
+
if (!this._container._leaflet_id) {
|
|
1048
|
+
return;
|
|
1049
|
+
}
|
|
1050
|
+
const lat = pos.coords.latitude, lng = pos.coords.longitude, hdg = pos.coords.heading, latlng = new L.LatLng(lat, lng), bounds = latlng.toBounds(pos.coords.accuracy), options = this._locateOptions;
|
|
1051
|
+
if (options.setView) {
|
|
1052
|
+
const zoom = this.getBoundsZoom(bounds);
|
|
1053
|
+
this.setView(latlng, options.maxZoom ? Math.min(zoom, options.maxZoom) : zoom);
|
|
1054
|
+
}
|
|
1055
|
+
const data = {
|
|
1056
|
+
latlng,
|
|
1057
|
+
bounds,
|
|
1058
|
+
timestamp: pos.timestamp,
|
|
1059
|
+
/** @TODO use mapProto._handleGeolocationResponse */
|
|
1060
|
+
heading: hdg
|
|
1061
|
+
};
|
|
1062
|
+
for (const i in pos.coords) {
|
|
1063
|
+
if (typeof pos.coords[i] === "number") {
|
|
1064
|
+
data[i] = pos.coords[i];
|
|
1932
1065
|
}
|
|
1933
|
-
|
|
1066
|
+
}
|
|
1067
|
+
this.fire("locationfound", data);
|
|
1068
|
+
}
|
|
1069
|
+
/**
|
|
1070
|
+
* @see https://github.com/ronikar/Leaflet/blob/5c480ef959b947c3beed7065425a5a36c486262b/src/geo/LatLngBounds.js#L253-L264
|
|
1071
|
+
*
|
|
1072
|
+
* @param {L.Bounds} points
|
|
1073
|
+
* @returns {L.Bounds}
|
|
1074
|
+
*/
|
|
1075
|
+
// toCircumscribedBounds(points) {
|
|
1076
|
+
// const minX = points.reduce(function (pv, v) { return Math.min(pv, v.x); }, points[0].x),
|
|
1077
|
+
// maxX = points.reduce(function (pv, v) { return Math.max(pv, v.x); }, points[0].x),
|
|
1078
|
+
// minY = points.reduce(function (pv, v) { return Math.min(pv, v.y); }, points[0].y),
|
|
1079
|
+
// maxY = points.reduce(function (pv, v) { return Math.max(pv, v.y); }, points[0].y);
|
|
1080
|
+
//
|
|
1081
|
+
// return L.bounds(L.point(minX, minY), L.point(maxX, maxY));
|
|
1082
|
+
// },
|
|
1083
|
+
});
|
|
1084
|
+
|
|
1085
|
+
// src/map/handler/CompassBearing.js
|
|
1086
|
+
L.Map.CompassBearing = L.Handler.extend({
|
|
1087
|
+
initialize(map) {
|
|
1088
|
+
this._map = map;
|
|
1089
|
+
if ("ondeviceorientationabsolute" in window) {
|
|
1090
|
+
this.__deviceOrientationEvent = "deviceorientationabsolute";
|
|
1091
|
+
} else if ("ondeviceorientation" in window) {
|
|
1092
|
+
this.__deviceOrientationEvent = "deviceorientation";
|
|
1093
|
+
}
|
|
1094
|
+
this._throttled = L.Util.throttle(this._onDeviceOrientation, 100, this);
|
|
1095
|
+
},
|
|
1096
|
+
addHooks() {
|
|
1097
|
+
if (this._map._rotate && this.__deviceOrientationEvent) {
|
|
1098
|
+
L.DomEvent.on(window, this.__deviceOrientationEvent, this._throttled, this);
|
|
1099
|
+
} else {
|
|
1100
|
+
this.disable();
|
|
1101
|
+
}
|
|
1102
|
+
},
|
|
1103
|
+
removeHooks() {
|
|
1104
|
+
if (this._map._rotate && this.__deviceOrientationEvent) {
|
|
1105
|
+
L.DomEvent.off(window, this.__deviceOrientationEvent, this._throttled, this);
|
|
1106
|
+
}
|
|
1107
|
+
},
|
|
1108
|
+
/**
|
|
1109
|
+
* `DeviceOrientationEvent.absolute` - Indicates whether the device is providing absolute
|
|
1110
|
+
* orientation values (relatives to Magnetic North) or
|
|
1111
|
+
* using some arbitrary frame determined by the device.
|
|
1112
|
+
*
|
|
1113
|
+
* `DeviceOrientationEvent.alpha` - Returns the rotation of the device around the Z axis;
|
|
1114
|
+
* that is, the number of degrees by which the device is
|
|
1115
|
+
* being twisted around the center of the screen.
|
|
1116
|
+
*
|
|
1117
|
+
* `window.orientation` - Returns the screen orientation in degrees (in 90-degree increments)
|
|
1118
|
+
* of the viewport relative to the device's natural orientation.
|
|
1119
|
+
* Its only possible values are -90, 0, 90, and 180. Positive
|
|
1120
|
+
* values are counterclockwise; negative values are clockwise.
|
|
1121
|
+
*
|
|
1122
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/DeviceOrientationEvent/absolute
|
|
1123
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/DeviceOrientationEvent/alpha
|
|
1124
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window/orientation
|
|
1125
|
+
*/
|
|
1126
|
+
_onDeviceOrientation(e) {
|
|
1127
|
+
let angle = e.webkitCompassHeading != null ? e.webkitCompassHeading : e.alpha;
|
|
1128
|
+
let deviceOrientation = 0;
|
|
1129
|
+
if (!Number.isFinite(angle)) {
|
|
1130
|
+
return;
|
|
1131
|
+
}
|
|
1132
|
+
if (!e.absolute && e.webkitCompassHeading) {
|
|
1133
|
+
angle = 360 - angle;
|
|
1134
|
+
}
|
|
1135
|
+
if (!e.absolute && "undefined" !== typeof window.orientation) {
|
|
1136
|
+
deviceOrientation = window.orientation;
|
|
1137
|
+
}
|
|
1138
|
+
this._map.setBearing(angle - deviceOrientation);
|
|
1139
|
+
}
|
|
1140
|
+
});
|
|
1141
|
+
L.Map.addInitHook("addHandler", "compassBearing", L.Map.CompassBearing);
|
|
1142
|
+
|
|
1143
|
+
// src/map/handler/ContainerMutation.js
|
|
1144
|
+
L.Map.mergeOptions({
|
|
1145
|
+
/**
|
|
1146
|
+
* Whether the map uses mutation observers to
|
|
1147
|
+
* detect changes in its container and trigger
|
|
1148
|
+
* `invalidateSize`. Disabled by default due to
|
|
1149
|
+
* support not being available in all web browsers.
|
|
1150
|
+
*
|
|
1151
|
+
* @type {Boolean}
|
|
1152
|
+
*
|
|
1153
|
+
* @see https://developer.mozilla.org/docs/Web/API/MutationObserver
|
|
1154
|
+
*/
|
|
1155
|
+
trackContainerMutation: false
|
|
1156
|
+
});
|
|
1157
|
+
L.Map.ContainerMutation = L.Handler.extend({
|
|
1158
|
+
addHooks() {
|
|
1159
|
+
if (!this._observer) {
|
|
1160
|
+
this._observer = new MutationObserver(L.Util.bind(this._map.invalidateSize, this._map));
|
|
1161
|
+
}
|
|
1162
|
+
this._observer.observe(this._map.getContainer(), {
|
|
1163
|
+
childList: false,
|
|
1164
|
+
attributes: true,
|
|
1165
|
+
characterData: false,
|
|
1166
|
+
subtree: false,
|
|
1167
|
+
attributeFilter: ["style"]
|
|
1168
|
+
});
|
|
1169
|
+
},
|
|
1170
|
+
removeHooks() {
|
|
1171
|
+
this._observer.disconnect();
|
|
1172
|
+
}
|
|
1173
|
+
});
|
|
1174
|
+
L.Map.addInitHook("addHandler", "trackContainerMutation", L.Map.ContainerMutation);
|
|
1175
|
+
|
|
1176
|
+
// src/map/handler/TouchGestures.js
|
|
1177
|
+
function touchToContainerPoint(map, touch) {
|
|
1178
|
+
const container = map.getContainer(), rect = container.getBoundingClientRect();
|
|
1179
|
+
return new L.Point(
|
|
1180
|
+
touch.clientX - rect.left - container.clientLeft,
|
|
1181
|
+
touch.clientY - rect.top - container.clientTop
|
|
1182
|
+
);
|
|
1183
|
+
}
|
|
1184
|
+
L.Map.mergeOptions({
|
|
1185
|
+
/**
|
|
1186
|
+
* Set it to false if you don't want the map to
|
|
1187
|
+
* zoom beyond min/max zoom and then bounce back
|
|
1188
|
+
* when pinch-zooming.
|
|
1189
|
+
*
|
|
1190
|
+
* @type {Boolean}
|
|
1191
|
+
*/
|
|
1192
|
+
bounceAtZoomLimits: true
|
|
1193
|
+
});
|
|
1194
|
+
L.Map.TouchGestures = L.Handler.extend({
|
|
1195
|
+
initialize(map) {
|
|
1196
|
+
this._map = map;
|
|
1197
|
+
this.rotate = !!this._map.options.touchRotate;
|
|
1198
|
+
this.zoom = !!this._map.options.touchZoom;
|
|
1199
|
+
},
|
|
1200
|
+
addHooks() {
|
|
1201
|
+
L.DomEvent.on(this._map._container, "touchstart", this._onTouchStart, this);
|
|
1202
|
+
},
|
|
1203
|
+
removeHooks() {
|
|
1204
|
+
L.DomEvent.off(this._map._container, "touchstart", this._onTouchStart, this);
|
|
1205
|
+
},
|
|
1206
|
+
_onTouchStart(e) {
|
|
1207
|
+
const map = this._map;
|
|
1208
|
+
if (!e.touches || e.touches.length !== 2 || map._animatingZoom || this._zooming || this._rotating) {
|
|
1209
|
+
return;
|
|
1210
|
+
}
|
|
1211
|
+
const p1 = touchToContainerPoint(map, e.touches[0]), p2 = touchToContainerPoint(map, e.touches[1]), vector = p1.subtract(p2);
|
|
1212
|
+
this._centerPoint = map.getSize()._divideBy(2);
|
|
1213
|
+
this._startLatLng = map.containerPointToLatLng(this._centerPoint);
|
|
1214
|
+
if (this.zoom) {
|
|
1215
|
+
if (map.options.touchZoom !== "center") {
|
|
1216
|
+
this._pinchStartLatLng = map.containerPointToLatLng(p1.add(p2)._divideBy(2));
|
|
1217
|
+
}
|
|
1218
|
+
this._startDist = p1.distanceTo(p2);
|
|
1219
|
+
this._startZoom = map.getZoom();
|
|
1220
|
+
this._zooming = true;
|
|
1221
|
+
} else {
|
|
1222
|
+
this._zooming = false;
|
|
1223
|
+
}
|
|
1224
|
+
if (this.rotate) {
|
|
1225
|
+
this._startTheta = Math.atan(vector.x / vector.y);
|
|
1226
|
+
this._startBearing = map.getBearing();
|
|
1227
|
+
if (vector.y < 0) {
|
|
1228
|
+
this._startBearing += 180;
|
|
1229
|
+
}
|
|
1230
|
+
this._rotating = true;
|
|
1231
|
+
} else {
|
|
1232
|
+
this._rotating = false;
|
|
1233
|
+
}
|
|
1234
|
+
this._moved = false;
|
|
1235
|
+
map._stop();
|
|
1236
|
+
L.DomEvent.on(document, "touchmove", this._onTouchMove, this).on(document, "touchend touchcancel", this._onTouchEnd, this);
|
|
1237
|
+
L.DomEvent.preventDefault(e);
|
|
1238
|
+
},
|
|
1239
|
+
_onTouchMove(e) {
|
|
1240
|
+
if (!e.touches || e.touches.length !== 2 || !(this._zooming || this._rotating)) {
|
|
1241
|
+
return;
|
|
1242
|
+
}
|
|
1243
|
+
const map = this._map, p1 = touchToContainerPoint(map, e.touches[0]), p2 = touchToContainerPoint(map, e.touches[1]), vector = p1.subtract(p2), scale = p1.distanceTo(p2) / this._startDist;
|
|
1244
|
+
let delta;
|
|
1245
|
+
if (this._rotating) {
|
|
1246
|
+
const theta = Math.atan(vector.x / vector.y);
|
|
1247
|
+
let bearingDelta = (theta - this._startTheta) * (180 / Math.PI);
|
|
1248
|
+
if (vector.y < 0) {
|
|
1249
|
+
bearingDelta += 180;
|
|
1250
|
+
}
|
|
1251
|
+
if (bearingDelta) {
|
|
1252
|
+
map.setBearing(this._startBearing - bearingDelta);
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
if (this._zooming) {
|
|
1256
|
+
this._zoom = map.getScaleZoom(scale, this._startZoom);
|
|
1257
|
+
if (!map.options.bounceAtZoomLimits && (this._zoom < map.getMinZoom() && scale < 1 || this._zoom > map.getMaxZoom() && scale > 1)) {
|
|
1258
|
+
this._zoom = map._limitZoom(this._zoom);
|
|
1259
|
+
}
|
|
1260
|
+
if (map.options.touchZoom === "center") {
|
|
1261
|
+
this._center = this._startLatLng;
|
|
1262
|
+
if (scale === 1) {
|
|
1263
|
+
return;
|
|
1264
|
+
}
|
|
1265
|
+
} else {
|
|
1266
|
+
delta = p1._add(p2)._divideBy(2)._subtract(this._centerPoint);
|
|
1267
|
+
if (scale === 1 && delta.x === 0 && delta.y === 0) {
|
|
1268
|
+
return;
|
|
1269
|
+
}
|
|
1270
|
+
const alpha = -map.getBearing() * (Math.PI / 180);
|
|
1271
|
+
this._center = map.unproject(map.project(this._pinchStartLatLng).subtract(delta.rotate(alpha)));
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
if (!this._moved) {
|
|
1275
|
+
map._moveStart(true, false);
|
|
1276
|
+
this._moved = true;
|
|
1277
|
+
}
|
|
1278
|
+
const moveFn = map._move.bind(map, this._center, this._zoom, { pinch: true, round: false }, void 0);
|
|
1279
|
+
moveFn();
|
|
1280
|
+
if (this.zoom) {
|
|
1281
|
+
if (map.options.zoomAnimation) {
|
|
1282
|
+
map._animateZoomNoDelay(this._center, map._limitZoom(this._zoom));
|
|
1283
|
+
} else {
|
|
1284
|
+
map._resetView(this._center, map._limitZoom(this._zoom));
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
L.DomEvent.preventDefault(e);
|
|
1288
|
+
},
|
|
1289
|
+
_onTouchEnd() {
|
|
1290
|
+
if (!this._moved || !(this._zooming || this._rotating)) {
|
|
1291
|
+
this._zooming = false;
|
|
1292
|
+
return;
|
|
1293
|
+
}
|
|
1294
|
+
this._zooming = false;
|
|
1295
|
+
this._rotating = false;
|
|
1296
|
+
L.DomEvent.off(document, "touchmove", this._onTouchMove, this).off(document, "touchend touchcancel", this._onTouchEnd, this);
|
|
1297
|
+
if (this.zoom) {
|
|
1298
|
+
if (this._map.options.zoomAnimation) {
|
|
1299
|
+
this._map._animateZoom(this._center, this._map._limitZoom(this._zoom), true, this._map.options.zoomSnap);
|
|
1300
|
+
} else {
|
|
1301
|
+
this._map._resetView(this._center, this._map._limitZoom(this._zoom));
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
});
|
|
1306
|
+
L.Map.addInitHook("addHandler", "touchGestures", L.Map.TouchGestures);
|
|
1934
1307
|
|
|
1935
|
-
|
|
1308
|
+
// src/map/handler/TouchRotate.js
|
|
1309
|
+
L.Map.mergeOptions({
|
|
1310
|
+
/**
|
|
1311
|
+
* Whether the map can be rotated with a two-finger rotation gesture
|
|
1312
|
+
*
|
|
1313
|
+
* @type {Boolean}
|
|
1314
|
+
*/
|
|
1315
|
+
touchRotate: false
|
|
1316
|
+
});
|
|
1317
|
+
L.Map.TouchRotate = L.Handler.extend({
|
|
1318
|
+
addHooks() {
|
|
1319
|
+
this._map.touchGestures.enable();
|
|
1320
|
+
this._map.touchGestures.rotate = true;
|
|
1321
|
+
},
|
|
1322
|
+
removeHooks() {
|
|
1323
|
+
this._map.touchGestures.rotate = false;
|
|
1324
|
+
}
|
|
1325
|
+
});
|
|
1326
|
+
L.Map.addInitHook("addHandler", "touchRotate", L.Map.TouchRotate);
|
|
1327
|
+
|
|
1328
|
+
// src/map/handler/ShiftKeyRotate.js
|
|
1329
|
+
L.Map.mergeOptions({
|
|
1330
|
+
/**
|
|
1331
|
+
* Whether the map can be rotated with shift + wheel scroll
|
|
1332
|
+
* @type {Boolean}
|
|
1333
|
+
*/
|
|
1334
|
+
shiftKeyRotate: true
|
|
1335
|
+
});
|
|
1336
|
+
L.Map.ShiftKeyRotate = L.Handler.extend({
|
|
1337
|
+
addHooks() {
|
|
1338
|
+
L.DomEvent.on(this._map._container, "wheel", this._handleShiftScroll, this);
|
|
1339
|
+
this._map.shiftKeyRotate.rotate = true;
|
|
1340
|
+
},
|
|
1341
|
+
removeHooks() {
|
|
1342
|
+
L.DomEvent.off(this._map._container, "wheel", this._handleShiftScroll, this);
|
|
1343
|
+
this._map.shiftKeyRotate.rotate = false;
|
|
1344
|
+
},
|
|
1345
|
+
_handleShiftScroll(e) {
|
|
1346
|
+
if (e.shiftKey) {
|
|
1347
|
+
e.preventDefault();
|
|
1348
|
+
this._map.scrollWheelZoom.disable();
|
|
1349
|
+
this._map.setBearing(this._map._bearing * (180 / Math.PI) + Math.sign(e.deltaY) * 5);
|
|
1350
|
+
} else {
|
|
1351
|
+
this._map.scrollWheelZoom.enable();
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
});
|
|
1355
|
+
L.Map.addInitHook("addHandler", "shiftKeyRotate", L.Map.ShiftKeyRotate);
|
|
1356
|
+
L.Map.addInitHook(function() {
|
|
1357
|
+
if (this.scrollWheelZoom.enabled() && this.shiftKeyRotate.enabled()) {
|
|
1358
|
+
this.scrollWheelZoom.disable();
|
|
1359
|
+
this.scrollWheelZoom.enable();
|
|
1360
|
+
}
|
|
1361
|
+
});
|
|
1362
|
+
|
|
1363
|
+
// src/map/handler/TouchZoom.js
|
|
1364
|
+
L.Map.mergeOptions({
|
|
1365
|
+
/**
|
|
1366
|
+
* Whether the map can be zoomed by touch-dragging
|
|
1367
|
+
* with two fingers. If passed `'center'`, it will
|
|
1368
|
+
* zoom to the center of the view regardless of
|
|
1369
|
+
* where the touch events (fingers) were. Enabled
|
|
1370
|
+
* for touch-capable web browsers.
|
|
1371
|
+
*
|
|
1372
|
+
* @type {(Boolean|String)}
|
|
1373
|
+
*/
|
|
1374
|
+
touchZoom: L.Browser.touch,
|
|
1375
|
+
/**
|
|
1376
|
+
* @TODO check if this is a duplicate of `L.Map.TouchGestures::bounceAtZoomLimits`
|
|
1377
|
+
*
|
|
1378
|
+
* Set it to false if you don't want the map to
|
|
1379
|
+
* zoom beyond min/max zoom and then bounce back
|
|
1380
|
+
* when pinch-zooming.
|
|
1381
|
+
*
|
|
1382
|
+
* @type {Boolean}
|
|
1383
|
+
*/
|
|
1384
|
+
bounceAtZoomLimits: false
|
|
1385
|
+
});
|
|
1386
|
+
L.Map.TouchZoom = L.Handler.extend({
|
|
1387
|
+
addHooks() {
|
|
1388
|
+
this._map._container.classList.add("leaflet-touch-zoom");
|
|
1389
|
+
this._map.touchGestures.enable();
|
|
1390
|
+
this._map.touchGestures.zoom = true;
|
|
1391
|
+
},
|
|
1392
|
+
removeHooks() {
|
|
1393
|
+
this._map._container.classList.remove("leaflet-touch-zoom");
|
|
1394
|
+
this._map.touchGestures.zoom = false;
|
|
1395
|
+
}
|
|
1396
|
+
});
|
|
1397
|
+
L.Map.addInitHook("addHandler", "touchZoom", L.Map.TouchZoom);
|
|
1398
|
+
|
|
1399
|
+
// src/control/Rotate.js
|
|
1400
|
+
L.Control.Rotate = L.Control.extend({
|
|
1401
|
+
options: {
|
|
1402
|
+
position: "topleft",
|
|
1403
|
+
closeOnZeroBearing: true
|
|
1404
|
+
},
|
|
1405
|
+
onAdd(map) {
|
|
1406
|
+
const container = this._container = L.DomUtil.create("div", "leaflet-control-rotate leaflet-bar");
|
|
1407
|
+
const arrow = this._arrow = L.DomUtil.create("span", "leaflet-control-rotate-arrow");
|
|
1408
|
+
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")`;
|
|
1409
|
+
arrow.style.cursor = "grab";
|
|
1410
|
+
arrow.style.display = "block";
|
|
1411
|
+
arrow.style.width = "100%";
|
|
1412
|
+
arrow.style.height = "100%";
|
|
1413
|
+
arrow.style.backgroundRepeat = "no-repeat";
|
|
1414
|
+
arrow.style.backgroundPosition = "50%";
|
|
1415
|
+
const link = this._link = L.DomUtil.create("a", "leaflet-control-rotate-toggle", container);
|
|
1416
|
+
link.appendChild(arrow);
|
|
1417
|
+
link.href = "#";
|
|
1418
|
+
link.title = "Rotate map";
|
|
1419
|
+
L.DomEvent.on(link, "dblclick", L.DomEvent.stopPropagation).on(link, "mousedown", this._handleMouseDown, this).on(link, "click", L.DomEvent.stop).on(link, "click", this._cycleState, this).on(link, "click", this._refocusOnMap, this);
|
|
1420
|
+
this._restyle();
|
|
1421
|
+
map.on("rotate", this._restyle, this);
|
|
1422
|
+
this._follow = false;
|
|
1423
|
+
this._canFollow = false;
|
|
1424
|
+
if (this.options.closeOnZeroBearing && map.getBearing() === 0) {
|
|
1425
|
+
container.style.display = "none";
|
|
1426
|
+
}
|
|
1427
|
+
return container;
|
|
1428
|
+
},
|
|
1429
|
+
onRemove(map) {
|
|
1430
|
+
map.off("rotate", this._restyle, this);
|
|
1431
|
+
},
|
|
1432
|
+
_handleMouseDown(e) {
|
|
1433
|
+
L.DomEvent.stop(e);
|
|
1434
|
+
this.dragging = true;
|
|
1435
|
+
this.dragstartX = e.pageX;
|
|
1436
|
+
this.dragstartY = e.pageY;
|
|
1437
|
+
L.DomEvent.on(document, "mousemove", this._handleMouseDrag, this).on(document, "mouseup", this._handleMouseUp, this);
|
|
1438
|
+
},
|
|
1439
|
+
_handleMouseUp(e) {
|
|
1440
|
+
L.DomEvent.stop(e);
|
|
1441
|
+
this.dragging = false;
|
|
1442
|
+
L.DomEvent.off(document, "mousemove", this._handleMouseDrag, this).off(document, "mouseup", this._handleMouseUp, this);
|
|
1443
|
+
},
|
|
1444
|
+
_handleMouseDrag(e) {
|
|
1445
|
+
if (!this.dragging) {
|
|
1446
|
+
return;
|
|
1447
|
+
}
|
|
1448
|
+
const deltaX = e.clientX - this.dragstartX;
|
|
1449
|
+
this._map.setBearing(deltaX);
|
|
1450
|
+
},
|
|
1451
|
+
_cycleState(ev) {
|
|
1452
|
+
if (!this._map) {
|
|
1453
|
+
return;
|
|
1454
|
+
}
|
|
1455
|
+
const map = this._map;
|
|
1456
|
+
if (!map.touchRotate.enabled() && !map.compassBearing.enabled()) {
|
|
1457
|
+
map.touchRotate.enable();
|
|
1458
|
+
} else if (!map.compassBearing.enabled()) {
|
|
1459
|
+
map.touchRotate.disable();
|
|
1460
|
+
(DeviceOrientationEvent && DeviceOrientationEvent.requestPermission ? DeviceOrientationEvent.requestPermission() : Promise.resolve("granted")).then((state) => "granted" === state && map.compassBearing.enable());
|
|
1461
|
+
} else {
|
|
1462
|
+
map.compassBearing.disable();
|
|
1463
|
+
map.setBearing(0);
|
|
1464
|
+
if (this.options.closeOnZeroBearing) {
|
|
1465
|
+
map.touchRotate.enable();
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
this._restyle();
|
|
1469
|
+
},
|
|
1470
|
+
_restyle() {
|
|
1471
|
+
if (!this._map.options.rotate) {
|
|
1472
|
+
this._link.classList.add("leaflet-disabled");
|
|
1473
|
+
} else {
|
|
1474
|
+
const map = this._map;
|
|
1475
|
+
const bearing = map.getBearing();
|
|
1476
|
+
this._arrow.style.transform = "rotate(" + bearing + "deg)";
|
|
1477
|
+
if (bearing && this.options.closeOnZeroBearing) {
|
|
1478
|
+
this._container.style.display = "block";
|
|
1479
|
+
}
|
|
1480
|
+
if (map.compassBearing.enabled()) {
|
|
1481
|
+
this._link.style.backgroundColor = "orange";
|
|
1482
|
+
} else if (map.touchRotate.enabled()) {
|
|
1483
|
+
this._link.style.backgroundColor = null;
|
|
1484
|
+
} else {
|
|
1485
|
+
this._link.style.backgroundColor = "grey";
|
|
1486
|
+
if (0 === bearing && this.options.closeOnZeroBearing) {
|
|
1487
|
+
this._container.style.display = "none";
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
});
|
|
1493
|
+
if (L.control) {
|
|
1494
|
+
L.control.rotate = (options) => new L.Control.Rotate(options);
|
|
1495
|
+
}
|
|
1496
|
+
L.Map.mergeOptions({
|
|
1497
|
+
rotateControl: true
|
|
1498
|
+
});
|
|
1499
|
+
L.Map.addInitHook(function() {
|
|
1500
|
+
if (this.options.rotateControl) {
|
|
1501
|
+
const options = typeof this.options.rotateControl === "object" ? this.options.rotateControl : {};
|
|
1502
|
+
this.rotateControl = new L.Control.Rotate(options);
|
|
1503
|
+
this.addControl(this.rotateControl);
|
|
1504
|
+
}
|
|
1505
|
+
});
|
|
1506
|
+
return __toCommonJS(index_exports);
|
|
1507
|
+
})();
|
|
1936
1508
|
//# sourceMappingURL=leaflet-rotate-src.js.map
|