terra-draw 1.0.0-beta.0 → 1.0.0-beta.10

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 (60) hide show
  1. package/README.md +10 -3
  2. package/dist/adapters/common/adapter-listener.d.ts +22 -0
  3. package/dist/adapters/common/base.adapter.d.ts +59 -0
  4. package/dist/adapters/mapbox-gl.adapter.d.ts +0 -1
  5. package/dist/adapters/openlayers.adapter.d.ts +14 -13
  6. package/dist/common.d.ts +11 -9
  7. package/dist/extend.d.ts +4 -0
  8. package/dist/geometry/calculate-relative-angle.d.ts +9 -0
  9. package/dist/geometry/clockwise.d.ts +2 -0
  10. package/dist/geometry/determine-halfplane.d.ts +2 -0
  11. package/dist/geometry/measure/bearing.d.ts +3 -7
  12. package/dist/geometry/measure/destination.d.ts +2 -0
  13. package/dist/geometry/measure/pixel-distance-to-line.d.ts +2 -10
  14. package/dist/geometry/measure/pixel-distance.d.ts +2 -7
  15. package/dist/geometry/point-on-line.d.ts +5 -0
  16. package/dist/geometry/project/web-mercator.d.ts +2 -4
  17. package/dist/geometry/web-mercator-centroid.d.ts +2 -4
  18. package/dist/geometry/web-mercator-point-on-line.d.ts +11 -0
  19. package/dist/modes/angled-rectangle/angled-rectangle.mode.d.ts +57 -0
  20. package/dist/modes/base.mode.d.ts +3 -1
  21. package/dist/modes/circle/circle.mode.d.ts +3 -2
  22. package/dist/modes/coordinate-snapping.behavior.d.ts +16 -0
  23. package/dist/modes/freehand/freehand.mode.d.ts +8 -2
  24. package/dist/modes/{snapping.behavior.d.ts → line-snapping.behavior.d.ts} +1 -1
  25. package/dist/modes/linestring/linestring.mode.d.ts +11 -4
  26. package/dist/modes/point/point.mode.d.ts +2 -2
  27. package/dist/modes/polygon/polygon.mode.d.ts +14 -4
  28. package/dist/modes/rectangle/rectangle.mode.d.ts +2 -2
  29. package/dist/modes/render/render.mode.d.ts +2 -1
  30. package/dist/modes/sector/sector.mode.d.ts +60 -0
  31. package/dist/modes/select/behaviors/drag-feature.behavior.d.ts +2 -2
  32. package/dist/modes/sensor/sensor.mode.d.ts +69 -0
  33. package/dist/store/store-feature-validation.d.ts +8 -2
  34. package/dist/store/store.d.ts +7 -3
  35. package/dist/terra-draw.cjs +1 -1
  36. package/dist/terra-draw.cjs.map +1 -1
  37. package/dist/terra-draw.d.ts +13 -13
  38. package/dist/terra-draw.modern.js +1 -1
  39. package/dist/terra-draw.modern.js.map +1 -1
  40. package/dist/terra-draw.module.js +1 -1
  41. package/dist/terra-draw.module.js.map +1 -1
  42. package/dist/terra-draw.umd.js +1 -1
  43. package/dist/terra-draw.umd.js.map +1 -1
  44. package/dist/validation-reasons.d.ts +13 -0
  45. package/dist/validations/common-validations.d.ts +2 -0
  46. package/dist/validations/linestring.validation.d.ts +4 -1
  47. package/dist/validations/max-size.validation.d.ts +3 -1
  48. package/dist/validations/min-size.validation.d.ts +3 -1
  49. package/dist/validations/not-self-intersecting.validation.d.ts +4 -1
  50. package/dist/validations/point.validation.d.ts +4 -1
  51. package/dist/validations/polygon.validation.d.ts +8 -2
  52. package/e2e/package-lock.json +5 -4
  53. package/e2e/package.json +1 -1
  54. package/e2e/public/index.html +3 -0
  55. package/e2e/tests/leaflet.spec.ts +490 -14
  56. package/e2e/tests/setup.ts +34 -6
  57. package/eslint.config.js +31 -0
  58. package/package.json +30 -30
  59. package/tsconfig.json +2 -1
  60. package/readme.gif +0 -0
