leaflet-rotate 0.5.1 → 0.5.2

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.
@@ -167,10 +167,8 @@ When('I drag the pitched map', async function () {
167
167
  rect = container.getBoundingClientRect(),
168
168
  start = [rect.left + rect.width / 2, rect.top + rect.height / 2];
169
169
  const vectorScreenPoint = () => {
170
- const bounds = element.getBBox();
171
- const point = new DOMPoint(bounds.x + bounds.width / 2, bounds.y + bounds.height / 2)
172
- .matrixTransform(element.getScreenCTM());
173
- return [point.x, point.y];
170
+ const bounds = element.getBoundingClientRect();
171
+ return [bounds.left + bounds.width / 2, bounds.top + bounds.height / 2];
174
172
  };
175
173
  const before = vectorScreenPoint(),
176
174
  pinBoundsBefore = pinElement.getBoundingClientRect(),
@@ -183,18 +181,42 @@ When('I drag the pitched map', async function () {
183
181
  await this.page.mouse.move(dragStart[0] + 70, dragStart[1] + 35, { steps: 4 });
184
182
  await this.page.mouse.up();
185
183
  this.pitchedDrag = await this.page.evaluate(() => {
186
- const { pinElement, vectorScreenPoint, before, pinBefore } = window.__pitchPanTest,
184
+ const { pinElement, vectorScreenPoint } = window.__pitchPanTest,
187
185
  after = vectorScreenPoint(),
188
186
  pinBoundsAfter = pinElement.getBoundingClientRect(),
189
- pinAfter = [pinBoundsAfter.left + pinBoundsAfter.width / 2, pinBoundsAfter.top + pinBoundsAfter.height / 2];
190
- delete window.__pitchPanTest;
187
+ pinAfter = [pinBoundsAfter.left + pinBoundsAfter.width / 2, pinBoundsAfter.top + pinBoundsAfter.height / 2],
188
+ container = map.getContainer().getBoundingClientRect(),
189
+ expected = map.latLngToContainerPoint(new L.LatLng(55, 10));
191
190
  return {
192
- vectorDelta: [after[0] - before[0], after[1] - before[1]],
193
- pinDelta: [pinAfter[0] - pinBefore[0], pinAfter[1] - pinBefore[1]],
194
- expected: map.latLngToContainerPoint(new L.LatLng(55, 10)),
195
- pointerDelta: [70, 35],
191
+ vector: [after[0] - container.left, after[1] - container.top],
192
+ expected: [expected.x, expected.y],
193
+ vectorError: Math.hypot(after[0] - container.left - expected.x, after[1] - container.top - expected.y),
194
+ pinError: Math.hypot(pinAfter[0] - container.left - expected.x, pinAfter[1] - container.top - expected.y),
196
195
  };
197
196
  });
197
+ this.repeatedPitchPanErrors = [];
198
+ for (let i = 0; i < 2; i++) {
199
+ const bounds = await this.page.locator('#map').boundingBox(),
200
+ center = { x: bounds.x + bounds.width / 2, y: bounds.y + bounds.height / 2 };
201
+ await this.page.mouse.move(center.x, center.y);
202
+ await this.page.mouse.down();
203
+ await this.page.mouse.move(center.x + 40, center.y + 20, { steps: 3 });
204
+ await this.page.mouse.up();
205
+ this.repeatedPitchPanErrors.push(await this.page.evaluate(() => {
206
+ const { element, pinElement } = window.__pitchPanTest,
207
+ bounds = element.getBoundingClientRect(),
208
+ vector = [bounds.left + bounds.width / 2, bounds.top + bounds.height / 2],
209
+ pinBounds = pinElement.getBoundingClientRect(),
210
+ pin = [pinBounds.left + pinBounds.width / 2, pinBounds.top + pinBounds.height / 2],
211
+ container = map.getContainer().getBoundingClientRect(),
212
+ expected = map.latLngToContainerPoint(new L.LatLng(55, 10));
213
+ return [
214
+ Math.hypot(vector[0] - container.left - expected.x, vector[1] - container.top - expected.y),
215
+ Math.hypot(pin[0] - container.left - expected.x, pin[1] - container.top - expected.y),
216
+ ];
217
+ }));
218
+ }
219
+ await this.page.evaluate(() => { delete window.__pitchPanTest; });
198
220
  });
199
221
 
200
222
  Then('vector layers stay aligned with their map coordinates', function () {
@@ -215,10 +237,92 @@ Then('vector layers stay aligned with their map coordinates', function () {
215
237
  }
216
238
  return;
217
239
  }
218
- const { vectorDelta, pinDelta, pointerDelta } = this.pitchedDrag;
219
- for (const delta of [vectorDelta, pinDelta]) {
220
- assert.ok(Math.abs(delta[0] - pointerDelta[0]) < 2, JSON.stringify(this.pitchedDrag));
221
- assert.ok(Math.abs(delta[1] - pointerDelta[1]) < 2, JSON.stringify(this.pitchedDrag));
240
+ assert.ok(this.pitchedDrag.vectorError < 2, JSON.stringify(this.pitchedDrag));
241
+ assert.ok(this.pitchedDrag.pinError < 2, JSON.stringify(this.pitchedDrag));
242
+ for (const errors of this.repeatedPitchPanErrors) {
243
+ assert.ok(errors[0] < 2 && errors[1] < 2, JSON.stringify(this.repeatedPitchPanErrors));
244
+ }
245
+ });
246
+
247
+ When('I pan a highly pitched map in several directions', { timeout: 30000 }, async function () {
248
+ this.pitchPanErrors = [];
249
+ this.page.on('pageerror', error => this.pitchPanErrors.push(error.message));
250
+ await this.page.evaluate(() => {
251
+ map.setView([50, 5], 5, { animate: false });
252
+ map.setBearing(45);
253
+ map.setPitch(70);
254
+ map.options.inertia = false;
255
+ const size = map.getSize(),
256
+ locations = [[0.35, 0.35], [0.65, 0.35], [0.35, 0.65], [0.65, 0.65]]
257
+ .map(([x, y]) => map.containerPointToLatLng([size.x * x, size.y * y])),
258
+ marker = new L.Marker(locations[0]).addTo(map),
259
+ vector = new L.CircleMarker(locations[0], { radius: 4 }).addTo(map),
260
+ bounds = element => {
261
+ const rect = element.getBoundingClientRect();
262
+ return [rect.x, rect.y, rect.width, rect.height];
263
+ };
264
+ window.__pitchRelease = {
265
+ locations,
266
+ resets: 0,
267
+ measure: () => ({
268
+ points: locations.map(ll => map.latLngToContainerPoint(ll)),
269
+ marker: bounds(marker.getElement()),
270
+ vector: bounds(vector.getElement()),
271
+ }),
272
+ };
273
+ map.on('viewreset', () => window.__pitchRelease.resets++);
274
+ });
275
+ this.pitchReleases = [];
276
+ for (const [dx, dy] of [[0, -60], [-60, 0], [30, 50], [30, 10]]) {
277
+ const bounds = await this.page.locator('#map').boundingBox(),
278
+ x = bounds.x + bounds.width / 2,
279
+ y = bounds.y + bounds.height / 2;
280
+ await this.page.mouse.move(x, y);
281
+ await this.page.mouse.down();
282
+ await this.page.mouse.move(x + dx, y + dy, { steps: 10 });
283
+ const before = await this.page.evaluate(() => window.__pitchRelease.measure());
284
+ await this.page.mouse.up();
285
+ await this.page.waitForTimeout(50);
286
+ this.pitchReleases.push(await this.page.evaluate(before => {
287
+ const state = window.__pitchRelease,
288
+ after = state.measure(),
289
+ center = map.project(map.getCenter()),
290
+ size = map.getSize(),
291
+ bearing = map.getBearing() * Math.PI / 180,
292
+ pitch = map.getPitch() * Math.PI / 180,
293
+ perspective = size.y * 1.5,
294
+ projectionErrors = state.locations.map(ll => {
295
+ const point = map.project(ll).subtract(center),
296
+ x = point.x * Math.cos(bearing) - point.y * Math.sin(bearing),
297
+ y = point.x * Math.sin(bearing) + point.y * Math.cos(bearing),
298
+ scale = perspective / (perspective - y * Math.sin(pitch)),
299
+ actual = map.latLngToContainerPoint(ll);
300
+ return Math.hypot(actual.x - size.x / 2 - x * scale, actual.y - size.y / 2 - y * Math.cos(pitch) * scale);
301
+ });
302
+ return { before, after, resets: state.resets, projectionErrors };
303
+ }, before));
304
+ }
305
+ this.pitchPanToError = await this.page.evaluate(() => {
306
+ const center = map.getCenter(),
307
+ target = new L.LatLng(center.lat + 0.1, center.lng + 0.1);
308
+ map.panTo(target, { animate: false });
309
+ return map.latLngToContainerPoint(target).distanceTo(map.getSize().divideBy(2));
310
+ });
311
+ });
312
+
313
+ Then('releasing the map does not jump or reset its layers', function () {
314
+ assert.deepEqual(this.pitchPanErrors, [], 'Pitched dragging must not throw JavaScript errors');
315
+ assert.ok(this.pitchPanToError < 1.5, `panTo missed its target by ${this.pitchPanToError}px`);
316
+ for (const result of this.pitchReleases) {
317
+ assert.equal(result.resets, 0, 'Releasing a pan must not reset the view or reload its tiles');
318
+ for (let i = 0; i < result.before.points.length; i++) {
319
+ const before = result.before.points[i], after = result.after.points[i];
320
+ assert.ok(Math.hypot(before.x - after.x, before.y - after.y) < 0.1, JSON.stringify(result));
321
+ }
322
+ for (const layer of ['marker', 'vector']) {
323
+ assert.ok(result.before[layer].every((value, i) => Math.abs(value - result.after[layer][i]) < 0.1), JSON.stringify(result));
324
+ }
325
+ assert.ok(result.projectionErrors.every(error => error < 1.5), JSON.stringify(result));
222
326
  }
223
327
  });
224
328