@abi-software/map-utilities 0.0.0-beta.6 → 1.0.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.
@@ -1,627 +1,627 @@
1
- <template>
2
- <div class="toolbar-container">
3
- <map-svg-sprite-color />
4
- <div class="toolbar-icons">
5
- <el-popover
6
- v-if="showEditModeIcon"
7
- content="Edit Mode"
8
- placement="top"
9
- :teleported="false"
10
- trigger="manual"
11
- width="100"
12
- popper-class="flatmap-popper"
13
- :visible="hoverVisibilities[hoverIndex('editPopover')].value"
14
- ref="editPopover"
15
- >
16
- <template #reference>
17
- <map-svg-icon
18
- icon="comment"
19
- class="icon-button drawEdit"
20
- @click="modeClickEvent('Edit')"
21
- @mouseover="showTooltip(hoverIndex('editPopover'))"
22
- @mouseout="hideTooltip(hoverIndex('editPopover'))"
23
- />
24
- </template>
25
- </el-popover>
26
- <el-popover
27
- v-if="showDeleteModeIcon"
28
- content="Delete Mode"
29
- placement="top"
30
- :teleported="false"
31
- trigger="manual"
32
- width="100"
33
- popper-class="flatmap-popper"
34
- :visible="hoverVisibilities[hoverIndex('deletePopover')].value"
35
- ref="deletePopover"
36
- >
37
- <template #reference>
38
- <map-svg-icon
39
- icon="drawTrash"
40
- class="icon-button drawDelete"
41
- @click="modeClickEvent('Delete')"
42
- @mouseover="showTooltip(hoverIndex('deletePopover'))"
43
- @mouseout="hideTooltip(hoverIndex('deletePopover'))"
44
- />
45
- </template>
46
- </el-popover>
47
- <el-popover
48
- v-if="showDrawPointIcon"
49
- content="Draw Point"
50
- placement="top"
51
- :teleported="false"
52
- trigger="manual"
53
- width="100"
54
- popper-class="flatmap-popper"
55
- :visible="hoverVisibilities[hoverIndex('pointPopover')].value"
56
- ref="pointPopover"
57
- >
58
- <template #reference>
59
- <map-svg-icon
60
- icon="drawPoint"
61
- class="icon-button drawPoint"
62
- @click="toolClickEvent('Point')"
63
- @mouseover="showTooltip(hoverIndex('pointPopover'))"
64
- @mouseout="hideTooltip(hoverIndex('pointPopover'))"
65
- />
66
- </template>
67
- </el-popover>
68
- <el-popover
69
- v-if="showDrawLineStringIcon"
70
- content="Draw LineString"
71
- placement="top"
72
- :teleported="false"
73
- trigger="manual"
74
- width="100"
75
- popper-class="flatmap-popper"
76
- :visible="hoverVisibilities[hoverIndex('lineStringPopover')].value"
77
- ref="drawLinePopover"
78
- >
79
- <template #reference>
80
- <map-svg-icon
81
- icon="drawLine"
82
- class="icon-button drawLineString"
83
- @click="toolClickEvent('LineString')"
84
- @mouseover="showTooltip(hoverIndex('lineStringPopover'))"
85
- @mouseout="hideTooltip(hoverIndex('lineStringPopover'))"
86
- />
87
- </template>
88
- </el-popover>
89
- <el-popover
90
- v-if="showDrawPolygonIcon"
91
- content="Draw Polygon"
92
- placement="top"
93
- :teleported="false"
94
- trigger="manual"
95
- width="100"
96
- popper-class="flatmap-popper"
97
- :visible="hoverVisibilities[hoverIndex('polygonPopover')].value"
98
- ref="polygonPopover"
99
- >
100
- <template #reference>
101
- <map-svg-icon
102
- icon="drawPolygon"
103
- class="icon-button drawPolygon"
104
- @click="toolClickEvent('Polygon')"
105
- @mouseover="showTooltip(hoverIndex('polygonPopover'))"
106
- @mouseout="hideTooltip(hoverIndex('polygonPopover'))"
107
- />
108
- </template>
109
- </el-popover>
110
- <el-popover
111
- v-if="showConnectionIcon"
112
- content="Connectivity"
113
- placement="top"
114
- :teleported="false"
115
- trigger="manual"
116
- width="100"
117
- popper-class="flatmap-popper"
118
- :visible="hoverVisibilities[hoverIndex('connectionPopover')].value"
119
- ref="connectionPopover"
120
- >
121
- <template #reference>
122
- <map-svg-icon
123
- icon="connection"
124
- class="icon-button drawConnection"
125
- @click="connectionClickEvent()"
126
- @mouseover="showTooltip(hoverIndex('connectionPopover'))"
127
- @mouseout="hideTooltip(hoverIndex('connectionPopover'))"
128
- />
129
- </template>
130
- </el-popover>
131
- </div>
132
- <ConnectionDialog
133
- v-if="mapCanvas"
134
- class="connection-dialog"
135
- v-show="connectionDisplay"
136
- :connectionEntry="connectionEntry"
137
- :inDrawing="inDrawing"
138
- :connectionExist="connectionExist"
139
- @dialogDisplay="connectionClickEvent()"
140
- @confirmDrawn="$emit('confirmDrawn', $event)"
141
- @cancelDrawn="$emit('cancelDrawn', $event)"
142
- @featureTooltip="$emit('featureTooltip', $event)"
143
- />
144
- </div>
145
- </template>
146
-
147
- <script>
148
- /* eslint-disable no-alert, no-console */
149
- import { MapSvgIcon, MapSvgSpriteColor } from "@abi-software/svg-sprite";
150
- import "@abi-software/svg-sprite/dist/style.css";
151
-
152
- /**
153
- * @param scopeElement Draggable scope area (Optional)
154
- * @param dragElement Draggable element
155
- */
156
- const draggable = (scopeElement, dragElement) => {
157
- let startX, startY, clickX, clickY, posX, posY;
158
- // reset position in case previous popped up dialog is dragged
159
- dragElement.style.left = "";
160
- dragElement.style.top = "";
161
- // const scopeRect = scopeElement.getBoundingClientRect()
162
- // const dragRect = dragElement.getBoundingClientRect()
163
-
164
- dragElement.addEventListener(
165
- "mousedown",
166
- (e) => {
167
- e.preventDefault();
168
- startX = dragElement.offsetLeft;
169
- startY = dragElement.offsetTop;
170
- clickX = e.clientX;
171
- clickY = e.clientY;
172
-
173
- dragElement.addEventListener("mousemove", drag, false);
174
- document.addEventListener(
175
- "mouseup",
176
- () => {
177
- dragElement.removeEventListener("mousemove", drag, false);
178
- },
179
- false
180
- );
181
- },
182
- false
183
- );
184
-
185
- function drag(e) {
186
- e.preventDefault();
187
- posX = startX - (clickX - e.clientX);
188
- posY = startY - (clickY - e.clientY);
189
- // if (
190
- // (posX > scopeRect.left && ((posX + dragRect.width) < scopeRect.right)) &&
191
- // (posY > scopeRect.top && ((posY + dragRect.height) < scopeRect.bottom))
192
- // ) {
193
- dragElement.style.left = `${posX}px`;
194
- dragElement.style.top = `${posY}px`;
195
- // } else {
196
- // if (posX <= scopeRect.left) {
197
- // dragElement.style.left = '0px';
198
- // } else if (posX + dragRect.width >= scopeRect.right) {
199
- // dragElement.style.left = `${scopeRect.right - dragRect.width}px`;
200
- // }
201
- // if (posY <= scopeRect.top) {
202
- // dragElement.style.top = '0px';
203
- // } else if (posY + dragRect.height >= scopeRect.bottom) {
204
- // dragElement.style.top = `${scopeRect.bottom - dragRect.height}px`;
205
- // }
206
- // }
207
- }
208
- };
209
-
210
- export default {
211
- name: "DrawToolbar",
212
- components: {
213
- MapSvgIcon,
214
- MapSvgSpriteColor,
215
- },
216
- props: {
217
- /**
218
- * Optional
219
- *
220
- * Associated with the Connection dialog.
221
- * This is needed to display the dialog and provides the additional drag capability to the dialog.
222
- *
223
- * e.g.
224
- * :mapCanvas="{
225
- * containerHTML: appRef, // Reference to the map canvas container.
226
- * class: '.maplibregl-canvas', // CSS selector for the map canvas.
227
- * }"
228
- */
229
- mapCanvas: {
230
- type: Object,
231
- default: undefined,
232
- },
233
- /**
234
- * Array of toolbar options to display.
235
- * 'Connection' requires 'LineString' is included in the toolbar options.
236
- */
237
- toolbarOptions: {
238
- type: Array,
239
- default: [
240
- "Edit",
241
- "Delete",
242
- "Point",
243
- "LineString",
244
- "Polygon",
245
- "Connection",
246
- ],
247
- },
248
- /**
249
- * Optional
250
- *
251
- * To update the toolbar icons or filter the features based on the tool type.
252
- * e.g. "All tools", "Point", "LineString", "Polygon" or "None".
253
- */
254
- drawnType: {
255
- type: String,
256
- default: "All tools",
257
- },
258
- activeDrawTool: {
259
- required: true,
260
- },
261
- activeDrawMode: {
262
- required: true,
263
- },
264
- /**
265
- * Optional
266
- *
267
- * Associated with the Connection dialog.
268
- * This will popup a dialog if new feature is drawn and map canvas exists.
269
- */
270
- newlyDrawnEntry: {
271
- type: Object,
272
- default: {},
273
- },
274
- /**
275
- * Optional
276
- *
277
- * Associated with the Connection dialog.
278
- * This will add entries to the dialog.
279
- */
280
- connectionEntry: {
281
- type: Object,
282
- default: {},
283
- },
284
- /**
285
- * Add following to the top hoverVisibilities array to enable tooltips for each icon.
286
- * [
287
- * { value: false, refs: 'toolbarPopover', ref: 'editPopover' },
288
- * { value: false, refs: 'toolbarPopover', ref: 'deletePopover' },
289
- * { value: false, refs: 'toolbarPopover', ref: 'pointPopover' },
290
- * { value: false, refs: 'toolbarPopover', ref: 'lineStringPopover' },
291
- * { value: false, refs: 'toolbarPopover', ref: 'polygonPopover' },
292
- * { value: false, refs: 'toolbarPopover', ref: 'connectionPopover' },
293
- * ]
294
- */
295
- hoverVisibilities: {
296
- type: Array,
297
- required: true,
298
- default: [
299
- { value: false, ref: "editPopover" },
300
- { value: false, ref: "deletePopover" },
301
- { value: false, ref: "pointPopover" },
302
- { value: false, ref: "lineStringPopover" },
303
- { value: false, ref: "polygonPopover" },
304
- { value: false, ref: "connectionPopover" },
305
- ],
306
- },
307
- },
308
- data: function () {
309
- return {
310
- toolbarIcons: [
311
- { name: "Edit", active: false, disabled: false },
312
- { name: "Delete", active: false, disabled: false },
313
- { name: "Point", active: false, disabled: false },
314
- { name: "LineString", active: false, disabled: false },
315
- { name: "Polygon", active: false, disabled: false },
316
- { name: "Connection", active: false, disabled: true },
317
- ],
318
- connectionDisplay: false,
319
- dialogPosition: {
320
- offsetX: 0,
321
- offsetY: 0,
322
- x: undefined,
323
- y: undefined,
324
- },
325
- };
326
- },
327
- computed: {
328
- showAllToolIcons: function () {
329
- return this.drawnType === "All tools" || this.drawnType === "None";
330
- },
331
- showEditModeIcon: function () {
332
- return this.toolbarOptions.includes("Edit");
333
- },
334
- showDeleteModeIcon: function () {
335
- return this.toolbarOptions.includes("Delete");
336
- },
337
- showDrawPointIcon: function () {
338
- return (
339
- this.toolbarOptions.includes("Point") &&
340
- (this.showAllToolIcons || this.drawnType === "Point")
341
- );
342
- },
343
- showDrawLineStringIcon: function () {
344
- return (
345
- this.toolbarOptions.includes("LineString") &&
346
- (this.showAllToolIcons || this.drawnType === "LineString")
347
- );
348
- },
349
- showDrawPolygonIcon: function () {
350
- return (
351
- this.toolbarOptions.includes("Polygon") &&
352
- (this.showAllToolIcons || this.drawnType === "Polygon")
353
- );
354
- },
355
- showConnectionIcon: function () {
356
- return (
357
- this.toolbarOptions.includes("Connection") &&
358
- this.toolbarOptions.includes("LineString") &&
359
- (this.showAllToolIcons || this.drawnType === "LineString")
360
- );
361
- },
362
- inDrawing: function () {
363
- return this.activeDrawTool !== undefined;
364
- },
365
- newlyDrawnExist: function () {
366
- return Object.keys(this.newlyDrawnEntry).length > 0;
367
- },
368
- connectionExist: function () {
369
- return Object.keys(this.connectionEntry).length > 0;
370
- },
371
- },
372
- watch: {
373
- drawnType: function () {
374
- this.disabledToolbarConnectionIcon(true);
375
- },
376
- activeDrawMode: function (value) {
377
- this.updateToolbarIcons(value);
378
- if (value === "Delete") {
379
- this.connectionDisplay = false;
380
- }
381
- },
382
- activeDrawTool: function (value) {
383
- this.updateToolbarIcons(value);
384
- if (!value) {
385
- this.connectionDisplay = false;
386
- }
387
- },
388
- newlyDrawnExist: function (value) {
389
- if (value) {
390
- this.connectionDisplay = true;
391
- }
392
- },
393
- connectionExist: function (value) {
394
- this.disabledToolbarConnectionIcon(!value);
395
- if (!value) {
396
- this.connectionDisplay = false;
397
- }
398
- },
399
- connectionDisplay: function (value) {
400
- this.activeToolbarConnectionIcon(value);
401
- if (value) {
402
- this.dialogCssHacks();
403
- } else {
404
- this.$emit("featureTooltip", undefined);
405
- }
406
- },
407
- dialogPosition: {
408
- handler: function () {
409
- const containerRect = this.$el.getBoundingClientRect();
410
- this.dialogPosition.offsetX = containerRect.x;
411
- this.dialogPosition.offsetY = containerRect.y;
412
- },
413
- deep: true,
414
- once: true,
415
- },
416
- },
417
- methods: {
418
- iconDisabled: function (name) {
419
- return this.toolbarIcons.filter((icon) => icon.name === name)[0].disabled;
420
- },
421
- modeClickEvent: function (type) {
422
- if (!this.iconDisabled(type)) {
423
- const drawMode = this.activeDrawMode === type ? undefined : type;
424
- this.$emit("clickToolbar", "mode", drawMode);
425
- }
426
- },
427
- toolClickEvent: function (type) {
428
- if (!this.iconDisabled(type)) {
429
- const drawTool = this.activeDrawTool === type ? undefined : type;
430
- this.$emit("clickToolbar", "tool", drawTool);
431
- }
432
- },
433
- connectionClickEvent: function () {
434
- if (!this.iconDisabled("Connection") && !this.newlyDrawnExist) {
435
- this.connectionDisplay = !this.connectionDisplay;
436
- }
437
- },
438
- updateToolbarIcons: function (value) {
439
- this.toolbarIcons.map((icon) => {
440
- if (icon.name === value) {
441
- icon.active = true;
442
- } else {
443
- icon.active = false;
444
- }
445
- });
446
- this.toolbarIcons
447
- .filter((icon) => icon.name !== "Connection" && icon.name !== value)
448
- .map((icon) => {
449
- if (value) {
450
- icon.disabled = true;
451
- } else {
452
- icon.disabled = false;
453
- }
454
- });
455
- this.toolbarCssHacks();
456
- },
457
- disabledToolbarConnectionIcon: function (value) {
458
- this.toolbarIcons
459
- .filter((icon) => icon.name === "Connection")
460
- .map((icon) => {
461
- if (value) {
462
- icon.disabled = true;
463
- } else {
464
- icon.disabled = false;
465
- }
466
- // Disable connection icon when delete mode is on
467
- if (this.activeDrawMode === "Delete") {
468
- icon.disabled = true;
469
- }
470
- });
471
- this.toolbarCssHacks();
472
- },
473
- activeToolbarConnectionIcon: function (value) {
474
- this.toolbarIcons
475
- .filter((icon) => icon.name === "Connection")
476
- .map((icon) => {
477
- if (value) {
478
- icon.active = true;
479
- } else {
480
- icon.active = false;
481
- }
482
- });
483
- this.toolbarCssHacks();
484
- },
485
- toolbarCssHacks: function () {
486
- this.$nextTick(() => {
487
- this.toolbarIcons.map((icon) => {
488
- const iconElement = this.$el.querySelector(`.draw${icon.name}`);
489
- if (iconElement) {
490
- if (icon.active) {
491
- iconElement.classList.add("active");
492
- } else {
493
- iconElement.classList.remove("active");
494
- }
495
- if (icon.disabled) {
496
- iconElement.classList.add("disabled");
497
- } else {
498
- iconElement.classList.remove("disabled");
499
- }
500
- }
501
- });
502
- });
503
- },
504
- dialogCssHacks: function () {
505
- this.$nextTick(() => {
506
- const dialog = this.$el.querySelector(".connection-dialog");
507
- draggable(this.mapCanvas.containerHTML, dialog);
508
- // dialog popup at the click position
509
- // slightly change x or y if close to boundary
510
- let posX, posY;
511
- const containerRect =
512
- this.mapCanvas.containerHTML.getBoundingClientRect();
513
- const dialogRect = dialog.getBoundingClientRect();
514
- if (this.dialogPosition.x > containerRect.width / 2) {
515
- posX = this.dialogPosition.x - dialogRect.width;
516
- } else {
517
- posX = this.dialogPosition.x;
518
- }
519
- if (this.dialogPosition.y > containerRect.height / 2) {
520
- posY = this.dialogPosition.y - dialogRect.height;
521
- } else {
522
- posY = this.dialogPosition.y;
523
- }
524
- dialog.style.transform = `translate(${
525
- posX - this.dialogPosition.offsetX
526
- }px, ${posY - this.dialogPosition.offsetY}px)`;
527
- });
528
- },
529
- hoverIndex: function (value) {
530
- return this.hoverVisibilities.findIndex((item) => item.ref === value);
531
- },
532
- showTooltip: function (tooltipNumber) {
533
- this.$emit("showTooltip", tooltipNumber);
534
- },
535
- hideTooltip: function (tooltipNumber) {
536
- this.$emit("hideTooltip", tooltipNumber);
537
- },
538
- dialogPopUpPositionHandler: function (e) {
539
- e.preventDefault();
540
- this.dialogPosition.x = e.clientX;
541
- this.dialogPosition.y = e.clientY;
542
- if (this.activeDrawTool === "Point") {
543
- this.dialogCssHacks();
544
- }
545
- },
546
- },
547
- mounted: function () {
548
- this.$nextTick(() => {
549
- this.toolbarCssHacks();
550
- if (this.mapCanvas) {
551
- this.mapCanvas.containerHTML
552
- .querySelector(this.mapCanvas.class)
553
- .addEventListener("click", this.dialogPopUpPositionHandler, false);
554
- }
555
- });
556
- },
557
- destroyed: function () {
558
- if (this.mapCanvas) {
559
- this.mapCanvas.containerHTML
560
- .querySelector(this.mapCanvas.class)
561
- .removeEventListener("click", this.dialogPopUpPositionHandler, false);
562
- }
563
- },
564
- };
565
- </script>
566
-
567
- <style lang="scss" scoped>
568
- .toolbar-icons {
569
- background-color: var(--el-color-primary-light-9);
570
- padding: 4px 4px 2px 4px;
571
- border-style: solid;
572
- border-color: var(--el-color-primary-light-5);
573
- border-radius: 1rem;
574
- position: absolute;
575
- right: calc(50vw - 100px);
576
- bottom: 16px;
577
- z-index: 10;
578
- }
579
-
580
- .drawEdit,
581
- .drawDelete,
582
- .drawPoint,
583
- .drawLineString,
584
- .drawPolygon,
585
- .drawConnection {
586
- padding: 4px;
587
- color: var(--el-color-primary-light-5) !important;
588
- }
589
-
590
- .icon-button {
591
- height: 24px !important;
592
- width: 24px !important;
593
- color: $app-primary-color;
594
-
595
- &.open-map-button {
596
- margin-bottom: 4px;
597
- }
598
-
599
- &:hover {
600
- cursor: pointer;
601
- }
602
- }
603
-
604
- .active {
605
- color: var(--el-color-primary) !important;
606
- }
607
-
608
- .disabled {
609
- color: #dddddd !important;
610
- cursor: not-allowed !important;
611
- }
612
-
613
- .connection-dialog {
614
- position: absolute;
615
- z-index: 10;
616
- cursor: move;
617
- }
618
- </style>
619
-
620
- <style lang="scss">
621
- .toolbar-container {
622
- --el-color-primary: #8300bf;
623
- --el-color-primary-light-5: #cd99e5;
624
- --el-color-primary-light-9: #f3e6f9;
625
- --el-color-primary-dark-2: var(--el-color-primary);
626
- }
627
- </style>
1
+ <template>
2
+ <div class="toolbar-container">
3
+ <map-svg-sprite-color />
4
+ <div class="toolbar-icons">
5
+ <el-popover
6
+ v-if="showEditModeIcon"
7
+ content="Edit Mode"
8
+ placement="top"
9
+ :teleported="false"
10
+ trigger="manual"
11
+ width="100"
12
+ popper-class="flatmap-popper"
13
+ :visible="hoverVisibilities[hoverIndex('editPopover')].value"
14
+ ref="editPopover"
15
+ >
16
+ <template #reference>
17
+ <map-svg-icon
18
+ icon="comment"
19
+ class="icon-button drawEdit"
20
+ @click="modeClickEvent('Edit')"
21
+ @mouseover="showTooltip(hoverIndex('editPopover'))"
22
+ @mouseout="hideTooltip(hoverIndex('editPopover'))"
23
+ />
24
+ </template>
25
+ </el-popover>
26
+ <el-popover
27
+ v-if="showDeleteModeIcon"
28
+ content="Delete Mode"
29
+ placement="top"
30
+ :teleported="false"
31
+ trigger="manual"
32
+ width="100"
33
+ popper-class="flatmap-popper"
34
+ :visible="hoverVisibilities[hoverIndex('deletePopover')].value"
35
+ ref="deletePopover"
36
+ >
37
+ <template #reference>
38
+ <map-svg-icon
39
+ icon="drawTrash"
40
+ class="icon-button drawDelete"
41
+ @click="modeClickEvent('Delete')"
42
+ @mouseover="showTooltip(hoverIndex('deletePopover'))"
43
+ @mouseout="hideTooltip(hoverIndex('deletePopover'))"
44
+ />
45
+ </template>
46
+ </el-popover>
47
+ <el-popover
48
+ v-if="showDrawPointIcon"
49
+ content="Draw Point"
50
+ placement="top"
51
+ :teleported="false"
52
+ trigger="manual"
53
+ width="100"
54
+ popper-class="flatmap-popper"
55
+ :visible="hoverVisibilities[hoverIndex('pointPopover')].value"
56
+ ref="pointPopover"
57
+ >
58
+ <template #reference>
59
+ <map-svg-icon
60
+ icon="drawPoint"
61
+ class="icon-button drawPoint"
62
+ @click="toolClickEvent('Point')"
63
+ @mouseover="showTooltip(hoverIndex('pointPopover'))"
64
+ @mouseout="hideTooltip(hoverIndex('pointPopover'))"
65
+ />
66
+ </template>
67
+ </el-popover>
68
+ <el-popover
69
+ v-if="showDrawLineStringIcon"
70
+ content="Draw LineString"
71
+ placement="top"
72
+ :teleported="false"
73
+ trigger="manual"
74
+ width="100"
75
+ popper-class="flatmap-popper"
76
+ :visible="hoverVisibilities[hoverIndex('lineStringPopover')].value"
77
+ ref="drawLinePopover"
78
+ >
79
+ <template #reference>
80
+ <map-svg-icon
81
+ icon="drawLine"
82
+ class="icon-button drawLineString"
83
+ @click="toolClickEvent('LineString')"
84
+ @mouseover="showTooltip(hoverIndex('lineStringPopover'))"
85
+ @mouseout="hideTooltip(hoverIndex('lineStringPopover'))"
86
+ />
87
+ </template>
88
+ </el-popover>
89
+ <el-popover
90
+ v-if="showDrawPolygonIcon"
91
+ content="Draw Polygon"
92
+ placement="top"
93
+ :teleported="false"
94
+ trigger="manual"
95
+ width="100"
96
+ popper-class="flatmap-popper"
97
+ :visible="hoverVisibilities[hoverIndex('polygonPopover')].value"
98
+ ref="polygonPopover"
99
+ >
100
+ <template #reference>
101
+ <map-svg-icon
102
+ icon="drawPolygon"
103
+ class="icon-button drawPolygon"
104
+ @click="toolClickEvent('Polygon')"
105
+ @mouseover="showTooltip(hoverIndex('polygonPopover'))"
106
+ @mouseout="hideTooltip(hoverIndex('polygonPopover'))"
107
+ />
108
+ </template>
109
+ </el-popover>
110
+ <el-popover
111
+ v-if="showConnectionIcon"
112
+ content="Connectivity"
113
+ placement="top"
114
+ :teleported="false"
115
+ trigger="manual"
116
+ width="100"
117
+ popper-class="flatmap-popper"
118
+ :visible="hoverVisibilities[hoverIndex('connectionPopover')].value"
119
+ ref="connectionPopover"
120
+ >
121
+ <template #reference>
122
+ <map-svg-icon
123
+ icon="connection"
124
+ class="icon-button drawConnection"
125
+ @click="connectionClickEvent()"
126
+ @mouseover="showTooltip(hoverIndex('connectionPopover'))"
127
+ @mouseout="hideTooltip(hoverIndex('connectionPopover'))"
128
+ />
129
+ </template>
130
+ </el-popover>
131
+ </div>
132
+ <ConnectionDialog
133
+ v-if="mapCanvas"
134
+ class="connection-dialog"
135
+ v-show="connectionDisplay"
136
+ :connectionEntry="connectionEntry"
137
+ :inDrawing="inDrawing"
138
+ :connectionExist="connectionExist"
139
+ @dialogDisplay="connectionClickEvent()"
140
+ @confirmDrawn="$emit('confirmDrawn', $event)"
141
+ @cancelDrawn="$emit('cancelDrawn', $event)"
142
+ @featureTooltip="$emit('featureTooltip', $event)"
143
+ />
144
+ </div>
145
+ </template>
146
+
147
+ <script>
148
+ /* eslint-disable no-alert, no-console */
149
+ import { MapSvgIcon, MapSvgSpriteColor } from "@abi-software/svg-sprite";
150
+ import "@abi-software/svg-sprite/dist/style.css";
151
+
152
+ /**
153
+ * @param scopeElement Draggable scope area (Optional)
154
+ * @param dragElement Draggable element
155
+ */
156
+ const draggable = (scopeElement, dragElement) => {
157
+ let startX, startY, clickX, clickY, posX, posY;
158
+ // reset position in case previous popped up dialog is dragged
159
+ dragElement.style.left = "";
160
+ dragElement.style.top = "";
161
+ // const scopeRect = scopeElement.getBoundingClientRect()
162
+ // const dragRect = dragElement.getBoundingClientRect()
163
+
164
+ dragElement.addEventListener(
165
+ "mousedown",
166
+ (e) => {
167
+ e.preventDefault();
168
+ startX = dragElement.offsetLeft;
169
+ startY = dragElement.offsetTop;
170
+ clickX = e.clientX;
171
+ clickY = e.clientY;
172
+
173
+ dragElement.addEventListener("mousemove", drag, false);
174
+ document.addEventListener(
175
+ "mouseup",
176
+ () => {
177
+ dragElement.removeEventListener("mousemove", drag, false);
178
+ },
179
+ false
180
+ );
181
+ },
182
+ false
183
+ );
184
+
185
+ function drag(e) {
186
+ e.preventDefault();
187
+ posX = startX - (clickX - e.clientX);
188
+ posY = startY - (clickY - e.clientY);
189
+ // if (
190
+ // (posX > scopeRect.left && ((posX + dragRect.width) < scopeRect.right)) &&
191
+ // (posY > scopeRect.top && ((posY + dragRect.height) < scopeRect.bottom))
192
+ // ) {
193
+ dragElement.style.left = `${posX}px`;
194
+ dragElement.style.top = `${posY}px`;
195
+ // } else {
196
+ // if (posX <= scopeRect.left) {
197
+ // dragElement.style.left = '0px';
198
+ // } else if (posX + dragRect.width >= scopeRect.right) {
199
+ // dragElement.style.left = `${scopeRect.right - dragRect.width}px`;
200
+ // }
201
+ // if (posY <= scopeRect.top) {
202
+ // dragElement.style.top = '0px';
203
+ // } else if (posY + dragRect.height >= scopeRect.bottom) {
204
+ // dragElement.style.top = `${scopeRect.bottom - dragRect.height}px`;
205
+ // }
206
+ // }
207
+ }
208
+ };
209
+
210
+ export default {
211
+ name: "DrawToolbar",
212
+ components: {
213
+ MapSvgIcon,
214
+ MapSvgSpriteColor,
215
+ },
216
+ props: {
217
+ /**
218
+ * Optional
219
+ *
220
+ * Associated with the Connection dialog.
221
+ * This is needed to display the dialog and provides the additional drag capability to the dialog.
222
+ *
223
+ * e.g.
224
+ * :mapCanvas="{
225
+ * containerHTML: appRef, // Reference to the map canvas container.
226
+ * class: '.maplibregl-canvas', // CSS selector for the map canvas.
227
+ * }"
228
+ */
229
+ mapCanvas: {
230
+ type: Object,
231
+ default: undefined,
232
+ },
233
+ /**
234
+ * Array of toolbar options to display.
235
+ * 'Connection' requires 'LineString' is included in the toolbar options.
236
+ */
237
+ toolbarOptions: {
238
+ type: Array,
239
+ default: [
240
+ "Edit",
241
+ "Delete",
242
+ "Point",
243
+ "LineString",
244
+ "Polygon",
245
+ "Connection",
246
+ ],
247
+ },
248
+ /**
249
+ * Optional
250
+ *
251
+ * To update the toolbar icons or filter the features based on the tool type.
252
+ * e.g. "All tools", "Point", "LineString", "Polygon" or "None".
253
+ */
254
+ drawnType: {
255
+ type: String,
256
+ default: "All tools",
257
+ },
258
+ activeDrawTool: {
259
+ required: true,
260
+ },
261
+ activeDrawMode: {
262
+ required: true,
263
+ },
264
+ /**
265
+ * Optional
266
+ *
267
+ * Associated with the Connection dialog.
268
+ * This will popup a dialog if new feature is drawn and map canvas exists.
269
+ */
270
+ newlyDrawnEntry: {
271
+ type: Object,
272
+ default: {},
273
+ },
274
+ /**
275
+ * Optional
276
+ *
277
+ * Associated with the Connection dialog.
278
+ * This will add entries to the dialog.
279
+ */
280
+ connectionEntry: {
281
+ type: Object,
282
+ default: {},
283
+ },
284
+ /**
285
+ * Add following to the top hoverVisibilities array to enable tooltips for each icon.
286
+ * [
287
+ * { value: false, refs: 'toolbarPopover', ref: 'editPopover' },
288
+ * { value: false, refs: 'toolbarPopover', ref: 'deletePopover' },
289
+ * { value: false, refs: 'toolbarPopover', ref: 'pointPopover' },
290
+ * { value: false, refs: 'toolbarPopover', ref: 'lineStringPopover' },
291
+ * { value: false, refs: 'toolbarPopover', ref: 'polygonPopover' },
292
+ * { value: false, refs: 'toolbarPopover', ref: 'connectionPopover' },
293
+ * ]
294
+ */
295
+ hoverVisibilities: {
296
+ type: Array,
297
+ required: true,
298
+ default: [
299
+ { value: false, ref: "editPopover" },
300
+ { value: false, ref: "deletePopover" },
301
+ { value: false, ref: "pointPopover" },
302
+ { value: false, ref: "lineStringPopover" },
303
+ { value: false, ref: "polygonPopover" },
304
+ { value: false, ref: "connectionPopover" },
305
+ ],
306
+ },
307
+ },
308
+ data: function () {
309
+ return {
310
+ toolbarIcons: [
311
+ { name: "Edit", active: false, disabled: false },
312
+ { name: "Delete", active: false, disabled: false },
313
+ { name: "Point", active: false, disabled: false },
314
+ { name: "LineString", active: false, disabled: false },
315
+ { name: "Polygon", active: false, disabled: false },
316
+ { name: "Connection", active: false, disabled: true },
317
+ ],
318
+ connectionDisplay: false,
319
+ dialogPosition: {
320
+ offsetX: 0,
321
+ offsetY: 0,
322
+ x: undefined,
323
+ y: undefined,
324
+ },
325
+ };
326
+ },
327
+ computed: {
328
+ showAllToolIcons: function () {
329
+ return this.drawnType === "All tools" || this.drawnType === "None";
330
+ },
331
+ showEditModeIcon: function () {
332
+ return this.toolbarOptions.includes("Edit");
333
+ },
334
+ showDeleteModeIcon: function () {
335
+ return this.toolbarOptions.includes("Delete");
336
+ },
337
+ showDrawPointIcon: function () {
338
+ return (
339
+ this.toolbarOptions.includes("Point") &&
340
+ (this.showAllToolIcons || this.drawnType === "Point")
341
+ );
342
+ },
343
+ showDrawLineStringIcon: function () {
344
+ return (
345
+ this.toolbarOptions.includes("LineString") &&
346
+ (this.showAllToolIcons || this.drawnType === "LineString")
347
+ );
348
+ },
349
+ showDrawPolygonIcon: function () {
350
+ return (
351
+ this.toolbarOptions.includes("Polygon") &&
352
+ (this.showAllToolIcons || this.drawnType === "Polygon")
353
+ );
354
+ },
355
+ showConnectionIcon: function () {
356
+ return (
357
+ this.toolbarOptions.includes("Connection") &&
358
+ this.toolbarOptions.includes("LineString") &&
359
+ (this.showAllToolIcons || this.drawnType === "LineString")
360
+ );
361
+ },
362
+ inDrawing: function () {
363
+ return this.activeDrawTool !== undefined;
364
+ },
365
+ newlyDrawnExist: function () {
366
+ return Object.keys(this.newlyDrawnEntry).length > 0;
367
+ },
368
+ connectionExist: function () {
369
+ return Object.keys(this.connectionEntry).length > 0;
370
+ },
371
+ },
372
+ watch: {
373
+ drawnType: function () {
374
+ this.disabledToolbarConnectionIcon(true);
375
+ },
376
+ activeDrawMode: function (value) {
377
+ this.updateToolbarIcons(value);
378
+ if (value === "Delete") {
379
+ this.connectionDisplay = false;
380
+ }
381
+ },
382
+ activeDrawTool: function (value) {
383
+ this.updateToolbarIcons(value);
384
+ if (!value) {
385
+ this.connectionDisplay = false;
386
+ }
387
+ },
388
+ newlyDrawnExist: function (value) {
389
+ if (value) {
390
+ this.connectionDisplay = true;
391
+ }
392
+ },
393
+ connectionExist: function (value) {
394
+ this.disabledToolbarConnectionIcon(!value);
395
+ if (!value) {
396
+ this.connectionDisplay = false;
397
+ }
398
+ },
399
+ connectionDisplay: function (value) {
400
+ this.activeToolbarConnectionIcon(value);
401
+ if (value) {
402
+ this.dialogCssHacks();
403
+ } else {
404
+ this.$emit("featureTooltip", undefined);
405
+ }
406
+ },
407
+ dialogPosition: {
408
+ handler: function () {
409
+ const containerRect = this.$el.getBoundingClientRect();
410
+ this.dialogPosition.offsetX = containerRect.x;
411
+ this.dialogPosition.offsetY = containerRect.y;
412
+ },
413
+ deep: true,
414
+ once: true,
415
+ },
416
+ },
417
+ methods: {
418
+ iconDisabled: function (name) {
419
+ return this.toolbarIcons.filter((icon) => icon.name === name)[0].disabled;
420
+ },
421
+ modeClickEvent: function (type) {
422
+ if (!this.iconDisabled(type)) {
423
+ const drawMode = this.activeDrawMode === type ? undefined : type;
424
+ this.$emit("clickToolbar", "mode", drawMode);
425
+ }
426
+ },
427
+ toolClickEvent: function (type) {
428
+ if (!this.iconDisabled(type)) {
429
+ const drawTool = this.activeDrawTool === type ? undefined : type;
430
+ this.$emit("clickToolbar", "tool", drawTool);
431
+ }
432
+ },
433
+ connectionClickEvent: function () {
434
+ if (!this.iconDisabled("Connection") && !this.newlyDrawnExist) {
435
+ this.connectionDisplay = !this.connectionDisplay;
436
+ }
437
+ },
438
+ updateToolbarIcons: function (value) {
439
+ this.toolbarIcons.map((icon) => {
440
+ if (icon.name === value) {
441
+ icon.active = true;
442
+ } else {
443
+ icon.active = false;
444
+ }
445
+ });
446
+ this.toolbarIcons
447
+ .filter((icon) => icon.name !== "Connection" && icon.name !== value)
448
+ .map((icon) => {
449
+ if (value) {
450
+ icon.disabled = true;
451
+ } else {
452
+ icon.disabled = false;
453
+ }
454
+ });
455
+ this.toolbarCssHacks();
456
+ },
457
+ disabledToolbarConnectionIcon: function (value) {
458
+ this.toolbarIcons
459
+ .filter((icon) => icon.name === "Connection")
460
+ .map((icon) => {
461
+ if (value) {
462
+ icon.disabled = true;
463
+ } else {
464
+ icon.disabled = false;
465
+ }
466
+ // Disable connection icon when delete mode is on
467
+ if (this.activeDrawMode === "Delete") {
468
+ icon.disabled = true;
469
+ }
470
+ });
471
+ this.toolbarCssHacks();
472
+ },
473
+ activeToolbarConnectionIcon: function (value) {
474
+ this.toolbarIcons
475
+ .filter((icon) => icon.name === "Connection")
476
+ .map((icon) => {
477
+ if (value) {
478
+ icon.active = true;
479
+ } else {
480
+ icon.active = false;
481
+ }
482
+ });
483
+ this.toolbarCssHacks();
484
+ },
485
+ toolbarCssHacks: function () {
486
+ this.$nextTick(() => {
487
+ this.toolbarIcons.map((icon) => {
488
+ const iconElement = this.$el.querySelector(`.draw${icon.name}`);
489
+ if (iconElement) {
490
+ if (icon.active) {
491
+ iconElement.classList.add("active");
492
+ } else {
493
+ iconElement.classList.remove("active");
494
+ }
495
+ if (icon.disabled) {
496
+ iconElement.classList.add("disabled");
497
+ } else {
498
+ iconElement.classList.remove("disabled");
499
+ }
500
+ }
501
+ });
502
+ });
503
+ },
504
+ dialogCssHacks: function () {
505
+ this.$nextTick(() => {
506
+ const dialog = this.$el.querySelector(".connection-dialog");
507
+ draggable(this.mapCanvas.containerHTML, dialog);
508
+ // dialog popup at the click position
509
+ // slightly change x or y if close to boundary
510
+ let posX, posY;
511
+ const containerRect =
512
+ this.mapCanvas.containerHTML.getBoundingClientRect();
513
+ const dialogRect = dialog.getBoundingClientRect();
514
+ if (this.dialogPosition.x > containerRect.width / 2) {
515
+ posX = this.dialogPosition.x - dialogRect.width;
516
+ } else {
517
+ posX = this.dialogPosition.x;
518
+ }
519
+ if (this.dialogPosition.y > containerRect.height / 2) {
520
+ posY = this.dialogPosition.y - dialogRect.height;
521
+ } else {
522
+ posY = this.dialogPosition.y;
523
+ }
524
+ dialog.style.transform = `translate(${
525
+ posX - this.dialogPosition.offsetX
526
+ }px, ${posY - this.dialogPosition.offsetY}px)`;
527
+ });
528
+ },
529
+ hoverIndex: function (value) {
530
+ return this.hoverVisibilities.findIndex((item) => item.ref === value);
531
+ },
532
+ showTooltip: function (tooltipNumber) {
533
+ this.$emit("showTooltip", tooltipNumber);
534
+ },
535
+ hideTooltip: function (tooltipNumber) {
536
+ this.$emit("hideTooltip", tooltipNumber);
537
+ },
538
+ dialogPopUpPositionHandler: function (e) {
539
+ e.preventDefault();
540
+ this.dialogPosition.x = e.clientX;
541
+ this.dialogPosition.y = e.clientY;
542
+ if (this.activeDrawTool === "Point") {
543
+ this.dialogCssHacks();
544
+ }
545
+ },
546
+ },
547
+ mounted: function () {
548
+ this.$nextTick(() => {
549
+ this.toolbarCssHacks();
550
+ if (this.mapCanvas) {
551
+ this.mapCanvas.containerHTML
552
+ .querySelector(this.mapCanvas.class)
553
+ .addEventListener("click", this.dialogPopUpPositionHandler, false);
554
+ }
555
+ });
556
+ },
557
+ destroyed: function () {
558
+ if (this.mapCanvas) {
559
+ this.mapCanvas.containerHTML
560
+ .querySelector(this.mapCanvas.class)
561
+ .removeEventListener("click", this.dialogPopUpPositionHandler, false);
562
+ }
563
+ },
564
+ };
565
+ </script>
566
+
567
+ <style lang="scss" scoped>
568
+ .toolbar-icons {
569
+ background-color: var(--el-color-primary-light-9);
570
+ padding: 4px 4px 2px 4px;
571
+ border-style: solid;
572
+ border-color: var(--el-color-primary-light-5);
573
+ border-radius: 1rem;
574
+ position: absolute;
575
+ right: calc(50vw - 100px);
576
+ bottom: 16px;
577
+ z-index: 10;
578
+ }
579
+
580
+ .drawEdit,
581
+ .drawDelete,
582
+ .drawPoint,
583
+ .drawLineString,
584
+ .drawPolygon,
585
+ .drawConnection {
586
+ padding: 4px;
587
+ color: var(--el-color-primary-light-5) !important;
588
+ }
589
+
590
+ .icon-button {
591
+ height: 24px !important;
592
+ width: 24px !important;
593
+ color: $app-primary-color;
594
+
595
+ &.open-map-button {
596
+ margin-bottom: 4px;
597
+ }
598
+
599
+ &:hover {
600
+ cursor: pointer;
601
+ }
602
+ }
603
+
604
+ .active {
605
+ color: var(--el-color-primary) !important;
606
+ }
607
+
608
+ .disabled {
609
+ color: #dddddd !important;
610
+ cursor: not-allowed !important;
611
+ }
612
+
613
+ .connection-dialog {
614
+ position: absolute;
615
+ z-index: 10;
616
+ cursor: move;
617
+ }
618
+ </style>
619
+
620
+ <style lang="scss">
621
+ .toolbar-container {
622
+ --el-color-primary: #8300bf;
623
+ --el-color-primary-light-5: #cd99e5;
624
+ --el-color-primary-light-9: #f3e6f9;
625
+ --el-color-primary-dark-2: var(--el-color-primary);
626
+ }
627
+ </style>