1
+ <template >
2
+ <FormKit v-model =" points" name =" points" placeholder =" optional" label =" Max-Y" type =" hidden" />
3
+ <MapView id =" map" :zoom =" 8" @click =" addPoint" >
4
+ <l-polygon :lat-lngs =" latLngs" color =" #41b782" :fill =" true" :fill-opacity =" 0.5" fill-color =" #41b782" />
5
+ <MapDraggableMarker v-for =" point, i in points" :key =" i" :pos =" point" @dragend =" updatePoint(i, $event)" />
6
+ </MapView >
7
+ </template >
8
+
9
+ <script lang="ts" setup>
10
+ import { LPolygon } from ' @vue-leaflet/vue-leaflet' ;
11
+ import { minBy } from ' lodash-es' ;
12
+ import type { FlatPoint , PosFragment } from ' ~/graphql/generated' ;
13
+
14
+ const context = useMap ()
15
+
16
+ const props = defineProps <{
17
+ initial? : FlatPoint []
18
+ }>()
19
+
20
+ const points = ref <FlatPoint []>(props .initial ?? [])
21
+
22
+ const latLngs = computed (() => points .value .map (it => toMapPos (context .value ! .map , it )))
23
+
24
+ function distance(a : FlatPoint , b : FlatPoint ) {
25
+ return Math .sqrt ((a .x - b .x ) ** 2 + (a .z - b .z ) ** 2 )
26
+ }
27
+
28
+ function findClosest(point : FlatPoint , between : FlatPoint []) {
29
+ const min = minBy (between , it => distance (point , it ))
30
+ return min && between .indexOf (min )
31
+ }
32
+
33
+ function addPoint(pos : PosFragment ) {
34
+ const { x, z } = roundPos (pos )
35
+ const current = points .value
36
+ const closest = findClosest ({ x , z }, current )
37
+ if (notNull (closest )) {
38
+ const neighbours = [current [(closest - 1 + current .length ) % current .length ], current [(closest + 1 ) % current .length ]]
39
+ const closestNeighbour = findClosest ({ x , z }, neighbours )!
40
+
41
+ const newPoints = [... current ]
42
+ if (closestNeighbour === 0 ) {
43
+ newPoints .splice (closest , 0 , { x , z })
44
+ } else {
45
+ newPoints .splice ((closest + 1 ) % current .length , 0 , { x , z })
46
+ }
47
+
48
+ points .value = newPoints
49
+ } else {
50
+ points .value = [... points .value , { x , z }]
51
+ }
52
+ }
53
+
54
+ function updatePoint(index : number , { x , z }: PosFragment ) {
55
+ const newPoints = [... points .value ]
56
+ newPoints [index ] = roundPos ({ x , z })
57
+ points .value = newPoints .map (it => {
58
+ const { x, z } = roundPos (it )
59
+ return { x , z }
60
+ })
61
+ }
62
+ </script >
63
+
64
+ <style lang="scss" scoped>
65
+ #map {
66
+ width : 100% ;
67
+ aspect-ratio : 1 / 1 ;
68
+ max-height : 500px ;
69
+ }
70
+ </style >
0 commit comments