@@ -53,7 +53,7 @@ test.describe("page setup", () => {
53
53
  test.describe("point mode", () => {
54
54
  const mode = "point";
55
55
 
56
- test("mode can set and can be used to create a point", async ({ page }) => {
56
+ test("mode can set and used to create a point", async ({ page }) => {
57
57
  const mapDiv = await setupMap({ page });
58
58
  await changeMode({ page, mode });
59
59
  await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
@@ -61,9 +61,7 @@ test.describe("point mode", () => {
61
61
  await expectPaths({ page, count: 1 });
62
62
  });
63
63
 
64
- test("mode can set and can be used to create multiple points", async ({
65
- page,
66
- }) => {
64
+ test("mode can set and used to create multiple points", async ({ page }) => {
67
65
  const mapDiv = await setupMap({ page });
68
66
  await changeMode({ page, mode });
69
67
 
@@ -91,7 +89,7 @@ test.describe("linestring mode", () => {
91
89
  ] as { name: string; config: TestConfigOptions[] }[];
92
90
 
93
91
  for (const { name, config } of options) {
94
- test(`mode can set and can be used to create a linestring${name}`, async ({
92
+ test(`mode can set and used to create a linestring${name}`, async ({
95
93
  page,
96
94
  }) => {
97
95
  const mapDiv = await setupMap({ page, configQueryParam: config });
@@ -108,7 +106,7 @@ test.describe("linestring mode", () => {
108
106
  await expectPaths({ page, count: 1 });
109
107
  });
110
108
 
111
- test(`mode can set and can be used to create a linestring with multiple points${name}`, async ({
109
+ test(`mode can set and used to create a linestring with multiple points${name}`, async ({
112
110
  page,
113
111
  }) => {
114
112
  const mapDiv = await setupMap({ page, configQueryParam: config });
@@ -133,7 +131,7 @@ test.describe("linestring mode", () => {
133
131
  await expectPaths({ page, count: 1 });
134
132
  });
135
133
 
136
- test(`mode can set and can be used to create a linestring with multiple clicked points${name}`, async ({
134
+ test(`mode can set and used to create a linestring with multiple clicked points${name}`, async ({
137
135
  page,
138
136
  }) => {
139
137
  const mapDiv = await setupMap({ page, configQueryParam: config });
@@ -158,7 +156,7 @@ test.describe("linestring mode", () => {
158
156
  await expectPaths({ page, count: 1 });
159
157
  });
160
158
 
161
- test(`mode can set and can be used to create multiple linestrings${name}`, async ({
159
+ test(`mode can set and used to create multiple linestrings${name}`, async ({
162
160
  page,
163
161
  }) => {
164
162
  const mapDiv = await setupMap({ page, configQueryParam: config });
@@ -191,13 +189,52 @@ test.describe("linestring mode", () => {
191
189
  // Two lines
192
190
  await expectPaths({ page, count: 2 });
193
191
  });
192
+
193
+ test(`mode can set with snapping enabled used to create multiple linestrings${name}`, async ({
194
+ page,
195
+ }) => {
196
+ const mapDiv = await setupMap({
197
+ page,
198
+ configQueryParam: config
199
+ ? [...config, "snappingCoordinate"]
200
+ : undefined,
201
+ });
202
+ await changeMode({ page, mode });
203
+
204
+ // First line
205
+ await page.mouse.move(mapDiv.width / 2, mapDiv.height / 2);
206
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
207
+ await page.mouse.move(mapDiv.width / 3, mapDiv.height / 3);
208
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 3);
209
+
210
+ // One point + one line
211
+ await expectPaths({ page, count: 2 });
212
+
213
+ // Close first line
214
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 3);
215
+
216
+ // One line
217
+ await expectPaths({ page, count: 1 });
218
+
219
+ // Second line
220
+ await page.mouse.move(mapDiv.width / 3, mapDiv.height / 3);
221
+
222
+ // Should see snapping point
223
+ await expectPaths({ page, count: 2 });
224
+
225
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 3);
226
+ await page.mouse.move(mapDiv.width / 4, mapDiv.height / 4);
227
+
228
+ // Snapping point disappears but the second line is created so it is still 2
229
+ await expectPaths({ page, count: 2 });
230
+ });
194
231
  }
195
232
  });
196
233
 
197
234
  test.describe("polygon mode", () => {
198
235
  const mode = "polygon";
199
236
 
200
- test("mode can set and can be used to create a polygon", async ({ page }) => {
237
+ test("mode can set and used to create a polygon", async ({ page }) => {
201
238
  const mapDiv = await setupMap({ page });
202
239
  await changeMode({ page, mode });
203
240
 
@@ -307,14 +344,66 @@ test.describe("polygon mode", () => {
307
344
  // over the limit of 1000000 square meters.
308
345
  await expectPaths({ page, count: 1 });
309
346
  });
347
+
348
+ test("mode can set and used to create a polygon with snapping enabled", async ({
349
+ page,
350
+ }) => {
351
+ const mapDiv = await setupMap({
352
+ page,
353
+ configQueryParam: ["snappingCoordinate"],
354
+ });
355
+ await changeMode({ page, mode });
356
+
357
+ // The length of the square sides in pixels
358
+ const sideLength = 100;
359
+
360
+ // Calculating the half of the side length
361
+ const halfLength = sideLength / 2;
362
+
363
+ // Coordinates of the center
364
+ const centerX = mapDiv.width / 2;
365
+ const centerY = mapDiv.height / 2;
366
+
367
+ // Coordinates of the four corners of the square
368
+ const topLeft = { x: centerX - halfLength, y: centerY - halfLength };
369
+ const topRight = { x: centerX + halfLength, y: centerY - halfLength };
370
+ const bottomLeft = { x: centerX - halfLength, y: centerY + halfLength };
371
+ const bottomRight = { x: centerX + halfLength, y: centerY + halfLength };
372
+
373
+ // Perform clicks at each corner
374
+ await page.mouse.click(topLeft.x, topLeft.y);
375
+ await page.mouse.click(topRight.x, topRight.y);
376
+ await page.mouse.click(bottomRight.x, bottomRight.y);
377
+ await page.mouse.click(bottomLeft.x, bottomLeft.y);
378
+
379
+ // Close the square
380
+ await page.mouse.click(bottomLeft.x, bottomLeft.y);
381
+
382
+ // One point + one line
383
+ await expectPaths({ page, count: 1 });
384
+
385
+ // Let's create a new polygon attached to the square, snapping to it
386
+ await page.mouse.click(bottomLeft.x, bottomLeft.y);
387
+ await page.mouse.click(bottomRight.x, bottomRight.y);
388
+ await page.mouse.click(bottomRight.x, bottomRight.y + 50);
389
+
390
+ await expectPaths({ page, count: 4 });
391
+
392
+ await page.mouse.click(bottomRight.x, bottomRight.y + 50);
393
+
394
+ await expectPaths({ page, count: 2 });
395
+
396
+ // Go to another corner and it should snap with a point appearing
397
+ await page.mouse.click(topLeft.x, topLeft.y);
398
+
399
+ await expectPaths({ page, count: 3 });
400
+ });
310
401
  });
311
402
 
312
403
  test.describe("rectangle mode", () => {
313
404
  const mode = "rectangle";
314
405
 
315
- test("mode can set and can be used to create a rectangle", async ({
316
- page,
317
- }) => {
406
+ test("mode can set and used to create a rectangle", async ({ page }) => {
318
407
  const mapDiv = await setupMap({ page });
319
408
  await changeMode({ page, mode });
320
409
 
@@ -328,10 +417,397 @@ test.describe("rectangle mode", () => {
328
417
  });
329
418
  });
330
419
 
420
+ test.describe("angled rectangle mode", () => {
421
+ const mode = "angled-rectangle";
422
+
423
+ test("mode can set and used to create an angled rectangle (horizontal up)", async ({
424
+ page,
425
+ }) => {
426
+ const mapDiv = await setupMap({ page });
427
+ await changeMode({ page, mode });
428
+
429
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
430
+ await page.mouse.move(mapDiv.width / 3, mapDiv.height / 2, { steps: 30 });
431
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 2);
432
+ await page.mouse.move(mapDiv.width / 3 + 50, mapDiv.height / 3 + 50, {
433
+ steps: 30,
434
+ });
435
+ await page.mouse.click(mapDiv.width / 3 + 50, mapDiv.height / 3 + 50);
436
+
437
+ await expectPaths({ page, count: 1 });
438
+
439
+ await expectPathDimensions({ page, width: 217, height: 74 });
440
+ });
441
+
442
+ test("mode can set and used to create an angled rectangle (horizontal down)", async ({
443
+ page,
444
+ }) => {
445
+ const mapDiv = await setupMap({ page });
446
+ await changeMode({ page, mode });
447
+
448
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
449
+ await page.mouse.move(mapDiv.width / 3, mapDiv.height / 2, { steps: 30 });
450
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 2);
451
+ await page.mouse.move(mapDiv.width / 3 + 50, mapDiv.height / 3 + 200, {
452
+ steps: 30,
453
+ });
454
+ await page.mouse.click(mapDiv.width / 3 + 50, mapDiv.height / 3 + 200);
455
+
456
+ await expectPaths({ page, count: 1 });
457
+
458
+ await expectPathDimensions({ page, width: 217, height: 84 });
459
+ });
460
+
461
+ test("mode can set and used to create an angled (diagonal)", async ({
462
+ page,
463
+ }) => {
464
+ const mapDiv = await setupMap({ page });
465
+ await changeMode({ page, mode });
466
+
467
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
468
+ await page.mouse.move(mapDiv.width / 3, mapDiv.height / 3, { steps: 30 });
469
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 3);
470
+ await page.mouse.move(mapDiv.width / 3 + 150, mapDiv.height / 3 + 150, {
471
+ steps: 30,
472
+ });
473
+ await page.mouse.click(mapDiv.width / 3 + 150, mapDiv.height / 3 + 150);
474
+
475
+ await expectPaths({ page, count: 1 });
476
+
477
+ await expectPathDimensions({ page, width: 245, height: 174 });
478
+ });
479
+
480
+ test("mode can set and used to create an angled (diagonal 2)", async ({
481
+ page,
482
+ }) => {
483
+ const mapDiv = await setupMap({ page });
484
+ await changeMode({ page, mode });
485
+
486
+ await page.mouse.click(mapDiv.width / 1.8, mapDiv.height / 1.8);
487
+ await page.mouse.move(mapDiv.width / 2.5, mapDiv.height / 1.3, {
488
+ steps: 30,
489
+ });
490
+ await page.mouse.click(mapDiv.width / 2.5, mapDiv.height / 1.3);
491
+ await page.mouse.move(mapDiv.width / 2.5 + 50, mapDiv.height / 1.3 + 50, {
492
+ steps: 30,
493
+ });
494
+ await page.mouse.click(mapDiv.width / 2.5 + 50, mapDiv.height / 1.3 + 50);
495
+
496
+ await expectPaths({ page, count: 1 });
497
+
498
+ await expectPathDimensions({ page, width: 246, height: 213 });
499
+ });
500
+ });
501
+
502
+ test.describe("sector mode", () => {
503
+ const mode = "sector";
504
+
505
+ test("mode can set and used to create a sector less than 90 degrees (clockwise)", async ({
506
+ page,
507
+ }) => {
508
+ const mapDiv = await setupMap({ page });
509
+ await changeMode({ page, mode });
510
+
511
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
512
+ await page.mouse.move(mapDiv.width / 3, mapDiv.height / 2, { steps: 30 });
513
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 2);
514
+ await page.mouse.move(mapDiv.width / 3, mapDiv.height / 3, {
515
+ steps: 30,
516
+ });
517
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 3);
518
+
519
+ await expectPaths({ page, count: 1 });
520
+
521
+ await expectPathDimensions({ page, width: 217, height: 109 });
522
+ });
523
+
524
+ test("mode can set and used to create a sector more than 90 degrees (clockwise)", async ({
525
+ page,
526
+ }) => {
527
+ const mapDiv = await setupMap({ page });
528
+ await changeMode({ page, mode });
529
+
530
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
531
+ await page.mouse.move(mapDiv.width / 3, mapDiv.height / 2, { steps: 30 });
532
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 2);
533
+ await page.mouse.move(mapDiv.width * 0.75, mapDiv.height / 3, {
534
+ steps: 30,
535
+ });
536
+ await page.mouse.click(mapDiv.width * 0.75, mapDiv.height / 3);
537
+
538
+ await expectPaths({ page, count: 1 });
539
+
540
+ await expectPathDimensions({ page, width: 417, height: 217 });
541
+ });
542
+
543
+ test("mode can set and used to create a sector more than 180 degrees (clockwise)", async ({
544
+ page,
545
+ }) => {
546
+ const mapDiv = await setupMap({ page });
547
+ await changeMode({ page, mode });
548
+
549
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
550
+ await page.mouse.move(mapDiv.width / 3, mapDiv.height / 2, { steps: 30 });
551
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 2);
552
+ await page.mouse.move(mapDiv.width * 0.75, mapDiv.height / 3, {
553
+ steps: 10,
554
+ });
555
+ await page.mouse.move(mapDiv.width * 0.4, mapDiv.height / 1.5, {
556
+ steps: 10,
557
+ });
558
+ await page.mouse.click(mapDiv.width * 0.4, mapDiv.height / 1.5);
559
+
560
+ await expectPaths({ page, count: 1 });
561
+
562
+ await expectPathDimensions({ page, width: 430, height: 430 });
563
+ });
564
+
565
+ test("mode can set and used to create a sector less than 90 degrees (anticlockwise)", async ({
566
+ page,
567
+ }) => {
568
+ const mapDiv = await setupMap({ page });
569
+ await changeMode({ page, mode });
570
+
571
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
572
+ await page.mouse.move(mapDiv.width / 3, mapDiv.height / 2, { steps: 30 });
573
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 2);
574
+ await page.mouse.move(mapDiv.width * 0.4, mapDiv.height / 1.5, {
575
+ steps: 30,
576
+ });
577
+ await page.mouse.click(mapDiv.width * 0.4, mapDiv.height / 1.5);
578
+
579
+ await expectPaths({ page, count: 1 });
580
+
581
+ await expectPathDimensions({ page, width: 217, height: 150 });
582
+ });
583
+
584
+ test("mode can set and used to create a sector more than 90 degrees (anticlockwise)", async ({
585
+ page,
586
+ }) => {
587
+ const mapDiv = await setupMap({ page });
588
+ await changeMode({ page, mode });
589
+
590
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
591
+ await page.mouse.move(mapDiv.width / 3, mapDiv.height / 2, { steps: 30 });
592
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 2);
593
+ await page.mouse.move(mapDiv.width * 0.75, mapDiv.height / 1.5, {
594
+ steps: 30,
595
+ });
596
+ await page.mouse.click(mapDiv.width * 0.75, mapDiv.height / 1.5);
597
+
598
+ await expectPaths({ page, count: 1 });
599
+
600
+ await expectPathDimensions({ page, width: 417, height: 217 });
601
+ });
602
+
603
+ test("mode can set and used to create a sector more than 180 degrees (anticlockwise)", async ({
604
+ page,
605
+ }) => {
606
+ const mapDiv = await setupMap({ page });
607
+ await changeMode({ page, mode });
608
+
609
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
610
+ await page.mouse.move(mapDiv.width / 3, mapDiv.height / 2, { steps: 30 });
611
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 2);
612
+ await page.mouse.move(mapDiv.width * 0.75, mapDiv.height / 1.5, {
613
+ steps: 30,
614
+ });
615
+ await page.mouse.move(mapDiv.width * 0.75, mapDiv.height / 3, {
616
+ steps: 30,
617
+ });
618
+ await page.mouse.click(mapDiv.width * 0.75, mapDiv.height / 3);
619
+
620
+ await expectPaths({ page, count: 1 });
621
+
622
+ await expectPathDimensions({ page, width: 430, height: 292 });
623
+ });
624
+ });
625
+
626
+ test.describe("sensor mode", () => {
627
+ const mode = "sensor";
628
+
629
+ test("mode can set and creates center point on first click", async ({
630
+ page,
631
+ }) => {
632
+ const mapDiv = await setupMap({ page });
633
+ await changeMode({ page, mode });
634
+
635
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
636
+
637
+ await expectPaths({ page, count: 1 });
638
+
639
+ await expectPathDimensions({ page, width: 12, height: 12 });
640
+ });
641
+
642
+ test("mode can set and but won't close if the mouse goes behind the initial arc", async ({
643
+ page,
644
+ }) => {
645
+ const mapDiv = await setupMap({ page });
646
+ await changeMode({ page, mode });
647
+
648
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
649
+ await page.mouse.move(mapDiv.width / 3, mapDiv.height / 2, { steps: 30 });
650
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 2);
651
+ await page.mouse.move(mapDiv.width / 3, mapDiv.height / 3, { steps: 30 });
652
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 3);
653
+
654
+ // The cursor is now behind the initial arc and so wont close the sensor
655
+ await page.mouse.move(mapDiv.width / 1, mapDiv.height / 3, { steps: 30 });
656
+ await page.mouse.click(mapDiv.width / 1, mapDiv.height / 3);
657
+
658
+ // We expect the count to be 2 because the sensor polygon is not finished
659
+ // and we are left with the center point and the arc line
660
+ await expectPaths({ page, count: 2 });
661
+
662
+ await expectPathDimensions({ page, width: 12, height: 12, item: 0 });
663
+ await expectPathDimensions({ page, width: 31, height: 109, item: 1 });
664
+ });
665
+
666
+ test("mode can set and used to create a sensor less than 90 degrees (clockwise)", async ({
667
+ page,
668
+ }) => {
669
+ const mapDiv = await setupMap({ page });
670
+ await changeMode({ page, mode });
671
+
672
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
673
+ await page.mouse.move(mapDiv.width / 3, mapDiv.height / 2, { steps: 30 });
674
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 2);
675
+ await page.mouse.move(mapDiv.width / 3, mapDiv.height / 3, { steps: 30 });
676
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 3);
677
+
678
+ // Finalise the sensor polygon
679
+ await page.mouse.move(mapDiv.width / 5, mapDiv.height / 3, { steps: 30 });
680
+ await page.mouse.click(mapDiv.width / 5, mapDiv.height / 3);
681
+
682
+ await expectPaths({ page, count: 1 });
683
+
684
+ await expectPathDimensions({ page, width: 220, height: 201 });
685
+ });
686
+
687
+ test("mode can set and used to create a sensor more than 90 degrees (clockwise)", async ({
688
+ page,
689
+ }) => {
690
+ const mapDiv = await setupMap({ page });
691
+ await changeMode({ page, mode });
692
+
693
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
694
+ await page.mouse.move(mapDiv.width / 3, mapDiv.height / 2, { steps: 30 });
695
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 2);
696
+ await page.mouse.move(mapDiv.width * 0.75, mapDiv.height / 2.5, {
697
+ steps: 30,
698
+ });
699
+ await page.mouse.click(mapDiv.width * 0.75, mapDiv.height / 2.5);
700
+
701
+ // Finalise the sensor polygon
702
+ await page.mouse.move(mapDiv.width * 0.75, mapDiv.height / 5, {
703
+ steps: 30,
704
+ });
705
+ await page.mouse.click(mapDiv.width * 0.75, mapDiv.height / 5);
706
+
707
+ await expectPathDimensions({ page, width: 767, height: 390 });
708
+ });
709
+
710
+ test("mode can set and used to create a sensor more than 180 degrees (clockwise)", async ({
711
+ page,
712
+ }) => {
713
+ const mapDiv = await setupMap({ page });
714
+ await changeMode({ page, mode });
715
+
716
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
717
+ await page.mouse.move(mapDiv.width / 3, mapDiv.height / 2, { steps: 30 });
718
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 2);
719
+ await page.mouse.move(mapDiv.width * 0.75, mapDiv.height / 3, {
720
+ steps: 10,
721
+ });
722
+ await page.mouse.move(mapDiv.width * 0.4, mapDiv.height / 1.5, {
723
+ steps: 10,
724
+ });
725
+ await page.mouse.click(mapDiv.width * 0.4, mapDiv.height / 1.5);
726
+
727
+ // Finalise the sensor polygon
728
+ await page.mouse.move(mapDiv.width * 0.4, mapDiv.height / 1.25);
729
+ await page.mouse.click(mapDiv.width * 0.4, mapDiv.height / 1.25);
730
+
731
+ await expectPaths({ page, count: 1 });
732
+
733
+ await expectPathDimensions({ page, width: 506, height: 506 });
734
+ });
735
+
736
+ test("mode can set and used to create a sensor less than 90 degrees (anticlockwise)", async ({
737
+ page,
738
+ }) => {
739
+ const mapDiv = await setupMap({ page });
740
+ await changeMode({ page, mode });
741
+
742
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
743
+ await page.mouse.move(mapDiv.width / 3, mapDiv.height / 2, { steps: 30 });
744
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 2);
745
+ await page.mouse.move(mapDiv.width * 0.4, mapDiv.height / 1.5, {
746
+ steps: 30,
747
+ });
748
+ await page.mouse.click(mapDiv.width * 0.4, mapDiv.height / 1.5);
749
+
750
+ // Finalise the sensor polygon
751
+ await page.mouse.move(mapDiv.width * 0.3, mapDiv.height / 1.25);
752
+ await page.mouse.click(mapDiv.width * 0.3, mapDiv.height / 1.25);
753
+
754
+ await expectPaths({ page, count: 1 });
755
+
756
+ await expectPathDimensions({ page, width: 183, height: 233 });
757
+ });
758
+
759
+ test("mode can set and used to create a sensor more than 90 degrees (anticlockwise)", async ({
760
+ page,
761
+ }) => {
762
+ const mapDiv = await setupMap({ page });
763
+ await changeMode({ page, mode });
764
+
765
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
766
+ await page.mouse.move(mapDiv.width / 3, mapDiv.height / 2, { steps: 30 });
767
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 2);
768
+ await page.mouse.move(mapDiv.width * 0.75, mapDiv.height / 1.5, {
769
+ steps: 30,
770
+ });
771
+ await page.mouse.click(mapDiv.width * 0.75, mapDiv.height / 1.5);
772
+
773
+ // Finalise the sensor polygon
774
+ await page.mouse.move(mapDiv.width * 0.75, mapDiv.height / 1.3);
775
+ await page.mouse.click(mapDiv.width * 0.75, mapDiv.height / 1.3);
776
+
777
+ await expectPathDimensions({ page, width: 728, height: 378 });
778
+ });
779
+
780
+ test("mode can set and used to create a sensor more than 180 degrees (anticlockwise)", async ({
781
+ page,
782
+ }) => {
783
+ const mapDiv = await setupMap({ page });
784
+ await changeMode({ page, mode });
785
+
786
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
787
+ await page.mouse.move(mapDiv.width / 3, mapDiv.height / 2, { steps: 30 });
788
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 2);
789
+ await page.mouse.move(mapDiv.width * 0.75, mapDiv.height / 1.5, {
790
+ steps: 30,
791
+ });
792
+ await page.mouse.move(mapDiv.width * 0.75, mapDiv.height / 3, {
793
+ steps: 30,
794
+ });
795
+ await page.mouse.click(mapDiv.width * 0.75, mapDiv.height / 3);
796
+
797
+ // Finalise the sensor polygon
798
+ await page.mouse.move(mapDiv.width * 0.8, mapDiv.height / 3, { steps: 30 });
799
+ await page.mouse.click(mapDiv.width * 0.8, mapDiv.height / 3);
800
+
801
+ await expectPaths({ page, count: 1 });
802
+
803
+ await expectPathDimensions({ page, width: 808, height: 547 });
804
+ });
805
+ });
806
+
331
807
  test.describe("circle mode", () => {
332
808
  const mode = "circle";
333
809
 
334
- test("mode can set and can be used to create a web mercator circle", async ({
810
+ test("mode can set and used to create a web mercator circle", async ({
335
811
  page,
336
812
  }) => {
337
813
  const mapDiv = await setupMap({ page });
@@ -346,7 +822,7 @@ test.describe("circle mode", () => {
346
822
  await expectPathDimensions({ page, width: 146, height: 146 });
347
823
  });
348
824
 
349
- test("mode can set and can be used to create a geodesic circle", async ({
825
+ test("mode can set and used to create a geodesic circle", async ({
350
826
  page,
351
827
  }) => {
352
828
  const mapDiv = await setupMap({ page, configQueryParam: ["globeCircle"] });
@@ -8,7 +8,8 @@ export type TestConfigOptions =
8
8
  | "insertCoordinates"
9
9
  | "insertCoordinatesGlobe"
10
10
  | "globeCircle"
11
- | "globeSelect";
11
+ | "globeSelect"
12
+ | "snappingCoordinate";
12
13
 
13
14
  export const setupMap = async ({
14
15
  page,
@@ -53,9 +54,28 @@ export const changeMode = async ({
53
54
  mode,
54
55
  }: {
55
56
  page: Page;
56
- mode: "point" | "polygon" | "linestring" | "select" | "rectangle" | "circle";
57
+ mode:
58
+ | "point"
59
+ | "polygon"
60
+ | "linestring"
61
+ | "select"
62
+ | "rectangle"
63
+ | "circle"
64
+ | "angled-rectangle"
65
+ | "sector"
66
+ | "sensor";
57
67
  }) => {
58
- const modeText = mode.charAt(0).toUpperCase() + mode.slice(1);
68
+ let modeText = mode.charAt(0).toUpperCase() + mode.slice(1);
69
+
70
+ if (mode.includes("-")) {
71
+ modeText = mode
72
+ .split("-")
73
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
74
+ .join(" ");
75
+ } else {
76
+ modeText = mode.charAt(0).toUpperCase() + mode.slice(1);
77
+ }
78
+
59
79
  const buttons = page.getByTestId("buttons");
60
80
  const button = buttons.getByText(modeText, { exact: true });
61
81
 
@@ -66,7 +86,10 @@ export const changeMode = async ({
66
86
  const color = await button.evaluate((el) =>
67
87
  window.getComputedStyle(el).getPropertyValue("color"),
68
88
  );
69
- expect(color).toBe("rgb(39, 204, 255)"); // We set hex but it gets computed to rgb
89
+ expect(
90
+ color,
91
+ "Text rgb color should match the expected selected button color",
92
+ ).toBe("rgb(39, 204, 255)"); // We set hex but it gets computed to rgb
70
93
  };
71
94
 
72
95
  export const expectPaths = async ({
@@ -82,7 +105,10 @@ export const expectPaths = async ({
82
105
  await page.waitForSelector(selector);
83
106
  expect(await page.locator(selector).count()).toBe(count);
84
107
  } else {
85
- await expect(await page.locator(selector).count()).toBe(0);
108
+ await expect(
109
+ await page.locator(selector).count(),
110
+ `locator count should be greater than 0 for selector ${selector}`,
111
+ ).toBe(0);
86
112
  }
87
113
  };
88
114
 
@@ -90,14 +116,16 @@ export const expectPathDimensions = async ({
90
116
  page,
91
117
  width,
92
118
  height,
119
+ item = 0,
93
120
  }: {
94
121
  page: Page;
95
122
  width: number;
96
123
  height: number;
124
+ item?: number;
97
125
  }) => {
98
126
  const selector = "svg > g > path";
99
127
 
100
- const boundingBox = await page.locator(selector).boundingBox();
128
+ const boundingBox = await page.locator(selector).nth(item).boundingBox();
101
129
 
102
130
  expect(boundingBox?.width).toBe(width);
103
131
  expect(boundingBox?.height).toBe(height);
@@ -0,0 +1,31 @@
1
+ import typescriptEslint from "@typescript-eslint/eslint-plugin";
2
+ import tsParser from "@typescript-eslint/parser";
3
+ import eslintPluginPrettier from "eslint-plugin-prettier";
4
+ import prettierConfig from "eslint-config-prettier";
5
+
6
+ export default [
7
+ {
8
+ name: "prettier", // Configuration name
9
+ files: ["**/*.{js,jsx,ts,tsx,json,md,yml,yaml,html,css}"],
10
+ plugins: {
11
+ prettier: eslintPluginPrettier, // Include Prettier plugin
12
+ },
13
+ rules: {
14
+ ...prettierConfig.rules, // Disable ESLint rules that conflict with Prettier
15
+ },
16
+ },
17
+ {
18
+ name: "typescript", // Configuration name
19
+ files: ["**/*.ts"], // TypeScript-specific configuration
20
+ plugins: {
21
+ "@typescript-eslint": typescriptEslint, // Include TypeScript ESLint plugin
22
+ },
23
+ languageOptions: {
24
+ parser: tsParser,
25
+ },
26
+ rules: {
27
+ "@typescript-eslint/no-empty-function": "warn",
28
+ "@typescript-eslint/no-explicit-any": "warn",
29
+ },
30
+ },
31
+ ];