terra-draw 0.0.1-alpha.9 → 1.0.0-beta.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.
Files changed (122) hide show
  1. package/.devcontainer/Dockerfile +8 -0
  2. package/.devcontainer/devcontainer.json +27 -0
  3. package/.devcontainer/post-create.sh +16 -0
  4. package/README.md +23 -13
  5. package/dist/adapters/arcgis-maps-sdk.adapter.d.ts +106 -0
  6. package/dist/adapters/google-maps.adapter.d.ts +90 -39
  7. package/dist/adapters/leaflet.adapter.d.ts +99 -33
  8. package/dist/adapters/mapbox-gl.adapter.d.ts +91 -37
  9. package/dist/adapters/maplibre-gl.adapter.d.ts +72 -0
  10. package/dist/adapters/openlayers.adapter.d.ts +120 -0
  11. package/dist/common.d.ts +118 -98
  12. package/dist/geometry/boolean/is-valid-coordinate.d.ts +4 -0
  13. package/dist/geometry/boolean/point-in-polygon.d.ts +2 -2
  14. package/dist/geometry/boolean/self-intersects.d.ts +2 -2
  15. package/dist/geometry/calculate-relative-angle.d.ts +17 -0
  16. package/dist/geometry/centroid.d.ts +2 -2
  17. package/dist/geometry/coordinates-identical.d.ts +2 -2
  18. package/dist/geometry/determine-halfplane.d.ts +10 -0
  19. package/dist/geometry/get-coordinates-as-points.d.ts +6 -6
  20. package/dist/geometry/get-midpoints.d.ts +14 -7
  21. package/dist/geometry/helpers.d.ts +4 -4
  22. package/dist/geometry/limit-decimal-precision.d.ts +1 -1
  23. package/dist/geometry/measure/area.d.ts +2 -0
  24. package/dist/geometry/measure/bearing.d.ts +9 -0
  25. package/dist/geometry/measure/destination.d.ts +9 -0
  26. package/dist/geometry/measure/haversine-distance.d.ts +2 -2
  27. package/dist/geometry/measure/pixel-distance-to-line.d.ts +10 -10
  28. package/dist/geometry/measure/pixel-distance.d.ts +7 -7
  29. package/dist/geometry/measure/rhumb-bearing.d.ts +2 -2
  30. package/dist/geometry/measure/rhumb-destination.d.ts +2 -2
  31. package/dist/geometry/measure/rhumb-distance.d.ts +2 -2
  32. package/dist/geometry/measure/slice-along.d.ts +2 -0
  33. package/dist/geometry/midpoint-coordinate.d.ts +4 -2
  34. package/dist/geometry/project/web-mercator.d.ts +20 -0
  35. package/dist/geometry/shape/create-bbox.d.ts +10 -0
  36. package/dist/geometry/shape/create-circle.d.ts +13 -7
  37. package/dist/geometry/shape/great-circle-coordinates.d.ts +2 -0
  38. package/dist/geometry/shape/web-mercator-distortion.d.ts +2 -0
  39. package/dist/geometry/transform/rotate.d.ts +9 -2
  40. package/dist/geometry/transform/scale.d.ts +9 -2
  41. package/dist/geometry/web-mercator-centroid.d.ts +11 -0
  42. package/dist/modes/angled-rectangle/angled-rectangle.mode.d.ts +62 -0
  43. package/dist/modes/base.behavior.d.ts +21 -19
  44. package/dist/modes/base.mode.d.ts +66 -33
  45. package/dist/modes/circle/circle.mode.d.ts +66 -37
  46. package/dist/modes/click-bounding-box.behavior.d.ts +6 -7
  47. package/dist/modes/freehand/freehand.mode.d.ts +63 -43
  48. package/dist/modes/insert-coordinates.behavior.d.ts +9 -0
  49. package/dist/modes/linestring/linestring.mode.d.ts +78 -47
  50. package/dist/modes/pixel-distance.behavior.d.ts +7 -7
  51. package/dist/modes/point/point.mode.d.ts +44 -26
  52. package/dist/modes/polygon/behaviors/closing-points.behavior.d.ts +19 -19
  53. package/dist/modes/polygon/polygon.mode.d.ts +69 -51
  54. package/dist/modes/rectangle/rectangle.mode.d.ts +55 -0
  55. package/dist/modes/render/render.mode.d.ts +52 -23
  56. package/dist/modes/select/behaviors/drag-coordinate-resize.behavior.d.ts +62 -0
  57. package/dist/modes/select/behaviors/drag-coordinate.behavior.d.ts +20 -13
  58. package/dist/modes/select/behaviors/drag-feature.behavior.d.ts +20 -17
  59. package/dist/modes/select/behaviors/{features-at-mouse-event.behavior.d.ts → feature-at-pointer-event.behavior.d.ts} +15 -15
  60. package/dist/modes/select/behaviors/midpoint.behavior.d.ts +19 -18
  61. package/dist/modes/select/behaviors/rotate-feature.behavior.d.ts +14 -13
  62. package/dist/modes/select/behaviors/scale-feature.behavior.d.ts +14 -13
  63. package/dist/modes/select/behaviors/selection-point.behavior.d.ts +19 -18
  64. package/dist/modes/select/select.mode.d.ts +119 -78
  65. package/dist/modes/snapping.behavior.d.ts +16 -13
  66. package/dist/modes/static/static.mode.d.ts +32 -30
  67. package/dist/store/spatial-index/quickselect.d.ts +2 -2
  68. package/dist/store/spatial-index/rbush.d.ts +35 -35
  69. package/dist/store/spatial-index/spatial-index.d.ts +18 -18
  70. package/dist/store/store-feature-validation.d.ts +16 -0
  71. package/dist/store/store.d.ts +59 -48
  72. package/dist/terra-draw.cjs +1 -1
  73. package/dist/terra-draw.cjs.map +1 -1
  74. package/dist/terra-draw.d.ts +223 -48
  75. package/dist/terra-draw.modern.js +1 -1
  76. package/dist/terra-draw.modern.js.map +1 -1
  77. package/dist/terra-draw.module.js +1 -1
  78. package/dist/terra-draw.module.js.map +1 -1
  79. package/dist/terra-draw.umd.js +1 -1
  80. package/dist/terra-draw.umd.js.map +1 -1
  81. package/dist/util/geoms.d.ts +3 -3
  82. package/dist/util/id.d.ts +1 -1
  83. package/dist/util/styling.d.ts +2 -2
  84. package/dist/validations/linestring.validation.d.ts +2 -0
  85. package/dist/validations/max-size.validation.d.ts +2 -0
  86. package/dist/validations/min-size.validation.d.ts +2 -0
  87. package/dist/validations/not-self-intersecting.validation.d.ts +2 -0
  88. package/dist/validations/point.validation.d.ts +2 -0
  89. package/dist/validations/polygon.validation.d.ts +3 -0
  90. package/e2e/README.md +29 -0
  91. package/e2e/package-lock.json +4274 -0
  92. package/e2e/package.json +26 -0
  93. package/e2e/playwright.config.ts +77 -0
  94. package/e2e/public/favicon.ico +0 -0
  95. package/e2e/public/index.html +53 -0
  96. package/e2e/tests/leaflet.spec.ts +739 -0
  97. package/e2e/tests/setup.ts +198 -0
  98. package/e2e/webpack.config.js +36 -0
  99. package/jest.nocheck.config.ts +17 -0
  100. package/package.json +158 -87
  101. package/readme.gif +0 -0
  102. package/tsconfig.json +25 -12
  103. package/CODE_OF_CONDUCT.md +0 -36
  104. package/CONTRIBUTING.md +0 -17
  105. package/DEVELOPMENT.md +0 -77
  106. package/dist/bundle.js +0 -6
  107. package/dist/bundle.js.LICENSE.txt +0 -4
  108. package/dist/geometry/create-circle.d.ts +0 -6
  109. package/dist/geometry/get-pixel-distance-to-line.d.ts +0 -10
  110. package/dist/geometry/get-pixel-distance.d.ts +0 -7
  111. package/dist/geometry/haversine-distance.d.ts +0 -1
  112. package/dist/geometry/point-in-polygon.d.ts +0 -1
  113. package/dist/geometry/self-intersects.d.ts +0 -2
  114. package/dist/modes/circle.mode.d.ts +0 -18
  115. package/dist/modes/freehand.mode.d.ts +0 -20
  116. package/dist/modes/line-string.mode.d.ts +0 -21
  117. package/dist/modes/point.mode.d.ts +0 -14
  118. package/dist/modes/polygon/behaviors/start-end-point.behavior.d.ts +0 -11
  119. package/dist/modes/polygon.mode.d.ts +0 -21
  120. package/dist/modes/select.mode.d.ts +0 -21
  121. package/dist/modes/static.mode.d.ts +0 -10
  122. package/jest.config.ts +0 -27
