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.
Files changed (42) hide show
  1. package/README.md +74 -5
  2. package/build/test.js +18 -0
  3. package/dist/leaflet-rotate-src.js +1081 -303
  4. package/dist/leaflet-rotate-src.js.map +3 -3
  5. package/dist/leaflet-rotate.js +1 -1
  6. package/dist/leaflet-rotate.js.map +3 -3
  7. package/lib/debug.js +84 -66
  8. package/lib/debug.min.js +1 -1
  9. package/misc/leaflet-heat-rotate.js +14 -7
  10. package/misc/loremIpsum.js +1 -1
  11. package/misc/places.js +1 -1
  12. package/misc/route.js +1 -1
  13. package/package.json +5 -5
  14. package/src/control/Rotate.js +98 -29
  15. package/src/dom/DomUtil.js +42 -47
  16. package/src/dom/Draggable.js +6 -1
  17. package/src/geo/LatLngBounds.js +5 -0
  18. package/src/geometry/Bounds.js +5 -0
  19. package/src/geometry/Point.js +33 -10
  20. package/src/index.js +3 -1
  21. package/src/layer/DivOverlay.js +43 -12
  22. package/src/layer/Popup.js +29 -16
  23. package/src/layer/Tooltip.js +21 -5
  24. package/src/layer/marker/Icon.js +20 -8
  25. package/src/layer/marker/Marker.js +103 -24
  26. package/src/layer/tile/GridLayer.js +22 -6
  27. package/src/layer/vector/Renderer.js +102 -11
  28. package/src/map/Map.js +408 -121
  29. package/src/map/handler/CompassBearing.js +33 -7
  30. package/src/map/handler/ContainerMutation.js +20 -3
  31. package/src/map/handler/ShiftKeyRotate.js +156 -16
  32. package/src/map/handler/TouchGestures.js +91 -29
  33. package/src/map/handler/TouchRotate.js +20 -3
  34. package/src/map/handler/TouchZoom.js +25 -5
  35. package/test/features/example.feature +5 -0
  36. package/test/features/rotation.feature +30 -0
  37. package/test/index.html +60 -22
  38. package/test/steps/bearing.steps.js +345 -3
  39. package/test/steps/example.steps.js +72 -11
  40. package/test/steps/gestures.steps.js +4 -4
  41. package/test/steps/overlays.steps.js +32 -32
  42. 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.marker([23.1799, 113.4103], { draggable: true }).addTo(map);
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.marker([55.1, 10.1]).addTo(map);
104
- const path = L.circleMarker([55.2, 10.2], { radius: 8 }).addTo(map);
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.latLng(55, 10));
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.marker([55, 10], {
69
- icon: L.divIcon({ className: 'road-label', html: 'Road name' }),
70
- rotation: 135 * L.DomUtil.DEG_TO_RAD,
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 * L.DomUtil.DEG_TO_RAD;
76
- const road = L.polyline([
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) * L.DomUtil.RAD_TO_DEG + 360) % 360;
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
- ) * L.DomUtil.RAD_TO_DEG + 360) % 360;
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.geoJSON({
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.circleMarker(latlng, { radius: 8 }),
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.canvas({ pane: 'overlayPane' });
124
- L.circleMarker([55, 10], { renderer, radius: 8 }).addTo(map);
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.control.rotate({ closeOnZeroBearing: false }).addTo(map);
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.marker([55, 10]).addTo(map);
145
- const draggableMarker = L.marker([55.1, 10.1], { draggable: true }).addTo(map);
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.marker(point, { autoPanOnFocus: true }).addTo(map);
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: function(latlngs) {
186
+ initialize(latlngs) {
187
187
  this._latlngs = latlngs;
188
188
  },
189
- onAdd: function(map) {
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: function(map) {
201
+ onRemove(map) {
202
202
  map.off('moveend', this._reset, this);
203
203
  L.DomUtil.remove(this._canvas);
204
204
  },
205
- _redraw: function() {
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: function(latlngs) {
211
+ initialize(latlngs) {
212
212
  this._latlngs = latlngs;
213
213
  this._el = L.DomUtil.create('div', 'leaflet-heatmap-overlay');
214
214
  },
215
- onAdd: function(map) {
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: function(map) {
221
+ onRemove(map) {
222
222
  map.off('moveend', this._draw, this);
223
223
  L.DomUtil.remove(this._el);
224
224
  },
225
- _draw: function() {
225
+ _draw() {
226
226
  this._update();
227
227
  },
228
- _update: function() {
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.latLng(55.1, 10.1), L.latLng(54.9, 9.8), L.latLng(55.25, 10.3)];
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.latLng(85, 0);
296
- const path = L.circleMarker(location, { radius: 6 }).addTo(map);
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.marker([55, 10]).addTo(map).bindPopup('popup');
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.marker(edge).addTo(map).bindPopup('edge popup');
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.map(element, {
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.marker([55.5, 10.5]).addTo(secondMap)
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 = L.point(tooltip.options.offset);
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),
@@ -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 body = (await response.text())
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
  });