leaflet-rotate 0.1.4 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/build/rollup.config.js +4 -4
- package/dist/leaflet-rotate-src.js +744 -329
- package/dist/leaflet-rotate-src.js.map +1 -1
- package/dist/leaflet-rotate.js +1760 -1
- package/dist/leaflet-rotate.js.map +1 -1
- package/lib/debug.js +253 -21
- package/lib/debug.min.js +1 -9
- package/package.json +10 -7
- package/src/control/Rotate.js +10 -7
- package/src/dom/DomUtil.js +8 -5
- package/src/dom/Draggable.js +8 -5
- package/src/geometry/Point.js +22 -18
- package/src/index.js +5 -3
- package/src/layer/DivOverlay.js +14 -22
- package/src/layer/Popup.js +30 -10
- package/src/layer/Tooltip.js +10 -7
- package/src/layer/marker/Icon.js +5 -2
- package/src/layer/marker/Marker.js +52 -43
- package/src/layer/tile/GridLayer.js +7 -16
- package/src/layer/vector/Canvas.js +18 -15
- package/src/layer/vector/Renderer.js +23 -32
- package/src/layer/vector/SVG.js +10 -7
- package/src/map/Map.js +462 -96
- package/src/map/handler/CompassBearing.js +7 -11
- package/src/map/handler/ContainerMutation.js +12 -8
- package/src/map/handler/ShiftKeyRotate.js +5 -2
- package/src/map/handler/TouchGestures.js +16 -11
- package/src/map/handler/TouchRotate.js +4 -2
- package/src/map/handler/TouchZoom.js +16 -4
- package/test/index.html +30 -6
- package/build/rollup.config.min.js +0 -2
- package/src/map/handler/ShiftKeyRotate.min.js +0 -1
package/src/map/Map.js
CHANGED
|
@@ -1,39 +1,41 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* L.Map
|
|
2
|
+
* @external L.Map
|
|
3
|
+
*
|
|
4
|
+
* @see https://github.com/Leaflet/Leaflet/blob/v1.9.3/src/map/Map.js
|
|
3
5
|
*/
|
|
6
|
+
|
|
4
7
|
const mapProto = L.extend({}, L.Map.prototype);
|
|
5
8
|
|
|
6
9
|
L.Map.mergeOptions({ rotate: false, bearing: 0, });
|
|
7
10
|
|
|
8
11
|
L.Map.include({
|
|
9
12
|
|
|
10
|
-
|
|
13
|
+
/**
|
|
14
|
+
* @param {(HTMLElement|String)} id html selector
|
|
15
|
+
* @param {Object} [options={}] leaflet map options
|
|
16
|
+
*/
|
|
17
|
+
initialize: function(id, options) {
|
|
11
18
|
if (options.rotate) {
|
|
12
19
|
this._rotate = true;
|
|
13
20
|
this._bearing = 0;
|
|
14
21
|
}
|
|
15
|
-
mapProto.initialize.
|
|
22
|
+
mapProto.initialize.apply(this, arguments);
|
|
16
23
|
if(this.options.rotate){
|
|
17
24
|
this.setBearing(this.options.bearing);
|
|
18
25
|
}
|
|
19
26
|
},
|
|
20
27
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
// }
|
|
31
|
-
// return mapProto.createPane.call(this, name, container || this._rotatePane);
|
|
32
|
-
// },
|
|
33
|
-
|
|
34
|
-
containerPointToLayerPoint: function(point) { // (Point)
|
|
28
|
+
/**
|
|
29
|
+
* Given a pixel coordinate relative to the map container,
|
|
30
|
+
* returns the corresponding pixel coordinate relative to
|
|
31
|
+
* the [origin pixel](#map-getpixelorigin).
|
|
32
|
+
*
|
|
33
|
+
* @param {L.Point} point pixel screen coordinates
|
|
34
|
+
* @returns {L.Point} transformed pixel point
|
|
35
|
+
*/
|
|
36
|
+
containerPointToLayerPoint: function(point) {
|
|
35
37
|
if (!this._rotate) {
|
|
36
|
-
return mapProto.containerPointToLayerPoint.
|
|
38
|
+
return mapProto.containerPointToLayerPoint.apply(this, arguments);
|
|
37
39
|
}
|
|
38
40
|
return L.point(point)
|
|
39
41
|
.subtract(this._getMapPanePos())
|
|
@@ -41,113 +43,232 @@ L.Map.include({
|
|
|
41
43
|
.subtract(this._getRotatePanePos());
|
|
42
44
|
},
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Given a pixel coordinate relative to the [origin pixel](#map-getpixelorigin),
|
|
48
|
+
* returns the corresponding pixel coordinate relative to the map container.
|
|
49
|
+
*
|
|
50
|
+
* @param {L.Point} point pixel screen coordinates
|
|
51
|
+
* @returns {L.Point} transformed pixel point
|
|
52
|
+
*/
|
|
53
|
+
layerPointToContainerPoint: function(point) {
|
|
45
54
|
if (!this._rotate) {
|
|
46
|
-
return mapProto.
|
|
55
|
+
return mapProto.layerPointToContainerPoint.apply(this, arguments);
|
|
47
56
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
57
|
+
return L.point(point)
|
|
58
|
+
.add(this._getRotatePanePos())
|
|
59
|
+
.rotateFrom(this._bearing, this._getRotatePanePos())
|
|
60
|
+
.add(this._getMapPanePos());
|
|
61
|
+
},
|
|
53
62
|
|
|
54
|
-
|
|
55
|
-
|
|
63
|
+
/**
|
|
64
|
+
* Converts a coordinate from the rotated pane reference system
|
|
65
|
+
* to the reference system of the not rotated map pane.
|
|
66
|
+
*
|
|
67
|
+
* (rotatePane) --> (mapPane)
|
|
68
|
+
* (rotatePane) --> (norotatePane)
|
|
69
|
+
*
|
|
70
|
+
* @param {L.Point} point pixel screen coordinates
|
|
71
|
+
* @returns {L.Point}
|
|
72
|
+
*
|
|
73
|
+
* @since leaflet-rotate (v0.1)
|
|
74
|
+
*/
|
|
75
|
+
rotatedPointToMapPanePoint: function(point) {
|
|
76
|
+
return L.point(point)
|
|
77
|
+
.rotate(this._bearing)
|
|
78
|
+
._add(this._getRotatePanePos());
|
|
56
79
|
},
|
|
57
80
|
|
|
58
|
-
|
|
81
|
+
/**
|
|
82
|
+
* Converts a coordinate from the not rotated map pane reference system
|
|
83
|
+
* to the reference system of the rotated pane.
|
|
84
|
+
*
|
|
85
|
+
* (mapPane) --> (rotatePane)
|
|
86
|
+
* (norotatePane) --> (rotatePane)
|
|
87
|
+
*
|
|
88
|
+
* @param {L.Point} point pixel screen coordinates
|
|
89
|
+
*
|
|
90
|
+
* @since leaflet-rotate (v0.1)
|
|
91
|
+
*/
|
|
92
|
+
mapPanePointToRotatedPoint: function(point) {
|
|
93
|
+
return L.point(point)
|
|
94
|
+
._subtract(this._getRotatePanePos())
|
|
95
|
+
.rotate(-this._bearing);
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Given latlng bounds, returns the bounds in projected pixel
|
|
100
|
+
* relative to the map container.
|
|
101
|
+
*
|
|
102
|
+
* @see https://github.com/ronikar/Leaflet/blob/5c480ef959b947c3beed7065425a5a36c486262b/src/map/Map.js#L1114-L1135
|
|
103
|
+
*
|
|
104
|
+
* @param {L.LatLngBounds} bounds
|
|
105
|
+
* @returns {L.Bounds}
|
|
106
|
+
*
|
|
107
|
+
* @since leaflet-rotate (v0.2)
|
|
108
|
+
*/
|
|
109
|
+
mapBoundsToContainerBounds: function (bounds) {
|
|
110
|
+
if (!this._rotate && mapProto.mapBoundsToContainerBounds) {
|
|
111
|
+
return mapProto.mapBoundsToContainerBounds.apply(this, arguments);
|
|
112
|
+
}
|
|
113
|
+
const nw = this.latLngToContainerPoint(bounds.getNorthWest()),
|
|
114
|
+
ne = this.latLngToContainerPoint(bounds.getNorthEast()),
|
|
115
|
+
sw = this.latLngToContainerPoint(bounds.getSouthWest()),
|
|
116
|
+
se = this.latLngToContainerPoint(bounds.getSouthEast());
|
|
117
|
+
return L.bounds([
|
|
118
|
+
L.point(Math.min(nw.x, ne.x, se.x, sw.x), Math.min(nw.y, ne.y, se.y, sw.y)), // [ minX, minY ]
|
|
119
|
+
L.point(Math.max(nw.x, ne.x, se.x, sw.x), Math.max(nw.y, ne.y, se.y, sw.y)) // [ maxX, maxY ]
|
|
120
|
+
]);
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Returns geographical bounds visible in the current map view
|
|
125
|
+
*
|
|
126
|
+
* @TODO find out if map bounds calculated by `L.Map::getBounds()`
|
|
127
|
+
* function should match the `rotatePane` or `norotatePane` bounds
|
|
128
|
+
*
|
|
129
|
+
* @see https://github.com/fnicollet/Leaflet/issues/7
|
|
130
|
+
*
|
|
131
|
+
* @returns {L.LatLngBounds}
|
|
132
|
+
*/
|
|
133
|
+
getBounds: function() {
|
|
59
134
|
if (!this._rotate) {
|
|
60
|
-
return mapProto.
|
|
135
|
+
return mapProto.getBounds.apply(this, arguments);
|
|
61
136
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
137
|
+
|
|
138
|
+
// SEE: https://github.com/fnicollet/Leaflet/pull/22
|
|
139
|
+
//
|
|
140
|
+
// var bounds = this.getPixelBounds(),
|
|
141
|
+
// sw = this.unproject(bounds.getBottomLeft()),
|
|
142
|
+
// ne = this.unproject(bounds.getTopRight());
|
|
143
|
+
// return new LatLngBounds(sw, ne);
|
|
144
|
+
//
|
|
145
|
+
|
|
146
|
+
// LatLngBounds' constructor automatically
|
|
147
|
+
// extends the bounds to fit the passed points
|
|
148
|
+
var size = this.getSize();
|
|
149
|
+
return new L.LatLngBounds([
|
|
150
|
+
this.containerPointToLatLng([0, 0]), // topleft
|
|
151
|
+
this.containerPointToLatLng([size.x, 0]), // topright
|
|
152
|
+
this.containerPointToLatLng([size.x, size.y]), // bottomright
|
|
153
|
+
this.containerPointToLatLng([0, size.y]), // bottomleft
|
|
154
|
+
]);
|
|
66
155
|
},
|
|
67
156
|
|
|
68
|
-
|
|
69
|
-
|
|
157
|
+
/**
|
|
158
|
+
* Returns the bounds of the current map view in projected pixel
|
|
159
|
+
* coordinates (sometimes useful in layer and overlay implementations).
|
|
160
|
+
*
|
|
161
|
+
* @TODO find out if map bounds calculated by `L.Map::getPixelBounds()`
|
|
162
|
+
* function should match the `rotatePane` or `norotatePane` bounds
|
|
163
|
+
*
|
|
164
|
+
* @see https://github.com/fnicollet/Leaflet/issues/7
|
|
165
|
+
*
|
|
166
|
+
* @returns {L.Bounds}
|
|
167
|
+
*/
|
|
168
|
+
// getPixelBounds(center, zoom) {
|
|
169
|
+
// // const topLeftPoint = map.containerPointToLayerPoint(this._getTopLeftPoint());
|
|
170
|
+
// const topLeftPoint = this._getTopLeftPoint(center, zoom);
|
|
171
|
+
// return new L.Bounds(topLeftPoint, topLeftPoint.add(this.getSize()));
|
|
172
|
+
// },
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Change map rotation
|
|
176
|
+
*
|
|
177
|
+
* @param {number} theta map degrees
|
|
178
|
+
*
|
|
179
|
+
* @since leaflet-rotate (v0.1)
|
|
180
|
+
*/
|
|
70
181
|
setBearing: function(theta) {
|
|
71
182
|
if (!L.Browser.any3d || !this._rotate) { return; }
|
|
72
183
|
|
|
73
|
-
var
|
|
74
|
-
|
|
75
|
-
|
|
184
|
+
var bearing = L.Util.wrapNum(theta, [0, 360]) * L.DomUtil.DEG_TO_RAD,
|
|
185
|
+
center = this._getPixelCenter(),
|
|
186
|
+
oldPos = this._getRotatePanePos().rotateFrom(-this._bearing, center),
|
|
187
|
+
newPos = oldPos.rotateFrom(bearing, center);
|
|
76
188
|
|
|
77
|
-
|
|
189
|
+
// CSS transform
|
|
190
|
+
L.DomUtil.setPosition(this._rotatePane, oldPos, bearing, center);
|
|
78
191
|
|
|
79
|
-
this.
|
|
80
|
-
this.
|
|
81
|
-
|
|
82
|
-
L.DomUtil.setPosition(this._rotatePane, rotatePanePos, this._bearing, this._pivot);
|
|
192
|
+
this._pivot = center;
|
|
193
|
+
this._bearing = bearing;
|
|
194
|
+
this._rotatePanePos = newPos;
|
|
83
195
|
|
|
84
196
|
this.fire('rotate');
|
|
85
197
|
},
|
|
86
198
|
|
|
199
|
+
/**
|
|
200
|
+
* Get current map rotation
|
|
201
|
+
*
|
|
202
|
+
* @returns {number} theta map degrees
|
|
203
|
+
*
|
|
204
|
+
* @since leaflet-rotate (v0.1)
|
|
205
|
+
*/
|
|
87
206
|
getBearing: function() {
|
|
88
207
|
return this._bearing * L.DomUtil.RAD_TO_DEG;
|
|
89
208
|
},
|
|
90
209
|
|
|
210
|
+
/**
|
|
211
|
+
* Creates a new [map pane](#map-pane) with the given name if it doesn't
|
|
212
|
+
* exist already, then returns it. The pane is created as a child of
|
|
213
|
+
* `container`, or as a child of the main map pane if not set.
|
|
214
|
+
*
|
|
215
|
+
* @param {String} name leaflet pane
|
|
216
|
+
* @param {HTMLElement} [container] parent element
|
|
217
|
+
* @returns {HTMLElement} pane container
|
|
218
|
+
*/
|
|
219
|
+
// createPane: function(name, container) {
|
|
220
|
+
// if (!this._rotate || name == 'mapPane') {
|
|
221
|
+
// return mapProto.createPane.apply(this, arguments);
|
|
222
|
+
// }
|
|
223
|
+
// // init "rotatePane"
|
|
224
|
+
// if (!this._rotatePane) {
|
|
225
|
+
// // this._pivot = this.getSize().divideBy(2);
|
|
226
|
+
// this._rotatePane = mapProto.createPane.call(this, 'rotatePane', this._mapPane);
|
|
227
|
+
// L.DomUtil.setPosition(this._rotatePane, new L.Point(0, 0), this._bearing, this._pivot);
|
|
228
|
+
// }
|
|
229
|
+
// return mapProto.createPane.call(this, name, container || this._rotatePane);
|
|
230
|
+
// },
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Panes are DOM elements used to control the ordering of layers on
|
|
234
|
+
* the map. You can access panes with [`map.getPane`](#map-getpane)
|
|
235
|
+
* or [`map.getPanes`](#map-getpanes) methods. New panes can be created
|
|
236
|
+
* with the [`map.createPane`](#map-createpane) method.
|
|
237
|
+
*
|
|
238
|
+
* Every map has the following default panes that differ only in zIndex:
|
|
239
|
+
*
|
|
240
|
+
* - mapPane [HTMLElement = 'auto'] - Pane that contains all other map panes
|
|
241
|
+
* - tilePane [HTMLElement = 2] - Pane for tile layers
|
|
242
|
+
* - overlayPane [HTMLElement = 4] - Pane for overlays like polylines and polygons
|
|
243
|
+
* - shadowPane [HTMLElement = 5] - Pane for overlay shadows (e.g. marker shadows)
|
|
244
|
+
* - markerPane [HTMLElement = 6] - Pane for marker icons
|
|
245
|
+
* - tooltipPane [HTMLElement = 650] - Pane for tooltips.
|
|
246
|
+
* - popupPane [HTMLElement = 700] - Pane for popups.
|
|
247
|
+
*/
|
|
91
248
|
_initPanes: function() {
|
|
92
249
|
var panes = this._panes = {};
|
|
93
250
|
this._paneRenderers = {};
|
|
94
251
|
|
|
95
|
-
// @section
|
|
96
|
-
//
|
|
97
|
-
// Panes are DOM elements used to control the ordering of layers on the map. You
|
|
98
|
-
// can access panes with [`map.getPane`](#map-getpane) or
|
|
99
|
-
// [`map.getPanes`](#map-getpanes) methods. New panes can be created with the
|
|
100
|
-
// [`map.createPane`](#map-createpane) method.
|
|
101
|
-
//
|
|
102
|
-
// Every map has the following default panes that differ only in zIndex.
|
|
103
|
-
//
|
|
104
|
-
// @pane mapPane: HTMLElement = 'auto'
|
|
105
|
-
// Pane that contains all other map panes
|
|
106
|
-
|
|
107
252
|
this._mapPane = this.createPane('mapPane', this._container);
|
|
108
253
|
L.DomUtil.setPosition(this._mapPane, new L.Point(0, 0));
|
|
109
254
|
|
|
110
255
|
if (this._rotate) {
|
|
111
256
|
this._rotatePane = this.createPane('rotatePane', this._mapPane);
|
|
112
257
|
this._norotatePane = this.createPane('norotatePane', this._mapPane);
|
|
113
|
-
|
|
114
|
-
// @pane tilePane: HTMLElement = 2
|
|
115
|
-
// Pane for tile layers
|
|
258
|
+
// rotatePane
|
|
116
259
|
this.createPane('tilePane', this._rotatePane);
|
|
117
|
-
// @pane overlayPane: HTMLElement = 4
|
|
118
|
-
// Pane for overlays like polylines and polygons
|
|
119
260
|
this.createPane('overlayPane', this._rotatePane);
|
|
120
|
-
|
|
121
|
-
// @pane shadowPane: HTMLElement = 5
|
|
122
|
-
// Pane for overlay shadows (e.g. marker shadows)
|
|
261
|
+
// norotatePane
|
|
123
262
|
this.createPane('shadowPane', this._norotatePane);
|
|
124
|
-
// @pane markerPane: HTMLElement = 6
|
|
125
|
-
// Pane for marker icons
|
|
126
263
|
this.createPane('markerPane', this._norotatePane);
|
|
127
|
-
// @pane tooltipPane: HTMLElement = 650
|
|
128
|
-
// Pane for tooltips.
|
|
129
264
|
this.createPane('tooltipPane', this._norotatePane);
|
|
130
|
-
// @pane popupPane: HTMLElement = 700
|
|
131
|
-
// Pane for popups.
|
|
132
265
|
this.createPane('popupPane', this._norotatePane);
|
|
133
266
|
} else {
|
|
134
|
-
// @pane tilePane: HTMLElement = 2
|
|
135
|
-
// Pane for tile layers
|
|
136
267
|
this.createPane('tilePane');
|
|
137
|
-
// @pane overlayPane: HTMLElement = 4
|
|
138
|
-
// Pane for overlays like polylines and polygons
|
|
139
268
|
this.createPane('overlayPane');
|
|
140
|
-
// @pane shadowPane: HTMLElement = 5
|
|
141
|
-
// Pane for overlay shadows (e.g. marker shadows)
|
|
142
269
|
this.createPane('shadowPane');
|
|
143
|
-
// @pane markerPane: HTMLElement = 6
|
|
144
|
-
// Pane for marker icons
|
|
145
270
|
this.createPane('markerPane');
|
|
146
|
-
// @pane tooltipPane: HTMLElement = 650
|
|
147
|
-
// Pane for tooltips.
|
|
148
271
|
this.createPane('tooltipPane');
|
|
149
|
-
// @pane popupPane: HTMLElement = 700
|
|
150
|
-
// Pane for popups.
|
|
151
272
|
this.createPane('popupPane');
|
|
152
273
|
}
|
|
153
274
|
|
|
@@ -157,37 +278,205 @@ L.Map.include({
|
|
|
157
278
|
}
|
|
158
279
|
},
|
|
159
280
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
281
|
+
/**
|
|
282
|
+
* Pans the map the minimum amount to make the `latlng` visible. Use
|
|
283
|
+
* padding options to fit the display to more restricted bounds.
|
|
284
|
+
* If `latlng` is already within the (optionally padded) display bounds,
|
|
285
|
+
* the map will not be panned.
|
|
286
|
+
*
|
|
287
|
+
* @see https://github.com/Raruto/leaflet-rotate/issues/18
|
|
288
|
+
*
|
|
289
|
+
* @param {L.LatLng} latlng coordinates
|
|
290
|
+
* @param {Object} [options={}] padding options
|
|
291
|
+
*
|
|
292
|
+
* @returns {L.Map} current map instance
|
|
293
|
+
*/
|
|
294
|
+
panInside(latlng, options) {
|
|
295
|
+
options = options || {};
|
|
296
|
+
|
|
297
|
+
const paddingTL = L.point(options.paddingTopLeft || options.padding || [0, 0]),
|
|
298
|
+
paddingBR = L.point(options.paddingBottomRight || options.padding || [0, 0]),
|
|
299
|
+
/** @TODO use mapProto.panInside */
|
|
300
|
+
// pixelPoint = this.project(latlng),
|
|
301
|
+
// pixelBounds = this.getPixelBounds(),
|
|
302
|
+
// pixelCenter = this.project(this.getCenter()),
|
|
303
|
+
rect = this._container.getBoundingClientRect(),
|
|
304
|
+
pixelPoint = this.latLngToContainerPoint(latlng),
|
|
305
|
+
pixelBounds = L.bounds([ L.point(rect), L.point(rect).add(this.getSize()) ]),
|
|
306
|
+
pixelCenter = pixelBounds.getCenter(),
|
|
307
|
+
//
|
|
308
|
+
paddedBounds = L.bounds([pixelBounds.min.add(paddingTL), pixelBounds.max.subtract(paddingBR)]),
|
|
309
|
+
paddedSize = paddedBounds.getSize();
|
|
310
|
+
|
|
311
|
+
if (!paddedBounds.contains(pixelPoint)) {
|
|
312
|
+
this._enforcingBounds = true;
|
|
313
|
+
const centerOffset = pixelPoint.subtract(paddedBounds.getCenter());
|
|
314
|
+
const offset = paddedBounds.extend(pixelPoint).getSize().subtract(paddedSize);
|
|
315
|
+
pixelCenter.x += centerOffset.x < 0 ? -offset.x : offset.x;
|
|
316
|
+
pixelCenter.y += centerOffset.y < 0 ? -offset.y : offset.y;
|
|
317
|
+
/** @TODO use mapProto.panInside */
|
|
318
|
+
// this.panTo(this.unproject(pixelCenter), options);
|
|
319
|
+
this.panTo(this.containerPointToLatLng(pixelCenter), options);
|
|
320
|
+
//
|
|
321
|
+
this._enforcingBounds = false;
|
|
322
|
+
}
|
|
323
|
+
return this;
|
|
165
324
|
},
|
|
166
325
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
326
|
+
/**
|
|
327
|
+
* Pans the map to the closest view that would lie inside the given bounds
|
|
328
|
+
* (if it's not already), controlling the animation using the options specific,
|
|
329
|
+
* if any.
|
|
330
|
+
*
|
|
331
|
+
* @TODO check if map bounds calculated by `L.Map::panInsideBounds()`
|
|
332
|
+
* function should match the `rotatePane` or `norotatePane` bounds
|
|
333
|
+
*
|
|
334
|
+
* @see https://github.com/fnicollet/Leaflet/issues/7
|
|
335
|
+
*
|
|
336
|
+
* @param {L.LatLngBounds} bounds coordinates
|
|
337
|
+
* @param {Object} [options] pan options
|
|
338
|
+
* @returns {L.Map} current map instance
|
|
339
|
+
*/
|
|
340
|
+
// panInsideBounds: function (bounds, options) {
|
|
341
|
+
// this._enforcingBounds = true;
|
|
342
|
+
// var center = this.getCenter(),
|
|
343
|
+
// newCenter = this._limitCenter(center, this._zoom, L.latLngBounds(bounds));
|
|
344
|
+
//
|
|
345
|
+
// if (!center.equals(newCenter)) {
|
|
346
|
+
// this.panTo(newCenter, options);
|
|
347
|
+
// }
|
|
348
|
+
//
|
|
349
|
+
// this._enforcingBounds = false;
|
|
350
|
+
// return this;
|
|
351
|
+
// },
|
|
352
|
+
|
|
353
|
+
// adjust center for view to get inside bounds
|
|
354
|
+
// _limitCenter(center, zoom, bounds) {
|
|
355
|
+
//
|
|
356
|
+
// if (!bounds) { return center; }
|
|
357
|
+
//
|
|
358
|
+
// const centerPoint = this.project(center, zoom),
|
|
359
|
+
// viewHalf = this.getSize().divideBy(2),
|
|
360
|
+
// viewBounds = new Bounds(centerPoint.subtract(viewHalf), centerPoint.add(viewHalf)),
|
|
361
|
+
// offset = this._getBoundsOffset(viewBounds, bounds, zoom);
|
|
362
|
+
//
|
|
363
|
+
// // If offset is less than a pixel, ignore.
|
|
364
|
+
// // This prevents unstable projections from getting into
|
|
365
|
+
// // an infinite loop of tiny offsets.
|
|
366
|
+
// if (Math.abs(offset.x) <= 1 && Math.abs(offset.y) <= 1) {
|
|
367
|
+
// return center;
|
|
368
|
+
// }
|
|
369
|
+
//
|
|
370
|
+
// return this.unproject(centerPoint.add(offset), zoom);
|
|
371
|
+
// },
|
|
372
|
+
|
|
373
|
+
// @method flyToBounds(bounds: LatLngBounds, options?: fitBounds options): this
|
|
374
|
+
// Sets the view of the map with a smooth animation like [`flyTo`](#map-flyto),
|
|
375
|
+
// but takes a bounds parameter like [`fitBounds`](#map-fitbounds).
|
|
376
|
+
// flyToBounds(bounds, options) {
|
|
377
|
+
// const target = this._getBoundsCenterZoom(bounds, options);
|
|
378
|
+
// return this.flyTo(target.center, target.zoom, options);
|
|
379
|
+
// },
|
|
380
|
+
|
|
381
|
+
// _getBoundsCenterZoom(bounds, options) {
|
|
382
|
+
//
|
|
383
|
+
// options = options || {};
|
|
384
|
+
// bounds = bounds.getBounds ? bounds.getBounds() : toLatLngBounds(bounds);
|
|
385
|
+
//
|
|
386
|
+
// const paddingTL = L.point(options.paddingTopLeft || options.padding || [0, 0]),
|
|
387
|
+
// paddingBR = L.point(options.paddingBottomRight || options.padding || [0, 0]);
|
|
388
|
+
//
|
|
389
|
+
// let zoom = this.getBoundsZoom(bounds, false, paddingTL.add(paddingBR));
|
|
390
|
+
//
|
|
391
|
+
// zoom = (typeof options.maxZoom === 'number') ? Math.min(options.maxZoom, zoom) : zoom;
|
|
392
|
+
//
|
|
393
|
+
// if (zoom === Infinity) {
|
|
394
|
+
// return { center: bounds.getCenter(), zoom };
|
|
395
|
+
// }
|
|
396
|
+
//
|
|
397
|
+
// return { center, zoom };
|
|
398
|
+
//
|
|
399
|
+
// },
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Returns the maximum zoom level on which the given bounds fit to the map
|
|
403
|
+
* view in its entirety. If `inside` (optional) is set to `true`, the method
|
|
404
|
+
* instead returns the minimum zoom level on which the map view fits into
|
|
405
|
+
* the given bounds in its entirety.
|
|
406
|
+
*
|
|
407
|
+
* @param {L.LatLngBounds} bounds
|
|
408
|
+
* @param {Boolean} [inside=false]
|
|
409
|
+
* @param {L.Point} [padding=[0,0]]
|
|
410
|
+
*
|
|
411
|
+
* @returns {Number} zoom level
|
|
412
|
+
*/
|
|
413
|
+
getBoundsZoom(bounds, inside, padding) {
|
|
414
|
+
if (!this._rotate || Math.abs(this._bearing).toFixed(1) < 0.1) {
|
|
415
|
+
return mapProto.getBoundsZoom.apply(this, arguments);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
bounds = L.latLngBounds(bounds);
|
|
419
|
+
padding = L.point(padding || [0, 0]);
|
|
420
|
+
|
|
421
|
+
let zoom = this.getZoom() || 0;
|
|
422
|
+
const min = this.getMinZoom(),
|
|
423
|
+
max = this.getMaxZoom(),
|
|
424
|
+
/** @TODO use mapProto.getBoundsZoom */
|
|
425
|
+
// nw = bounds.getNorthWest(),
|
|
426
|
+
// se = bounds.getSouthEast(),
|
|
427
|
+
// size = this.getSize().subtract(padding),
|
|
428
|
+
// boundsSize = L.bounds(this.project(se, zoom), this.project(nw, zoom)).getSize(),
|
|
429
|
+
size = this.getSize().subtract(padding),
|
|
430
|
+
boundsSize = this.mapBoundsToContainerBounds(bounds).getSize(),
|
|
431
|
+
snap = this.options.zoomSnap,
|
|
432
|
+
scalex = size.x / boundsSize.x,
|
|
433
|
+
scaley = size.y / boundsSize.y,
|
|
434
|
+
scale = inside ? Math.max(scalex, scaley) : Math.min(scalex, scaley);
|
|
435
|
+
|
|
436
|
+
zoom = this.getScaleZoom(scale, zoom);
|
|
437
|
+
|
|
438
|
+
if (snap) {
|
|
439
|
+
zoom = Math.round(zoom / (snap / 100)) * (snap / 100); // don't jump if within 1% of a snap level
|
|
440
|
+
zoom = inside ? Math.ceil(zoom / snap) * snap : Math.floor(zoom / snap) * snap;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
return Math.max(min, Math.min(max, zoom));
|
|
172
444
|
},
|
|
173
445
|
|
|
174
|
-
|
|
446
|
+
/**
|
|
447
|
+
* Layer point of the current center
|
|
448
|
+
*
|
|
449
|
+
* @returns {L.Point} layer center
|
|
450
|
+
*/
|
|
451
|
+
// _getCenterLayerPoint: function () {
|
|
452
|
+
// return this.containerPointToLayerPoint(this.getSize()._divideBy(2));
|
|
453
|
+
// },
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Offset of the specified place to the current center in pixels
|
|
457
|
+
*
|
|
458
|
+
* @param {L.LatLng} latlng map coordinates
|
|
459
|
+
*/
|
|
175
460
|
_getCenterOffset: function(latlng) {
|
|
176
|
-
var centerOffset = mapProto._getCenterOffset.
|
|
461
|
+
var centerOffset = mapProto._getCenterOffset.apply(this, arguments);
|
|
177
462
|
if (this._rotate) {
|
|
178
463
|
centerOffset = centerOffset.rotate(this._bearing);
|
|
179
464
|
}
|
|
180
465
|
return centerOffset;
|
|
181
466
|
},
|
|
182
467
|
|
|
468
|
+
/**
|
|
469
|
+
* @since leaflet-rotate (v0.1)
|
|
470
|
+
*/
|
|
183
471
|
_getRotatePanePos: function() {
|
|
184
472
|
return this._rotatePanePos || new L.Point(0, 0);
|
|
473
|
+
// return L.DomUtil.getPosition(this._rotatePane) || new L.Point(0, 0);
|
|
185
474
|
},
|
|
186
475
|
|
|
187
476
|
_getNewPixelOrigin: function(center, zoom) {
|
|
188
477
|
var viewHalf = this.getSize()._divideBy(2);
|
|
189
478
|
if (!this._rotate) {
|
|
190
|
-
mapProto._getNewPixelOrigin.
|
|
479
|
+
return mapProto._getNewPixelOrigin.apply(this, arguments);
|
|
191
480
|
}
|
|
192
481
|
return this.project(center, zoom)
|
|
193
482
|
.rotate(this._bearing)
|
|
@@ -198,10 +487,72 @@ L.Map.include({
|
|
|
198
487
|
._round();
|
|
199
488
|
},
|
|
200
489
|
|
|
490
|
+
/**
|
|
491
|
+
* @since leaflet-rotate (v0.2)
|
|
492
|
+
*
|
|
493
|
+
* @see src\layer\tile\GridLayer::_getTiledPixelBounds()
|
|
494
|
+
*/
|
|
495
|
+
_getNewPixelBounds: function(center, zoom) {
|
|
496
|
+
center = center || this.getCenter();
|
|
497
|
+
zoom = zoom || this.getZoom();
|
|
498
|
+
if (!this._rotate && mapProto._getNewPixelBounds) {
|
|
499
|
+
return mapProto._getNewPixelBounds.apply(this, arguments);
|
|
500
|
+
}
|
|
501
|
+
var mapZoom = this._animatingZoom ? Math.max(this._animateToZoom, this.getZoom()) : this.getZoom(),
|
|
502
|
+
scale = this.getZoomScale(mapZoom, zoom),
|
|
503
|
+
pixelCenter = this.project(center, zoom).floor(),
|
|
504
|
+
size = this.getSize(),
|
|
505
|
+
halfSize = new L.Bounds([
|
|
506
|
+
this.containerPointToLayerPoint([0, 0]).floor(),
|
|
507
|
+
this.containerPointToLayerPoint([size.x, 0]).floor(),
|
|
508
|
+
this.containerPointToLayerPoint([0, size.y]).floor(),
|
|
509
|
+
this.containerPointToLayerPoint([size.x, size.y]).floor()
|
|
510
|
+
]).getSize().divideBy(scale * 2);
|
|
511
|
+
|
|
512
|
+
return new L.Bounds(pixelCenter.subtract(halfSize), pixelCenter.add(halfSize));
|
|
513
|
+
},
|
|
514
|
+
|
|
515
|
+
/**
|
|
516
|
+
* @since leaflet-rotate (v0.2)
|
|
517
|
+
*
|
|
518
|
+
* @return {L.Point} map pivot point (center)
|
|
519
|
+
*/
|
|
520
|
+
_getPixelCenter: function() {
|
|
521
|
+
if (!this._rotate && mapProto._getPixelCenter) {
|
|
522
|
+
return mapProto._getPixelCenter.apply(this, arguments);
|
|
523
|
+
}
|
|
524
|
+
return this.getSize()._divideBy(2)._subtract(this._getMapPanePos());
|
|
525
|
+
},
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* @since leaflet-rotate (v0.2)
|
|
529
|
+
*
|
|
530
|
+
* @see src\layer\vector\Renderer::_update()
|
|
531
|
+
*/
|
|
532
|
+
_getPaddedPixelBounds: function(padding) {
|
|
533
|
+
if (!this._rotate && mapProto._getPaddedPixelBounds) {
|
|
534
|
+
return mapProto._getPaddedPixelBounds.apply(this, arguments);
|
|
535
|
+
}
|
|
536
|
+
var p = padding,
|
|
537
|
+
size = this.getSize(),
|
|
538
|
+
padMin = size.multiplyBy(-p),
|
|
539
|
+
padMax = size.multiplyBy(1 + p);
|
|
540
|
+
//min = this.containerPointToLayerPoint(size.multiplyBy(-p)).round();
|
|
541
|
+
|
|
542
|
+
return new L.Bounds([
|
|
543
|
+
this.containerPointToLayerPoint([padMin.x, padMin.y]).floor(),
|
|
544
|
+
this.containerPointToLayerPoint([padMin.x, padMax.y]).floor(),
|
|
545
|
+
this.containerPointToLayerPoint([padMax.x, padMin.y]).floor(),
|
|
546
|
+
this.containerPointToLayerPoint([padMax.x, padMax.y]).floor()
|
|
547
|
+
]);
|
|
548
|
+
},
|
|
549
|
+
|
|
201
550
|
_handleGeolocationResponse: function(pos) {
|
|
551
|
+
if (!this._container._leaflet_id) { return; }
|
|
552
|
+
|
|
202
553
|
var lat = pos.coords.latitude,
|
|
203
554
|
lng = pos.coords.longitude,
|
|
204
|
-
|
|
555
|
+
/** @TODO use mapProto._handleGeolocationResponse */
|
|
205
556
|
hdg = pos.coords.heading,
|
|
206
557
|
latlng = new L.LatLng(lat, lng),
|
|
207
558
|
bounds = latlng.toBounds(pos.coords.accuracy),
|
|
@@ -216,7 +567,7 @@ L.Map.include({
|
|
|
216
567
|
latlng: latlng,
|
|
217
568
|
bounds: bounds,
|
|
218
569
|
timestamp: pos.timestamp,
|
|
219
|
-
|
|
570
|
+
/** @TODO use mapProto._handleGeolocationResponse */
|
|
220
571
|
heading: hdg
|
|
221
572
|
};
|
|
222
573
|
|
|
@@ -232,4 +583,19 @@ L.Map.include({
|
|
|
232
583
|
this.fire('locationfound', data);
|
|
233
584
|
},
|
|
234
585
|
|
|
586
|
+
/**
|
|
587
|
+
* @see https://github.com/ronikar/Leaflet/blob/5c480ef959b947c3beed7065425a5a36c486262b/src/geo/LatLngBounds.js#L253-L264
|
|
588
|
+
*
|
|
589
|
+
* @param {L.Bounds} points
|
|
590
|
+
* @returns {L.Bounds}
|
|
591
|
+
*/
|
|
592
|
+
// toCircumscribedBounds(points) {
|
|
593
|
+
// var minX = points.reduce(function (pv, v) { return Math.min(pv, v.x); }, points[0].x),
|
|
594
|
+
// maxX = points.reduce(function (pv, v) { return Math.max(pv, v.x); }, points[0].x),
|
|
595
|
+
// minY = points.reduce(function (pv, v) { return Math.min(pv, v.y); }, points[0].y),
|
|
596
|
+
// maxY = points.reduce(function (pv, v) { return Math.max(pv, v.y); }, points[0].y);
|
|
597
|
+
//
|
|
598
|
+
// return L.bounds(L.point(minX, minY), L.point(maxX, maxY));
|
|
599
|
+
// },
|
|
600
|
+
|
|
235
601
|
});
|