leaflet-rotate 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +74 -5
- package/build/test.js +18 -0
- package/dist/leaflet-rotate-src.js +1081 -303
- package/dist/leaflet-rotate-src.js.map +3 -3
- package/dist/leaflet-rotate.js +1 -1
- package/dist/leaflet-rotate.js.map +3 -3
- package/lib/debug.js +84 -66
- package/lib/debug.min.js +1 -1
- package/misc/leaflet-heat-rotate.js +14 -7
- package/misc/loremIpsum.js +1 -1
- package/misc/places.js +1 -1
- package/misc/route.js +1 -1
- package/package.json +5 -5
- package/src/control/Rotate.js +98 -29
- package/src/dom/DomUtil.js +42 -47
- package/src/dom/Draggable.js +6 -1
- package/src/geo/LatLngBounds.js +5 -0
- package/src/geometry/Bounds.js +5 -0
- package/src/geometry/Point.js +33 -10
- package/src/index.js +3 -1
- package/src/layer/DivOverlay.js +43 -12
- package/src/layer/Popup.js +29 -16
- package/src/layer/Tooltip.js +21 -5
- package/src/layer/marker/Icon.js +20 -8
- package/src/layer/marker/Marker.js +103 -24
- package/src/layer/tile/GridLayer.js +22 -6
- package/src/layer/vector/Renderer.js +102 -11
- package/src/map/Map.js +408 -121
- package/src/map/handler/CompassBearing.js +33 -7
- package/src/map/handler/ContainerMutation.js +20 -3
- package/src/map/handler/ShiftKeyRotate.js +156 -16
- package/src/map/handler/TouchGestures.js +91 -29
- package/src/map/handler/TouchRotate.js +20 -3
- package/src/map/handler/TouchZoom.js +25 -5
- package/test/features/example.feature +5 -0
- package/test/features/rotation.feature +30 -0
- package/test/index.html +60 -22
- package/test/steps/bearing.steps.js +345 -3
- package/test/steps/example.steps.js +72 -11
- package/test/steps/gestures.steps.js +4 -4
- package/test/steps/overlays.steps.js +32 -32
- package/test/support/hooks.js +38 -2
|
@@ -60,7 +60,7 @@ When('I drag a constrained marker on a rotated map', async function () {
|
|
|
60
60
|
map.setView([23.1799, 113.4103], 15, { animate: false });
|
|
61
61
|
map.setBearing(30);
|
|
62
62
|
map.setZoom(16, { animate: false });
|
|
63
|
-
window.dragMarker = L.
|
|
63
|
+
window.dragMarker = new L.Marker([23.1799, 113.4103], { draggable: true }).addTo(map);
|
|
64
64
|
window.dragMarkerStart = window.dragMarker.getLatLng();
|
|
65
65
|
window.dragCallbackLatLngs = [];
|
|
66
66
|
window.dragMarker.on('drag dragend', event => {
|
|
@@ -100,8 +100,8 @@ When('I drag a map with interactive layers while rotated', async function () {
|
|
|
100
100
|
await this.page.evaluate(() => {
|
|
101
101
|
map.options.zoomAnimation = false;
|
|
102
102
|
map.setView([55, 10], 6, { animate: false });
|
|
103
|
-
const marker = L.
|
|
104
|
-
const path = L.
|
|
103
|
+
const marker = new L.Marker([55.1, 10.1]).addTo(map);
|
|
104
|
+
const path = new L.CircleMarker([55.2, 10.2], { radius: 8 }).addTo(map);
|
|
105
105
|
map.setBearing(35);
|
|
106
106
|
window.interactiveLayers = { marker, path };
|
|
107
107
|
});
|
|
@@ -134,7 +134,7 @@ When('I drag a map with interactive layers while rotated', async function () {
|
|
|
134
134
|
pathScreen.y - mapRect.top - pathExpected.y,
|
|
135
135
|
];
|
|
136
136
|
};
|
|
137
|
-
const moved = !map.getCenter().equals(L.
|
|
137
|
+
const moved = !map.getCenter().equals(new L.LatLng(55, 10));
|
|
138
138
|
const positions = [measure()];
|
|
139
139
|
map.setBearing(0);
|
|
140
140
|
positions.push(measure());
|
|
@@ -65,27 +65,27 @@ When('I rotate a label marker with the view', async function () {
|
|
|
65
65
|
this.labelAngles = await this.page.evaluate(() => {
|
|
66
66
|
map.setView([55, 10], 6, { animate: false });
|
|
67
67
|
map.setBearing(0);
|
|
68
|
-
const label = L.
|
|
69
|
-
icon: L.
|
|
70
|
-
rotation: 135 *
|
|
68
|
+
const label = new L.Marker([55, 10], {
|
|
69
|
+
icon: new L.DivIcon({ className: 'road-label', html: 'Road name' }),
|
|
70
|
+
rotation: 135 * (Math.PI / 180),
|
|
71
71
|
rotateWithView: true,
|
|
72
72
|
keepUpright: true,
|
|
73
73
|
}).addTo(map);
|
|
74
74
|
const center = map.latLngToContainerPoint(label.getLatLng());
|
|
75
|
-
const direction = 135 *
|
|
76
|
-
const road = L.
|
|
75
|
+
const direction = 135 * (Math.PI / 180);
|
|
76
|
+
const road = new L.Polyline([
|
|
77
77
|
map.containerPointToLatLng(center.subtract([20 * Math.cos(direction), 20 * Math.sin(direction)])),
|
|
78
78
|
map.containerPointToLatLng(center.add([20 * Math.cos(direction), 20 * Math.sin(direction)])),
|
|
79
79
|
]).addTo(map);
|
|
80
80
|
return [0, 45, 90, 180, 270].map(bearing => {
|
|
81
81
|
map.setBearing(bearing);
|
|
82
82
|
const transform = new DOMMatrix(getComputedStyle(label.getElement()).transform);
|
|
83
|
-
const labelAngle = (Math.atan2(transform.b, transform.a) *
|
|
83
|
+
const labelAngle = (Math.atan2(transform.b, transform.a) * (180 / Math.PI) + 360) % 360;
|
|
84
84
|
const endpoints = road.getLatLngs().map(latlng => map.latLngToContainerPoint(latlng));
|
|
85
85
|
const roadAngle = (Math.atan2(
|
|
86
86
|
endpoints[1].y - endpoints[0].y,
|
|
87
87
|
endpoints[1].x - endpoints[0].x,
|
|
88
|
-
) *
|
|
88
|
+
) * (180 / Math.PI) + 360) % 360;
|
|
89
89
|
return { labelAngle, roadAngle };
|
|
90
90
|
});
|
|
91
91
|
});
|
|
@@ -96,13 +96,13 @@ When('I add GeoJSON to a custom pane inside the rotate pane', async function ()
|
|
|
96
96
|
map.setView([55, 10], 6, { animate: false });
|
|
97
97
|
map.setBearing(35);
|
|
98
98
|
const pane = map.createPane('customGeoJsonPane', map.getPane('rotatePane'));
|
|
99
|
-
const geoJson = L.
|
|
99
|
+
const geoJson = new L.GeoJSON({
|
|
100
100
|
type: 'Feature',
|
|
101
101
|
geometry: { type: 'Point', coordinates: [10, 55] },
|
|
102
102
|
properties: {},
|
|
103
103
|
}, {
|
|
104
104
|
pane: 'customGeoJsonPane',
|
|
105
|
-
pointToLayer: (feature, latlng) => L.
|
|
105
|
+
pointToLayer: (feature, latlng) => new L.CircleMarker(latlng, { radius: 8 }),
|
|
106
106
|
}).addTo(map);
|
|
107
107
|
const element = geoJson.getLayers()[0].getElement();
|
|
108
108
|
const bounds = element.getBBox();
|
|
@@ -120,8 +120,8 @@ When('I add GeoJSON to a custom pane inside the rotate pane', async function ()
|
|
|
120
120
|
When('I render a Canvas vector layer on a rotated map', async function () {
|
|
121
121
|
this.canvasPane = await this.page.evaluate(() => {
|
|
122
122
|
map.setBearing(35);
|
|
123
|
-
const renderer = L.
|
|
124
|
-
L.
|
|
123
|
+
const renderer = new L.Canvas({ pane: 'overlayPane' });
|
|
124
|
+
new L.CircleMarker([55, 10], { renderer, radius: 8 }).addTo(map);
|
|
125
125
|
return {
|
|
126
126
|
rotating: renderer._container.parentNode === map.getPane('overlayPane')
|
|
127
127
|
&& map.getPane('overlayPane').parentNode === map.getPane('rotatePane'),
|
|
@@ -132,7 +132,7 @@ When('I render a Canvas vector layer on a rotated map', async function () {
|
|
|
132
132
|
|
|
133
133
|
When('I remove the rotate control and change the map bearing', async function () {
|
|
134
134
|
this.removedControl = await this.page.evaluate(() => {
|
|
135
|
-
const control = L.
|
|
135
|
+
const control = new L.Control.Rotate({ closeOnZeroBearing: false }).addTo(map);
|
|
136
136
|
map.removeControl(control);
|
|
137
137
|
map.setBearing(40);
|
|
138
138
|
return { bearing: map.getBearing(), attached: Boolean(control._map) };
|
|
@@ -141,8 +141,8 @@ When('I remove the rotate control and change the map bearing', async function ()
|
|
|
141
141
|
|
|
142
142
|
When('I create default and draggable markers', async function () {
|
|
143
143
|
this.markerDragStates = await this.page.evaluate(() => {
|
|
144
|
-
const defaultMarker = L.
|
|
145
|
-
const draggableMarker = L.
|
|
144
|
+
const defaultMarker = new L.Marker([55, 10]).addTo(map);
|
|
145
|
+
const draggableMarker = new L.Marker([55.1, 10.1], { draggable: true }).addTo(map);
|
|
146
146
|
return [defaultMarker, draggableMarker].map(marker => marker.dragging.enabled());
|
|
147
147
|
});
|
|
148
148
|
});
|
|
@@ -171,7 +171,7 @@ When('I focus a marker near the edge of a rotated map', async function () {
|
|
|
171
171
|
map.setView([55, 10], 6, { animate: false });
|
|
172
172
|
map.setBearing(30);
|
|
173
173
|
const point = map.containerPointToLatLng([35, map.getSize().y / 2]);
|
|
174
|
-
const marker = L.
|
|
174
|
+
const marker = new L.Marker(point, { autoPanOnFocus: true }).addTo(map);
|
|
175
175
|
const before = map.getCenter();
|
|
176
176
|
marker.getElement().focus();
|
|
177
177
|
return before.equals(map.getCenter());
|
|
@@ -183,10 +183,10 @@ When('I redraw a heat layer after rotating, panning, and zooming', async functio
|
|
|
183
183
|
map.setView([55, 10], 6, { animate: false });
|
|
184
184
|
map.setBearing(35);
|
|
185
185
|
L.HeatLayer = L.Layer.extend({
|
|
186
|
-
initialize
|
|
186
|
+
initialize(latlngs) {
|
|
187
187
|
this._latlngs = latlngs;
|
|
188
188
|
},
|
|
189
|
-
onAdd
|
|
189
|
+
onAdd(map) {
|
|
190
190
|
this._map = map;
|
|
191
191
|
const size = map.getSize();
|
|
192
192
|
this._heat = { _width: size.x, _height: size.y };
|
|
@@ -198,41 +198,41 @@ When('I redraw a heat layer after rotating, panning, and zooming', async functio
|
|
|
198
198
|
map.on('moveend', this._reset, this);
|
|
199
199
|
this._reset();
|
|
200
200
|
},
|
|
201
|
-
onRemove
|
|
201
|
+
onRemove(map) {
|
|
202
202
|
map.off('moveend', this._reset, this);
|
|
203
203
|
L.DomUtil.remove(this._canvas);
|
|
204
204
|
},
|
|
205
|
-
_redraw
|
|
205
|
+
_redraw() {
|
|
206
206
|
this._drawnPoints = this._latlngs.map(latlng => this._map.latLngToContainerPoint(latlng));
|
|
207
207
|
},
|
|
208
208
|
});
|
|
209
209
|
L.heatLayer = latlngs => new L.HeatLayer(latlngs);
|
|
210
210
|
globalThis.HeatmapOverlay = L.Layer.extend({
|
|
211
|
-
initialize
|
|
211
|
+
initialize(latlngs) {
|
|
212
212
|
this._latlngs = latlngs;
|
|
213
213
|
this._el = L.DomUtil.create('div', 'leaflet-heatmap-overlay');
|
|
214
214
|
},
|
|
215
|
-
onAdd
|
|
215
|
+
onAdd(map) {
|
|
216
216
|
this._map = map;
|
|
217
217
|
map.getPane('overlayPane').appendChild(this._el);
|
|
218
218
|
map.on('moveend', this._draw, this);
|
|
219
219
|
this._draw();
|
|
220
220
|
},
|
|
221
|
-
onRemove
|
|
221
|
+
onRemove(map) {
|
|
222
222
|
map.off('moveend', this._draw, this);
|
|
223
223
|
L.DomUtil.remove(this._el);
|
|
224
224
|
},
|
|
225
|
-
_draw
|
|
225
|
+
_draw() {
|
|
226
226
|
this._update();
|
|
227
227
|
},
|
|
228
|
-
_update
|
|
228
|
+
_update() {
|
|
229
229
|
this._drawnPoints = this._latlngs.map(latlng => this._map.latLngToContainerPoint(latlng));
|
|
230
230
|
},
|
|
231
231
|
});
|
|
232
232
|
});
|
|
233
233
|
await this.page.addScriptTag({ url: `${this.baseUrl}/misc/leaflet-heat-rotate.js` });
|
|
234
234
|
this.heatPointDeltas = await this.page.evaluate(async () => {
|
|
235
|
-
const locations = [L.
|
|
235
|
+
const locations = [new L.LatLng(55.1, 10.1), new L.LatLng(54.9, 9.8), new L.LatLng(55.25, 10.3)];
|
|
236
236
|
const layer = L.heatLayer(locations).addTo(map);
|
|
237
237
|
const overlay = new HeatmapOverlay(locations).addTo(map);
|
|
238
238
|
const deltas = [];
|
|
@@ -292,8 +292,8 @@ When('I zoom an SVG path near the latitude limit', async function () {
|
|
|
292
292
|
map.options.zoomAnimation = false;
|
|
293
293
|
map.setView([85, 0], 5, { animate: false });
|
|
294
294
|
map.setBearing(30);
|
|
295
|
-
const location = L.
|
|
296
|
-
const path = L.
|
|
295
|
+
const location = new L.LatLng(85, 0);
|
|
296
|
+
const path = new L.CircleMarker(location, { radius: 6 }).addTo(map);
|
|
297
297
|
const pathPoint = () => {
|
|
298
298
|
const element = path.getElement();
|
|
299
299
|
const bounds = element.getBBox();
|
|
@@ -316,7 +316,7 @@ When('I open a popup on a rotated map without zoom animation', async function ()
|
|
|
316
316
|
map.options.zoomAnimation = false;
|
|
317
317
|
map.setView([55, 10], 6, { animate: false });
|
|
318
318
|
map.setBearing(30);
|
|
319
|
-
const marker = L.
|
|
319
|
+
const marker = new L.Marker([55, 10]).addTo(map).bindPopup('popup');
|
|
320
320
|
marker.getElement().click();
|
|
321
321
|
const popup = marker.getPopup();
|
|
322
322
|
const tip = popup.getElement().querySelector('.leaflet-popup-tip-container');
|
|
@@ -347,7 +347,7 @@ When('I open a popup near the edge of a rotated map', async function () {
|
|
|
347
347
|
map.setBearing(30);
|
|
348
348
|
map.on('move zoomend dragend locationfound locationerror', () => {});
|
|
349
349
|
const edge = map.containerPointToLatLng([map.getSize().x - 10, map.getSize().y / 2]);
|
|
350
|
-
const marker = L.
|
|
350
|
+
const marker = new L.Marker(edge).addTo(map).bindPopup('edge popup');
|
|
351
351
|
const oldCenter = map.project(map.getCenter(), map.getZoom());
|
|
352
352
|
marker.openPopup();
|
|
353
353
|
await new Promise(resolve => {
|
|
@@ -380,10 +380,10 @@ When('I open a popup in a second rotated map with map listeners', async function
|
|
|
380
380
|
element.id = 'secondary-map';
|
|
381
381
|
element.style.cssText = 'height: 300px; width: 500px; margin-top: 40px';
|
|
382
382
|
document.body.append(element);
|
|
383
|
-
const secondMap = window.secondaryMap = L.
|
|
383
|
+
const secondMap = window.secondaryMap = new L.Map(element, {
|
|
384
384
|
center: [55, 10], zoom: 6, rotate: true, bearing: 30,
|
|
385
385
|
});
|
|
386
|
-
const marker = L.
|
|
386
|
+
const marker = new L.Marker([55.5, 10.5]).addTo(secondMap)
|
|
387
387
|
.bindPopup('popup')
|
|
388
388
|
.bindTooltip('tooltip', { permanent: true, direction: 'right' });
|
|
389
389
|
marker.openTooltip();
|
|
@@ -400,7 +400,7 @@ When('I open a popup in a second rotated map with map listeners', async function
|
|
|
400
400
|
.add(popup._getAnchor()).add(popup.options.offset);
|
|
401
401
|
const tooltip = marker.getTooltip();
|
|
402
402
|
const tooltipRect = tooltip.getElement().getBoundingClientRect();
|
|
403
|
-
const tooltipOffset =
|
|
403
|
+
const tooltipOffset = tooltip.options.offset || new L.Point(0, 0);
|
|
404
404
|
const tooltipPoint = secondMap.latLngToContainerPoint(marker.getLatLng()).add(tooltip._getAnchor()).add(tooltipOffset);
|
|
405
405
|
const tooltipExpected = [
|
|
406
406
|
tooltipPoint.x + parseFloat(getComputedStyle(tooltip.getElement()).marginLeft),
|
package/test/support/hooks.js
CHANGED
|
@@ -26,9 +26,19 @@ Before(async function () {
|
|
|
26
26
|
this.context = await browser.newContext();
|
|
27
27
|
await this.context.route(/.html$/, async route => {
|
|
28
28
|
const response = await route.fetch();
|
|
29
|
-
const
|
|
29
|
+
const version = process.env.LEAFLET_VERSION;
|
|
30
|
+
let body = (await response.text())
|
|
30
31
|
.replace(/https:\/\/unpkg\.com\/leaflet-rotate@(.*?)\//g, '../')
|
|
31
|
-
.replace(/leaflet-rotate@(.*?)\//g, '../')
|
|
32
|
+
.replace(/leaflet-rotate@(.*?)\//g, '../')
|
|
33
|
+
.replace(/\bconst (map|esri|osm|layers|markers|path|circle|polygon|rectangle) =/g, 'const $1 = window.$1 =');
|
|
34
|
+
if (version === '2') {
|
|
35
|
+
body = body
|
|
36
|
+
.replace(
|
|
37
|
+
'<script src="https://unpkg.com/leaflet@1.9/dist/leaflet-src.js"></script>',
|
|
38
|
+
'<script src="https://unpkg.com/leaflet@2.0.0-alpha.1/dist/leaflet-global-src.js"></script><script>globalThis.L = globalThis.leaflet;</script>'
|
|
39
|
+
)
|
|
40
|
+
.replace('https://unpkg.com/leaflet@1.9/dist/leaflet.css', 'https://unpkg.com/leaflet@2.0.0-alpha.1/dist/leaflet.css');
|
|
41
|
+
}
|
|
32
42
|
await route.fulfill({ response, body, headers: response.headers() });
|
|
33
43
|
});
|
|
34
44
|
this.page = await this.context.newPage();
|
|
@@ -39,6 +49,32 @@ After(async function () {
|
|
|
39
49
|
});
|
|
40
50
|
|
|
41
51
|
Given('the example page is open', async function () {
|
|
52
|
+
const version = process.env.LEAFLET_VERSION;
|
|
42
53
|
await this.page.goto(`${baseUrl}/examples/leaflet-rotate.html`);
|
|
43
54
|
await this.page.waitForLoadState('domcontentloaded');
|
|
55
|
+
await this.page.waitForFunction(() => window.map && window.path && typeof window.map.getBearing === 'function');
|
|
56
|
+
|
|
57
|
+
const result = await this.page.evaluate(() => {
|
|
58
|
+
const domUtilTest = document.createElement('div');
|
|
59
|
+
L.DomUtil.setPosition(domUtilTest, new L.Point(10, 20), Math.PI / 2, new L.Point(10, 20));
|
|
60
|
+
const testMarker = new L.Marker([55, 10], { rotation: Math.PI / 4 }).addTo(map);
|
|
61
|
+
const compatibility = {
|
|
62
|
+
bearing: map.getBearing(),
|
|
63
|
+
rotatePane: map._rotatePane instanceof HTMLElement,
|
|
64
|
+
markerOnMap: testMarker._map === map,
|
|
65
|
+
pathOnMap: path._map === map,
|
|
66
|
+
markerTransform: testMarker.getElement().style.transform,
|
|
67
|
+
domUtilTransform: domUtilTest.style.transform,
|
|
68
|
+
pluginVersion: L.version,
|
|
69
|
+
};
|
|
70
|
+
testMarker.remove();
|
|
71
|
+
return compatibility;
|
|
72
|
+
});
|
|
73
|
+
assert.ok(Math.abs(result.bearing - 30) < 1e-9, JSON.stringify(result));
|
|
74
|
+
assert.equal(result.rotatePane, true);
|
|
75
|
+
assert.equal(result.markerOnMap, true);
|
|
76
|
+
assert.equal(result.pathOnMap, true);
|
|
77
|
+
assert.match(result.markerTransform, /rotate\(0\.785/);
|
|
78
|
+
assert.match(result.domUtilTransform, /rotate\(1\.570/);
|
|
79
|
+
assert.match(result.pluginVersion, version === '2' ? /^2\.0\.0-alpha/ : /^1\.9/);
|
|
44
80
|
});
|