@@ -0,0 +1,739 @@
1
+ import { test, expect } from "@playwright/test";
2
+ import {
3
+ changeMode,
4
+ drawTwoClickShape,
5
+ drawRectangularPolygon,
6
+ expectGroupPosition,
7
+ expectPathDimensions,
8
+ expectPaths,
9
+ pageUrl,
10
+ setupMap,
11
+ TestConfigOptions,
12
+ } from "./setup";
13
+
14
+ test.describe("page setup", () => {
15
+ test("loads map", async ({ page }) => {
16
+ await page.goto(pageUrl);
17
+
18
+ // Expect map application to exist
19
+ await expect(page.getByRole("application")).toBeVisible();
20
+ });
21
+
22
+ test("loads UI", async ({ page }) => {
23
+ await page.goto(pageUrl);
24
+
25
+ await expect(page.getByText("Point")).toBeVisible();
26
+ await expect(page.getByText("Linestring")).toBeVisible();
27
+ await expect(page.getByText("Polygon")).toBeVisible();
28
+ await expect(page.getByText("Select")).toBeVisible();
29
+ await expect(page.getByText("Clear")).toBeVisible();
30
+ });
31
+
32
+ test("there are no console errors", async ({ page }) => {
33
+ const errors: string[] = [];
34
+ page.on("console", (msg) => {
35
+ if (msg.type() === "error") {
36
+ errors.push(msg.text());
37
+ }
38
+ });
39
+ await page.goto(pageUrl);
40
+ await expect(page.getByRole("application")).toBeVisible();
41
+
42
+ expect(errors).toEqual([]);
43
+ });
44
+
45
+ test("there are no build issues", async ({ page }) => {
46
+ await page.goto(pageUrl);
47
+ await expect(
48
+ await page.locator("#webpack-dev-server-client-overlay").count(),
49
+ ).toBe(0);
50
+ });
51
+ });
52
+
53
+ test.describe("point mode", () => {
54
+ const mode = "point";
55
+
56
+ test("mode can set and can be used to create a point", async ({ page }) => {
57
+ const mapDiv = await setupMap({ page });
58
+ await changeMode({ page, mode });
59
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
60
+
61
+ await expectPaths({ page, count: 1 });
62
+ });
63
+
64
+ test("mode can set and can be used to create multiple points", async ({
65
+ page,
66
+ }) => {
67
+ const mapDiv = await setupMap({ page });
68
+ await changeMode({ page, mode });
69
+
70
+ await page.mouse.click(mapDiv.width / 4, mapDiv.height / 4);
71
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 3);
72
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
73
+
74
+ await expectPaths({ page, count: 3 });
75
+ });
76
+ });
77
+
78
+ test.describe("linestring mode", () => {
79
+ const mode = "linestring";
80
+
81
+ const options = [
82
+ { name: "", config: undefined },
83
+ {
84
+ name: " with insert coordinates for web mercator projection",
85
+ config: ["insertCoordinates"],
86
+ },
87
+ {
88
+ name: " with insert coordinates for globe projection",
89
+ config: ["insertCoordinatesGlobe"],
90
+ },
91
+ ] as { name: string; config: TestConfigOptions[] }[];
92
+
93
+ for (const { name, config } of options) {
94
+ test(`mode can set and can be used to create a linestring${name}`, async ({
95
+ page,
96
+ }) => {
97
+ const mapDiv = await setupMap({ page, configQueryParam: config });
98
+ await changeMode({ page, mode });
99
+
100
+ await page.mouse.move(mapDiv.width / 2, mapDiv.height / 2);
101
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
102
+ await page.mouse.move(mapDiv.width / 3, mapDiv.height / 3);
103
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 3);
104
+
105
+ // Close
106
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 3);
107
+
108
+ await expectPaths({ page, count: 1 });
109
+ });
110
+
111
+ test(`mode can set and can be used to create a linestring with multiple points${name}`, async ({
112
+ page,
113
+ }) => {
114
+ const mapDiv = await setupMap({ page, configQueryParam: config });
115
+ await changeMode({ page, mode });
116
+
117
+ await page.mouse.move(mapDiv.width / 2, mapDiv.height / 2);
118
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
119
+ await page.mouse.move(mapDiv.width / 3, mapDiv.height / 3);
120
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 3);
121
+
122
+ // Draw coordinate 2
123
+ await page.mouse.move(mapDiv.width / 3, mapDiv.height / 2);
124
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 2);
125
+
126
+ // Draw coordinate 3
127
+ await page.mouse.move(mapDiv.width / 2, mapDiv.height / 3);
128
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 3);
129
+
130
+ // Close
131
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 3);
132
+
133
+ await expectPaths({ page, count: 1 });
134
+ });
135
+
136
+ test(`mode can set and can be used to create a linestring with multiple clicked points${name}`, async ({
137
+ page,
138
+ }) => {
139
+ const mapDiv = await setupMap({ page, configQueryParam: config });
140
+ await changeMode({ page, mode });
141
+
142
+ await page.mouse.move(mapDiv.width / 2, mapDiv.height / 2);
143
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
144
+ await page.mouse.move(mapDiv.width / 3, mapDiv.height / 3);
145
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 3);
146
+
147
+ // Draw coordinate 2
148
+ await page.mouse.move(mapDiv.width / 3, mapDiv.height / 2);
149
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 2);
150
+
151
+ // Draw coordinate 3
152
+ await page.mouse.move(mapDiv.width / 2, mapDiv.height / 3);
153
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 3);
154
+
155
+ // Close
156
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 3);
157
+
158
+ await expectPaths({ page, count: 1 });
159
+ });
160
+
161
+ test(`mode can set and can be used to create multiple linestrings${name}`, async ({
162
+ page,
163
+ }) => {
164
+ const mapDiv = await setupMap({ page, configQueryParam: config });
165
+ await changeMode({ page, mode });
166
+
167
+ // First line
168
+ await page.mouse.move(mapDiv.width / 2, mapDiv.height / 2);
169
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
170
+ await page.mouse.move(mapDiv.width / 3, mapDiv.height / 3);
171
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 3);
172
+
173
+ // One point + one line
174
+ await expectPaths({ page, count: 2 });
175
+
176
+ // Close first line
177
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 3);
178
+
179
+ // One line
180
+ await expectPaths({ page, count: 1 });
181
+
182
+ // Second line
183
+ await page.mouse.move(mapDiv.width / 4, mapDiv.height / 4);
184
+ await page.mouse.click(mapDiv.width / 4, mapDiv.height / 4);
185
+ await page.mouse.move(mapDiv.width / 5, mapDiv.height / 5);
186
+ await page.mouse.click(mapDiv.width / 5, mapDiv.height / 5);
187
+
188
+ // Close second line
189
+ await page.mouse.click(mapDiv.width / 5, mapDiv.height / 5);
190
+
191
+ // Two lines
192
+ await expectPaths({ page, count: 2 });
193
+ });
194
+ }
195
+ });
196
+
197
+ test.describe("polygon mode", () => {
198
+ const mode = "polygon";
199
+
200
+ test("mode can set and can be used to create a polygon", async ({ page }) => {
201
+ const mapDiv = await setupMap({ page });
202
+ await changeMode({ page, mode });
203
+
204
+ // The length of the square sides in pixels
205
+ const sideLength = 100;
206
+
207
+ // Calculating the half of the side length
208
+ const halfLength = sideLength / 2;
209
+
210
+ // Coordinates of the center
211
+ const centerX = mapDiv.width / 2;
212
+ const centerY = mapDiv.height / 2;
213
+
214
+ // Coordinates of the four corners of the square
215
+ const topLeft = { x: centerX - halfLength, y: centerY - halfLength };
216
+ const topRight = { x: centerX + halfLength, y: centerY - halfLength };
217
+ const bottomLeft = { x: centerX - halfLength, y: centerY + halfLength };
218
+ const bottomRight = { x: centerX + halfLength, y: centerY + halfLength };
219
+
220
+ // Perform clicks at each corner
221
+ await page.mouse.click(topLeft.x, topLeft.y);
222
+ await page.mouse.click(topRight.x, topRight.y);
223
+ await page.mouse.click(bottomRight.x, bottomRight.y);
224
+ await page.mouse.click(bottomLeft.x, bottomLeft.y);
225
+
226
+ // Close the square
227
+ await page.mouse.click(bottomLeft.x, bottomLeft.y);
228
+
229
+ // One point + one line
230
+ await expectPaths({ page, count: 1 });
231
+ });
232
+
233
+ test("can use validation setting to prevent maximum size", async ({
234
+ page,
235
+ }) => {
236
+ const mapDiv = await setupMap({
237
+ page,
238
+ configQueryParam: ["validationFailure"],
239
+ });
240
+ await changeMode({ page, mode });
241
+
242
+ // The length of the square sides in pixels
243
+ const sideLength = 100;
244
+
245
+ // Calculating the half of the side length
246
+ const halfLength = sideLength / 2;
247
+
248
+ // Coordinates of the center
249
+ const centerX = mapDiv.width / 2;
250
+ const centerY = mapDiv.height / 2;
251
+
252
+ // Coordinates of the four corners of the square
253
+ const topLeft = { x: centerX - halfLength, y: centerY - halfLength };
254
+ const topRight = { x: centerX + halfLength, y: centerY - halfLength };
255
+ const bottomLeft = { x: centerX - halfLength, y: centerY + halfLength };
256
+ const bottomRight = { x: centerX + halfLength, y: centerY + halfLength };
257
+
258
+ // Perform clicks at each corner
259
+ await page.mouse.click(topLeft.x, topLeft.y);
260
+ await page.mouse.click(topRight.x, topRight.y);
261
+ await page.mouse.click(bottomRight.x, bottomRight.y);
262
+ await page.mouse.click(bottomLeft.x, bottomLeft.y);
263
+
264
+ // Attempt to close the square
265
+ await page.mouse.click(bottomLeft.x, bottomLeft.y);
266
+
267
+ // Square will fail, as triangle will be 705665 square meters, but square will be
268
+ // over the limit of 1000000 square meters.
269
+ await expectPaths({ page, count: 3 });
270
+ });
271
+
272
+ test("can use validation setting to draw underneath maximum size ", async ({
273
+ page,
274
+ }) => {
275
+ const mapDiv = await setupMap({
276
+ page,
277
+ configQueryParam: ["validationSuccess"],
278
+ });
279
+ await changeMode({ page, mode });
280
+
281
+ // The length of the square sides in pixels
282
+ const sideLength = 100;
283
+
284
+ // Calculating the half of the side length
285
+ const halfLength = sideLength / 2;
286
+
287
+ // Coordinates of the center
288
+ const centerX = mapDiv.width / 2;
289
+ const centerY = mapDiv.height / 2;
290
+
291
+ // Coordinates of the four corners of the square
292
+ const topLeft = { x: centerX - halfLength, y: centerY - halfLength };
293
+ const topRight = { x: centerX + halfLength, y: centerY - halfLength };
294
+ const bottomLeft = { x: centerX - halfLength, y: centerY + halfLength };
295
+ const bottomRight = { x: centerX + halfLength, y: centerY + halfLength };
296
+
297
+ // Perform clicks at each corner
298
+ await page.mouse.click(topLeft.x, topLeft.y);
299
+ await page.mouse.click(topRight.x, topRight.y);
300
+ await page.mouse.click(bottomRight.x, bottomRight.y);
301
+ await page.mouse.click(bottomLeft.x, bottomLeft.y);
302
+
303
+ // Attempt to close the square
304
+ await page.mouse.click(bottomLeft.x, bottomLeft.y);
305
+
306
+ // Square will fail, as triangle will be 705665 square meters, but square will be
307
+ // over the limit of 1000000 square meters.
308
+ await expectPaths({ page, count: 1 });
309
+ });
310
+ });
311
+
312
+ test.describe("rectangle mode", () => {
313
+ const mode = "rectangle";
314
+
315
+ test("mode can set and can be used to create a rectangle", async ({
316
+ page,
317
+ }) => {
318
+ const mapDiv = await setupMap({ page });
319
+ await changeMode({ page, mode });
320
+
321
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
322
+ await page.mouse.click(mapDiv.width / 2 + 50, mapDiv.height / 2 + 50);
323
+
324
+ // One point + one line
325
+ await expectPaths({ page, count: 1 });
326
+
327
+ await expectPathDimensions({ page, width: 54, height: 54 }); // Stroke width of 4
328
+ });
329
+ });
330
+
331
+ test.describe("angled rectangle mode", () => {
332
+ const mode = "angled-rectangle";
333
+
334
+ test("mode can set and can be used to create an angled rectangle (horizontal up)", async ({
335
+ page,
336
+ }) => {
337
+ const mapDiv = await setupMap({ page });
338
+ await changeMode({ page, mode });
339
+
340
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
341
+ await page.mouse.move(mapDiv.width / 3, mapDiv.height / 2, { steps: 30 });
342
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 2);
343
+ await page.mouse.move(mapDiv.width / 3 + 50, mapDiv.height / 3 + 50, {
344
+ steps: 30,
345
+ });
346
+ await page.mouse.click(mapDiv.width / 3 + 50, mapDiv.height / 3 + 50);
347
+
348
+ await expectPaths({ page, count: 1 });
349
+
350
+ await expectPathDimensions({ page, width: 217, height: 74 });
351
+ });
352
+
353
+ test("mode can set and can be used to create an angled rectangle (horizontal down)", async ({
354
+ page,
355
+ }) => {
356
+ const mapDiv = await setupMap({ page });
357
+ await changeMode({ page, mode });
358
+
359
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
360
+ await page.mouse.move(mapDiv.width / 3, mapDiv.height / 2, { steps: 30 });
361
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 2);
362
+ await page.mouse.move(mapDiv.width / 3 + 50, mapDiv.height / 3 + 200, {
363
+ steps: 30,
364
+ });
365
+ await page.mouse.click(mapDiv.width / 3 + 50, mapDiv.height / 3 + 200);
366
+
367
+ await expectPaths({ page, count: 1 });
368
+
369
+ await expectPathDimensions({ page, width: 217, height: 84 });
370
+ });
371
+
372
+ test("mode can set and can be used to create an angled (diagonal)", async ({
373
+ page,
374
+ }) => {
375
+ const mapDiv = await setupMap({ page });
376
+ await changeMode({ page, mode });
377
+
378
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
379
+ await page.mouse.move(mapDiv.width / 3, mapDiv.height / 3, { steps: 30 });
380
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 3);
381
+ await page.mouse.move(mapDiv.width / 3 + 150, mapDiv.height / 3 + 150, {
382
+ steps: 30,
383
+ });
384
+ await page.mouse.click(mapDiv.width / 3 + 150, mapDiv.height / 3 + 150);
385
+
386
+ await expectPaths({ page, count: 1 });
387
+
388
+ await expectPathDimensions({ page, width: 245, height: 174 });
389
+ });
390
+
391
+ test("mode can set and can be used to create an angled (diagonal 2)", async ({
392
+ page,
393
+ }) => {
394
+ const mapDiv = await setupMap({ page });
395
+ await changeMode({ page, mode });
396
+
397
+ await page.mouse.click(mapDiv.width / 1.8, mapDiv.height / 1.8);
398
+ await page.mouse.move(mapDiv.width / 2.5, mapDiv.height / 1.3, {
399
+ steps: 30,
400
+ });
401
+ await page.mouse.click(mapDiv.width / 2.5, mapDiv.height / 1.3);
402
+ await page.mouse.move(mapDiv.width / 2.5 + 50, mapDiv.height / 1.3 + 50, {
403
+ steps: 30,
404
+ });
405
+ await page.mouse.click(mapDiv.width / 2.5 + 50, mapDiv.height / 1.3 + 50);
406
+
407
+ await expectPaths({ page, count: 1 });
408
+
409
+ await expectPathDimensions({ page, width: 246, height: 213 });
410
+ });
411
+ });
412
+
413
+ test.describe("circle mode", () => {
414
+ const mode = "circle";
415
+
416
+ test("mode can set and can be used to create a web mercator circle", async ({
417
+ page,
418
+ }) => {
419
+ const mapDiv = await setupMap({ page });
420
+ await changeMode({ page, mode });
421
+
422
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
423
+ await page.mouse.click(mapDiv.width / 2 + 50, mapDiv.height / 2 + 50);
424
+
425
+ // One point + one line
426
+ await expectPaths({ page, count: 1 });
427
+
428
+ await expectPathDimensions({ page, width: 146, height: 146 });
429
+ });
430
+
431
+ test("mode can set and can be used to create a geodesic circle", async ({
432
+ page,
433
+ }) => {
434
+ const mapDiv = await setupMap({ page, configQueryParam: ["globeCircle"] });
435
+ await changeMode({ page, mode });
436
+
437
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
438
+ await page.mouse.click(mapDiv.width / 2 + 50, mapDiv.height / 2 + 50);
439
+
440
+ // One point + one line
441
+ await expectPaths({ page, count: 1 });
442
+
443
+ await expectPathDimensions({ page, width: 146, height: 146 });
444
+ });
445
+ });
446
+
447
+ test.describe("select mode", () => {
448
+ const mode = "select";
449
+
450
+ const options = [
451
+ { name: "in web mercator projection", config: undefined },
452
+ {
453
+ name: "in globe projection",
454
+ config: ["globeSelect"],
455
+ },
456
+ ] as { name: string; config: TestConfigOptions[] }[];
457
+
458
+ for (const { name, config } of options) {
459
+ test(`mode can set and then polygon can be selected and deselected ${name}`, async ({
460
+ page,
461
+ }) => {
462
+ const mapDiv = await setupMap({ page, configQueryParam: config });
463
+
464
+ await changeMode({ page, mode: "polygon" });
465
+ const sideLength = 100;
466
+ const halfLength = sideLength / 2;
467
+ const centerX = mapDiv.width / 2;
468
+ const centerY = mapDiv.height / 2;
469
+ const topLeft = { x: centerX - halfLength, y: centerY - halfLength };
470
+ const topRight = { x: centerX + halfLength, y: centerY - halfLength };
471
+ const bottomLeft = { x: centerX - halfLength, y: centerY + halfLength };
472
+ const bottomRight = { x: centerX + halfLength, y: centerY + halfLength };
473
+ await page.mouse.click(topLeft.x, topLeft.y);
474
+ await page.mouse.click(topRight.x, topRight.y);
475
+ await page.mouse.click(bottomRight.x, bottomRight.y);
476
+ await page.mouse.click(bottomLeft.x, bottomLeft.y);
477
+ await page.mouse.click(bottomLeft.x, bottomLeft.y); // Closed
478
+
479
+ await changeMode({ page, mode });
480
+
481
+ // Select
482
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
483
+ await expectPaths({ page, count: 9 }); // 8 selection points and 1 square
484
+
485
+ // Deselect
486
+ await page.mouse.click(mapDiv.width - 10, mapDiv.height / 2);
487
+ await expectPaths({ page, count: 1 }); // 0 selection points and 1 square
488
+ });
489
+
490
+ test(`selected polygon can be dragged ${name}`, async ({ page }) => {
491
+ const mapDiv = await setupMap({ page, configQueryParam: config });
492
+
493
+ await changeMode({ page, mode: "polygon" });
494
+
495
+ // Draw a rectangle
496
+ const { topLeft } = await drawRectangularPolygon({ mapDiv, page });
497
+
498
+ // Change to select mode
499
+ await changeMode({ page, mode });
500
+
501
+ // Before drag
502
+ const x = topLeft.x - 2;
503
+ const y = topLeft.y - 2;
504
+ await expectGroupPosition({ page, x, y });
505
+
506
+ // Select
507
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
508
+ await expectPaths({ page, count: 9 }); // 8 selection points and 1 square
509
+
510
+ // Drag
511
+ await page.mouse.move(mapDiv.width / 2, mapDiv.height / 2);
512
+ await page.mouse.down();
513
+ await page.mouse.move(mapDiv.width / 2 + 50, mapDiv.height / 2 + 50, {
514
+ steps: 30,
515
+ }); // Steps is required
516
+ await page.mouse.up();
517
+
518
+ await page.mouse.click(mapDiv.width - 10, mapDiv.height / 2);
519
+
520
+ await expectGroupPosition({ page, x: x + 48, y: y + 48 });
521
+ });
522
+
523
+ test(`selected polygon can have individual coordinates dragged ${name}`, async ({
524
+ page,
525
+ }) => {
526
+ const mapDiv = await setupMap({ page, configQueryParam: config });
527
+
528
+ await changeMode({ page, mode: "polygon" });
529
+
530
+ // Draw a rectangle
531
+ const { topLeft } = await drawRectangularPolygon({ mapDiv, page });
532
+
533
+ // Change to select mode
534
+ await changeMode({ page, mode });
535
+
536
+ // Before drag
537
+ const x = topLeft.x - 2;
538
+ const y = topLeft.y - 2;
539
+ await expectGroupPosition({ page, x, y });
540
+
541
+ // Select
542
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
543
+ await expectPaths({ page, count: 9 }); // 8 selection points and 1 square
544
+
545
+ // Drag
546
+ await page.mouse.move(topLeft.x, topLeft.y);
547
+ await page.mouse.down();
548
+ await page.mouse.move(topLeft.x - 50, topLeft.y + 50, { steps: 30 }); // Steps is required
549
+ await page.mouse.up();
550
+
551
+ // Deselect
552
+ await page.mouse.click(mapDiv.width - 10, mapDiv.height / 2);
553
+
554
+ // Dragged the coordinate to the left and down slightly
555
+ await expectGroupPosition({ page, x: 538, y: 308 });
556
+ });
557
+
558
+ test(`selected polygon can have individual coordinates dragged and succeeds when validation succeeds ${name}`, async ({
559
+ page,
560
+ }) => {
561
+ const mapDiv = await setupMap({
562
+ page,
563
+ configQueryParam: config
564
+ ? [...config, "validationSuccess"]
565
+ : ["validationSuccess"],
566
+ });
567
+
568
+ await changeMode({ page, mode: "polygon" });
569
+
570
+ // Draw a rectangle
571
+ const { topLeft } = await drawRectangularPolygon({
572
+ mapDiv,
573
+ page,
574
+ size: "small",
575
+ });
576
+
577
+ // Change to select mode
578
+ await changeMode({ page, mode });
579
+
580
+ // Before drag
581
+ const x = topLeft.x - 2;
582
+ const y = topLeft.y - 2;
583
+ await expectGroupPosition({ page, x, y });
584
+
585
+ // Select
586
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
587
+ // await expectPaths({ page, count: 9 }); // 8 selection points and 1 square
588
+
589
+ // Drag
590
+ await page.mouse.move(topLeft.x, topLeft.y);
591
+ await page.mouse.down();
592
+ await page.mouse.move(topLeft.x - 50, topLeft.y - 50, { steps: 30 });
593
+ await page.mouse.up();
594
+
595
+ // Deselect
596
+ await page.mouse.click(mapDiv.width - 10, mapDiv.height / 2);
597
+
598
+ // We are attempting to dragg right tothe top left corner but it is not getting there
599
+ // because it is capped by the validation. If this was allowed x would be ~90
600
+ await expectGroupPosition({ page, x: 553, y: 273 });
601
+ });
602
+
603
+ test(`selected polygon can have individual coordinates dragged and fail when validation fails ${name}`, async ({
604
+ page,
605
+ }) => {
606
+ const mapDiv = await setupMap({
607
+ page,
608
+ configQueryParam: config
609
+ ? [...config, "validationFailure"]
610
+ : ["validationFailure"],
611
+ });
612
+
613
+ await changeMode({ page, mode: "polygon" });
614
+
615
+ // Draw a rectangle
616
+ const { topLeft } = await drawRectangularPolygon({
617
+ mapDiv,
618
+ page,
619
+ size: "small",
620
+ });
621
+
622
+ // Change to select mode
623
+ await changeMode({ page, mode });
624
+
625
+ // Before drag
626
+ const x = topLeft.x - 2;
627
+ const y = topLeft.y - 2;
628
+ await expectGroupPosition({ page, x, y });
629
+
630
+ // Select
631
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
632
+ // await expectPaths({ page, count: 9 }); // 8 selection points and 1 square
633
+
634
+ // Drag
635
+ await page.mouse.move(topLeft.x, topLeft.y);
636
+ await page.mouse.down();
637
+ await page.mouse.move(0, 0, { steps: 30 });
638
+ await page.mouse.up();
639
+
640
+ // Deselect
641
+ await page.mouse.click(mapDiv.width - 10, mapDiv.height / 2);
642
+
643
+ // We are attempting to dragg right tothe top left corner but it is not getting there
644
+ // because it is capped by the validation. If this was allowed x would be ~90
645
+ await expectGroupPosition({ page, x: 563, y: 301 });
646
+ });
647
+ }
648
+
649
+ test("selected rectangle has it's shape maintained when coordinates are dragged with resizable flag", async ({
650
+ page,
651
+ }) => {
652
+ const mapDiv = await setupMap({ page });
653
+
654
+ await changeMode({ page, mode: "rectangle" });
655
+
656
+ // Draw a rectangle
657
+ const { topLeft } = await drawTwoClickShape({ mapDiv, page });
658
+
659
+ // Change to select mode
660
+ await changeMode({ page, mode });
661
+
662
+ // Before drag
663
+ const x = topLeft.x - 2;
664
+ const y = topLeft.y - 2;
665
+ await expectGroupPosition({ page, x, y });
666
+
667
+ // Select
668
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
669
+ await expectPaths({ page, count: 5 }); // 4 selection points and 1 square
670
+
671
+ // Drag
672
+ await page.mouse.move(topLeft.x, topLeft.y);
673
+ await page.mouse.down();
674
+ await page.mouse.move(topLeft.x - 100, topLeft.y + 100, { steps: 50 }); // Steps is required
675
+ await page.mouse.up();
676
+
677
+ // Deselect
678
+ await page.mouse.click(mapDiv.width - 10, mapDiv.height / 2);
679
+
680
+ // Dragged the square up and to the left
681
+ await expectGroupPosition({ page, x: 490, y: 408 });
682
+ });
683
+
684
+ test("selected circle has it's shape maintained from center origin when coordinates are dragged with resizable flag", async ({
685
+ page,
686
+ }) => {
687
+ const mapDiv = await setupMap({ page });
688
+
689
+ await changeMode({ page, mode: "circle" });
690
+
691
+ // Draw a circle
692
+ await drawTwoClickShape({ mapDiv, page });
693
+
694
+ // Change to select mode
695
+ await changeMode({ page, mode });
696
+
697
+ // Select
698
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
699
+ await expectPaths({ page, count: 65 }); // 4 selection points and 1 square
700
+
701
+ // Drag
702
+ await page.mouse.move(mapDiv.width / 2, mapDiv.height / 2 + 50);
703
+ await page.mouse.down();
704
+ await page.mouse.move(mapDiv.width / 2, mapDiv.height / 2 + 100, {
705
+ steps: 50,
706
+ }); // Steps is required
707
+ await page.mouse.up();
708
+
709
+ // Deselect
710
+ await page.mouse.click(mapDiv.width - 10, mapDiv.height / 2);
711
+
712
+ // Dragged the square up and to the left
713
+ await expectGroupPosition({ page, x: 447, y: 138 });
714
+ });
715
+ });
716
+
717
+ test.describe("clear", () => {
718
+ test("drawn geometries can be cleared correctly", async ({ page }) => {
719
+ const mapDiv = await setupMap({ page });
720
+
721
+ await changeMode({ page, mode: "point" });
722
+ await page.mouse.click(mapDiv.width / 4, mapDiv.height / 4);
723
+
724
+ await changeMode({ page, mode: "linestring" });
725
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
726
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 3);
727
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 3);
728
+
729
+ await changeMode({ page, mode: "polygon" });
730
+ await drawRectangularPolygon({ mapDiv, page });
731
+
732
+ await expectPaths({ page, count: 3 });
733
+
734
+ const button = page.getByText("clear");
735
+ await button.click();
736
+
737
+ await expectPaths({ page, count: 0 });
738
+ });
739
+ });