@rural-environmental-registry/map_component 1.0.0 → 1.2.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.
Files changed (71) hide show
  1. package/README.md +444 -0
  2. package/dist/constants/coordinatePanel.d.ts +1 -1
  3. package/dist/handlers/drawingControl.d.ts +0 -1
  4. package/dist/handlers/mapHandler.d.ts +8 -3
  5. package/dist/handlers/mapToolsHandler.d.ts +39 -0
  6. package/dist/handlers/measureToolsHandler.d.ts +51 -0
  7. package/dist/handlers/memorialButtonControl.d.ts +19 -0
  8. package/dist/handlers/toolsConstants.d.ts +3 -0
  9. package/dist/index.css +1 -1
  10. package/dist/index.d.ts +2 -0
  11. package/dist/index.mjs +32914 -25131
  12. package/dist/types/index.d.ts +69 -0
  13. package/dist/utils/areaCalculator.d.ts +3 -0
  14. package/dist/utils/drawingPathOptions.d.ts +8 -0
  15. package/dist/utils/geometryCalculator.d.ts +13 -0
  16. package/dist/utils/geometryFileParseResult.d.ts +8 -0
  17. package/dist/utils/memorialLayer.d.ts +3 -0
  18. package/dist/utils/menuHistory.d.ts +8 -0
  19. package/dist/utils/normalizeGeoJsonToFeatures.d.ts +2 -0
  20. package/dist/utils/parseGeoJsonFile.d.ts +2 -0
  21. package/dist/utils/parseKmlFile.d.ts +2 -0
  22. package/dist/utils/parseShapefileZip.d.ts +3 -0
  23. package/dist/utils/stableMarker.d.ts +15 -0
  24. package/dist/utils/validateImportedPolygonGeometry.d.ts +9 -0
  25. package/package.json +22 -4
  26. package/src/assets/icons/file-import-regular-full-gray.svg +1 -0
  27. package/src/assets/icons/file-lines-regular-full-gray.svg +1 -0
  28. package/src/assets/icons/layer-icon.svg +3 -0
  29. package/src/assets/icons/loading.gif +0 -0
  30. package/src/assets/icons/marker-icon.svg +1 -0
  31. package/src/assets/icons/measure-icon.svg +5 -0
  32. package/src/assets/layers/mapLayers.json +16 -0
  33. package/src/assets/main.css +187 -0
  34. package/src/assets/styles/element-plus.css +25 -0
  35. package/src/assets/styles/layers-menu.css +95 -0
  36. package/src/assets/styles/leaflet.css +361 -0
  37. package/src/components/MapDPG.vue +302 -0
  38. package/src/components/coordinate/CoordinatePanel.vue +1206 -0
  39. package/src/components/fa-icon/FontAwesomeIcon.vue +44 -0
  40. package/src/components/loading/Loading.vue +25 -0
  41. package/src/components/map/LeafletMap.vue +183 -0
  42. package/src/components/menu/ChildMenu.vue +112 -0
  43. package/src/components/menu/LayerMenu.vue +294 -0
  44. package/src/components/menu/ParentMenu.vue +132 -0
  45. package/src/constants/coordinatePanel.ts +68 -0
  46. package/src/handlers/constants.ts +35 -0
  47. package/src/handlers/drawingControl.ts +143 -0
  48. package/src/handlers/mapHandler.ts +124 -0
  49. package/src/handlers/mapToolsHandler.ts +281 -0
  50. package/src/handlers/measureToolsHandler.ts +424 -0
  51. package/src/handlers/memorialButtonControl.ts +171 -0
  52. package/src/handlers/toolsConstants.ts +69 -0
  53. package/src/index.ts +6 -0
  54. package/src/shims-vue.d.ts +5 -0
  55. package/src/types/index.ts +260 -0
  56. package/src/types/json.d.ts +4 -0
  57. package/src/types/shpjs.d.ts +7 -0
  58. package/src/types/svg.d.ts +4 -0
  59. package/src/utils/CoordinateConverter.ts +43 -0
  60. package/src/utils/areaCalculator.ts +9 -0
  61. package/src/utils/drawingPathOptions.ts +57 -0
  62. package/src/utils/geometryCalculator.ts +62 -0
  63. package/src/utils/geometryFileParseResult.ts +5 -0
  64. package/src/utils/memorialLayer.ts +7 -0
  65. package/src/utils/menuHistory.ts +71 -0
  66. package/src/utils/normalizeGeoJsonToFeatures.ts +52 -0
  67. package/src/utils/parseGeoJsonFile.ts +23 -0
  68. package/src/utils/parseKmlFile.ts +31 -0
  69. package/src/utils/parseShapefileZip.ts +29 -0
  70. package/src/utils/stableMarker.ts +52 -0
  71. package/src/utils/validateImportedPolygonGeometry.ts +62 -0
@@ -0,0 +1,361 @@
1
+ @import 'leaflet/dist/leaflet.css';
2
+
3
+ .map-container {
4
+ --map-control-size: var(--mapa-size-base-30);
5
+ --map-control-icon-size: var(--mapa-size-base-20);
6
+
7
+ .leaflet-control-layers {
8
+ border: none !important;
9
+ border-radius: var(--mapa-base-radius-10);
10
+ background-color: var(--mapa-base-white);
11
+ box-shadow: var(--mapa-base-box-shadow);
12
+ box-sizing: border-box;
13
+ }
14
+
15
+ .leaflet-control-layers:not(.leaflet-control-layers-expanded) {
16
+ width: var(--map-control-size) !important;
17
+ min-width: var(--map-control-size);
18
+ }
19
+
20
+ .leaflet-control-layers.leaflet-control-layers-expanded {
21
+ width: auto !important;
22
+ min-width: 10rem;
23
+ }
24
+
25
+ .leaflet-control-layers-separator {
26
+ display: none;
27
+ }
28
+
29
+ .leaflet-control-layers label {
30
+ font-size: var(--mapa-fs-15);
31
+ color: var(--mapa-base-black);
32
+ padding: var(--mapa-size-base-5);
33
+ cursor: pointer;
34
+ margin-top: var(--mapa-size-base-2);
35
+ margin-bottom: var(--mapa-size-base-2);
36
+ }
37
+
38
+ .leaflet-control-layers input[type='radio'] {
39
+ accent-color: var(--mapa-base-green);
40
+ }
41
+
42
+ .leaflet-control-layers-overlays {
43
+ display: none;
44
+ }
45
+
46
+ .leaflet-control-layers-toggle {
47
+ background-image: url('../icons/layer-icon.svg');
48
+ background-size: var(--map-control-icon-size) var(--map-control-icon-size) !important;
49
+ background-repeat: no-repeat !important;
50
+ background-position: center !important;
51
+ width: var(--map-control-size) !important;
52
+ height: var(--map-control-size) !important;
53
+ line-height: var(--map-control-size) !important;
54
+ padding: 0 !important;
55
+ margin: 0 !important;
56
+ box-sizing: border-box !important;
57
+ }
58
+
59
+ /* zoom */
60
+
61
+ .leaflet-control-zoom {
62
+ border: none !important;
63
+ background: transparent !important;
64
+ box-shadow: var(--mapa-base-box-shadow);
65
+ border-radius: var(--mapa-base-radius-10);
66
+ overflow: hidden;
67
+ width: var(--map-control-size) !important;
68
+ box-sizing: border-box;
69
+ }
70
+
71
+ .leaflet-control-zoom a {
72
+ width: var(--map-control-size) !important;
73
+ height: var(--map-control-size) !important;
74
+ font-size: var(--mapa-fs-22) !important;
75
+ line-height: var(--map-control-size) !important;
76
+ border: none !important;
77
+ background-color: var(--mapa-base-white) !important;
78
+ color: var(--mapa-base-gray);
79
+ box-sizing: border-box;
80
+ }
81
+
82
+ .leaflet-control-zoom a:first-child {
83
+ border-top-left-radius: var(--mapa-base-radius-10) !important;
84
+ border-top-right-radius: var(--mapa-base-radius-10) !important;
85
+ }
86
+
87
+ .leaflet-control-zoom a:last-child {
88
+ border-bottom-left-radius: var(--mapa-base-radius-10) !important;
89
+ border-bottom-right-radius: var(--mapa-base-radius-10) !important;
90
+ }
91
+
92
+ .leaflet-control-zoom a:hover {
93
+ background-color: #f4f4f4 !important;
94
+ }
95
+
96
+ /* Geoman.io */
97
+
98
+ .leaflet-pm-toolbar {
99
+ border-radius: var(--mapa-base-radius-10);
100
+ background-color: var(--mapa-base-white);
101
+ box-shadow: var(--mapa-base-box-shadow);
102
+ }
103
+
104
+ .leaflet-pm-toolbar.leaflet-pm-draw.leaflet-bar.leaflet-control {
105
+ transform: translateX(-1.5px);
106
+ }
107
+
108
+ .leaflet-pm-toolbar .button-container {
109
+ padding: 0;
110
+ margin: 0;
111
+
112
+ &:first-child a {
113
+ border-top-right-radius: var(--mapa-base-radius-10);
114
+ border-top-left-radius: var(--mapa-base-radius-10);
115
+ }
116
+
117
+ &:last-child a {
118
+ border-bottom-right-radius: var(--mapa-base-radius-10);
119
+ border-bottom-left-radius: var(--mapa-base-radius-10);
120
+ }
121
+ }
122
+
123
+ .leaflet-pm-toolbar .control-icon,
124
+ .leaflet-pm-toolbar .leaflet-pm-action {
125
+ width: var(--map-control-size) !important;
126
+ height: var(--map-control-size) !important;
127
+ line-height: var(--map-control-size) !important;
128
+ background-size: var(--map-control-icon-size) var(--map-control-icon-size) !important;
129
+ background-position: center center !important;
130
+ background-repeat: no-repeat !important;
131
+ overflow: hidden;
132
+ box-sizing: border-box;
133
+ }
134
+
135
+ .leaflet-pm-toolbar .leaflet-pm-icon-shapefile {
136
+ background-image: url('../icons/file-import-regular-full-gray.svg');
137
+ }
138
+
139
+ /* Ajuste óptico: polígono e importar no glyph do Geoman/FA */
140
+ .leaflet-pm-toolbar .leaflet-pm-icon-polygon {
141
+ background-position: calc(50%) center !important;
142
+ }
143
+
144
+ .leaflet-pm-toolbar .leaflet-pm-icon-shapefile {
145
+ background-position: calc(50% + 1px) center !important;
146
+ }
147
+
148
+ .leaflet-pm-toolbar .button-container a,
149
+ .leaflet-pm-toolbar .button-container .leaflet-buttons-control-button {
150
+ display: flex !important;
151
+ align-items: center;
152
+ justify-content: center;
153
+ width: var(--map-control-size) !important;
154
+ height: var(--map-control-size) !important;
155
+ padding: 0 !important;
156
+ box-sizing: border-box;
157
+ }
158
+
159
+ .leaflet-pm-actions-container {
160
+ display: none !important;
161
+ }
162
+
163
+ .map-container--measuring .leaflet-pm-actions-container {
164
+ display: flex !important;
165
+ }
166
+
167
+ /* Ferramentas de medida — dois botões (reta / polígono) + painel estilo leaflet-measure */
168
+ .leaflet-control-measure-tools {
169
+ position: relative;
170
+ background: transparent;
171
+ box-shadow: none;
172
+ width: var(--map-control-size) !important;
173
+ min-width: var(--map-control-size) !important;
174
+ max-width: var(--map-control-size) !important;
175
+ height: auto !important;
176
+ min-height: auto !important;
177
+ max-height: none !important;
178
+ overflow: visible !important;
179
+ }
180
+
181
+ .leaflet-control-measure-tools .measure-tools-buttons {
182
+ display: flex;
183
+ flex-direction: column;
184
+ width: var(--map-control-size);
185
+ border-radius: var(--mapa-base-radius-10);
186
+ overflow: hidden;
187
+ box-shadow: var(--mapa-base-box-shadow);
188
+ }
189
+
190
+ .leaflet-control-measure-tools .measure-tools-btn {
191
+ display: flex;
192
+ align-items: center;
193
+ justify-content: center;
194
+ width: var(--map-control-size);
195
+ height: var(--map-control-size);
196
+ padding: 0;
197
+ border: none;
198
+ background-color: var(--mapa-base-white);
199
+ color: var(--mapa-base-gray);
200
+ cursor: pointer;
201
+ box-sizing: border-box;
202
+ line-height: 1;
203
+ }
204
+
205
+ .leaflet-control-measure-tools .measure-tools-btn:not(:last-child) {
206
+ border-bottom: var(--mapa-size-base-1) solid rgba(0, 0, 0, 0.08);
207
+ }
208
+
209
+ .leaflet-control-measure-tools .measure-tools-btn:hover {
210
+ background-color: #f4f4f4;
211
+ color: var(--mapa-base-black);
212
+ }
213
+
214
+ .leaflet-control-measure-tools .measure-tools-btn--active {
215
+ background-color: var(--mapa-base-green);
216
+ color: var(--mapa-base-white);
217
+ }
218
+
219
+ .leaflet-control-measure-tools .measure-tools-btn svg {
220
+ display: block;
221
+ width: var(--map-control-icon-size);
222
+ height: var(--map-control-icon-size);
223
+ }
224
+
225
+ .leaflet-control-measure-tools .measure-tools-interaction {
226
+ position: absolute;
227
+ top: calc(100% + var(--mapa-size-base-10));
228
+ right: 0;
229
+ left: auto;
230
+ width: 17.5rem;
231
+ min-width: 12rem;
232
+ max-width: 17.5rem;
233
+ max-height: min(24rem, 50vh);
234
+ overflow-y: auto;
235
+ padding: 10px 12px;
236
+ border-radius: var(--mapa-base-radius-10);
237
+ box-shadow: var(--mapa-base-box-shadow);
238
+ background-color: var(--mapa-base-white);
239
+ box-sizing: border-box;
240
+ z-index: 1000;
241
+ pointer-events: auto;
242
+ }
243
+
244
+ .leaflet-control-measure-tools.measure-tools-expanded {
245
+ z-index: 1001;
246
+ }
247
+
248
+ .leaflet-control-measure-tools h3 {
249
+ margin: 0 0 12px;
250
+ padding-bottom: 10px;
251
+ border-bottom: 1px solid #ddd;
252
+ font-size: var(--mapa-fs-15);
253
+ color: var(--mapa-base-black);
254
+ }
255
+
256
+ .leaflet-control-measure-tools .js-measure-help {
257
+ margin: 0 0 10px;
258
+ line-height: 1.5;
259
+ color: var(--mapa-base-black);
260
+ font-size: var(--mapa-fs-15);
261
+ }
262
+
263
+ .leaflet-control-measure-tools .results .group {
264
+ margin-top: 10px;
265
+ padding-top: 10px;
266
+ border-top: 1px dotted #eaeaea;
267
+ }
268
+
269
+ .leaflet-control-measure-tools .tasks {
270
+ margin: 12px 0 0;
271
+ padding: 10px 0 0;
272
+ border-top: 1px solid #ddd;
273
+ text-align: right;
274
+ list-style: none;
275
+ }
276
+
277
+ .leaflet-control-measure-tools .tasks li {
278
+ display: inline;
279
+ margin: 0 10px 0 0;
280
+ }
281
+
282
+ .leaflet-control-measure-tools a.cancel,
283
+ .leaflet-control-measure-tools a.finish,
284
+ .leaflet-measure-resultpopup a.zoomto,
285
+ .leaflet-measure-resultpopup a.deletemarkup {
286
+ color: var(--mapa-base-green);
287
+ text-decoration: none;
288
+ }
289
+
290
+ .leaflet-measure-resultpopup h3 {
291
+ margin: 0 0 8px;
292
+ font-size: var(--mapa-fs-15);
293
+ }
294
+
295
+ .leaflet-measure-resultpopup p {
296
+ margin: 0;
297
+ line-height: 1.5;
298
+ }
299
+
300
+ .map-container--measuring .leaflet-container,
301
+ .map-container--measuring .leaflet-container.leaflet-grab,
302
+ .map-container--measuring .leaflet-container.leaflet-dragging {
303
+ cursor: crosshair !important;
304
+ }
305
+
306
+ /* Controles suspensos alinhados (topright) */
307
+ .leaflet-top.leaflet-right {
308
+ display: flex;
309
+ flex-direction: column;
310
+ align-items: flex-end;
311
+ padding: var(--mapa-size-base-10);
312
+ gap: var(--mapa-size-base-10);
313
+ box-sizing: border-box;
314
+
315
+ .leaflet-control:not(.leaflet-control-layers-expanded):not(.leaflet-control-measure-tools) {
316
+ float: none !important;
317
+ clear: none !important;
318
+ margin: 0 !important;
319
+ width: var(--map-control-size);
320
+ box-sizing: border-box;
321
+ }
322
+
323
+ .leaflet-control.leaflet-control-measure-tools {
324
+ float: none !important;
325
+ clear: none !important;
326
+ margin: 0 !important;
327
+ width: var(--map-control-size) !important;
328
+ box-sizing: border-box;
329
+ }
330
+
331
+ .leaflet-control.leaflet-control-layers-expanded {
332
+ float: none !important;
333
+ clear: none !important;
334
+ margin: 0 !important;
335
+ box-sizing: border-box;
336
+ }
337
+
338
+ .leaflet-control-map-tools,
339
+ .leaflet-control-zoom,
340
+ .leaflet-control-layers:not(.leaflet-control-layers-expanded) {
341
+ width: var(--map-control-size) !important;
342
+ }
343
+
344
+ .leaflet-control-layers.leaflet-control-layers-expanded {
345
+ width: auto !important;
346
+ min-width: 10rem;
347
+ }
348
+ }
349
+
350
+ /* Vértices Geoman — área de clique maior para fechar polígono no primeiro ponto */
351
+ .geoman-draw-cursor .marker-icon {
352
+ width: 14px !important;
353
+ height: 14px !important;
354
+ margin-left: -7px !important;
355
+ margin-top: -7px !important;
356
+ }
357
+
358
+ .leaflet-top.leaflet-left {
359
+ padding-top: var(--mapa-size-base-10);
360
+ }
361
+ }
@@ -0,0 +1,302 @@
1
+ <template>
2
+ <div
3
+ ref="mapContainerRef"
4
+ class="map-container"
5
+ >
6
+ <Loading :isLoading="(isLoading || showLoading) && !disableLoading" />
7
+ <Map
8
+ ref="mapRef"
9
+ :drawingOptions="options.drawing"
10
+ :fullscreenContainer="mapContainerRef"
11
+ :layers="layers"
12
+ :mapOptions="options.map"
13
+ :toolsOptions="options.tools"
14
+ @onDrawing="emit('onDrawing', $event)"
15
+ @onFullscreenChange="emit('onFullscreenChange', $event)"
16
+ @onMeasureComplete="emit('onMeasureComplete', $event)"
17
+ @startLoading="isLoading = true"
18
+ @stopLoading="isLoading = false"
19
+ />
20
+ <LayerMenu
21
+ v-if="mapRef?.map && layers?.customLayers"
22
+ :layerControl="mapRef.layerControl"
23
+ :layersConfig="layers.customLayers"
24
+ :map="mapRef.map"
25
+ :options="options.layersMenu"
26
+ @onChildLayerToggle="emit('onChildLayerToggle', $event)"
27
+ @onGroupLayerToggle="emit('onGroupLayerToggle', $event)"
28
+ @startLoading="isLoading = true"
29
+ @stopLoading="isLoading = false"
30
+ />
31
+ <CoordinatePanel
32
+ v-if="mapRef && descriptiveMemorial?.show"
33
+ ref="coordinatePanelRef"
34
+ :descriptiveMemorial="descriptiveMemorial"
35
+ :map="mapRef.map"
36
+ @geometryChange="handleGeometryChange"
37
+ @geometryGeoJsonChange="handleGeometryGeoJsonChange"
38
+ @geometryRemoved="handleGeometryRemoved"
39
+ @systemChange="handleCoordinateSystemChange"
40
+ />
41
+ </div>
42
+ </template>
43
+
44
+ <script lang="ts" setup>
45
+ import L from 'leaflet'
46
+ import { computed, ref } from 'vue'
47
+ import {
48
+ DrawingEvent,
49
+ GroupLayerData,
50
+ IncrementedLayer,
51
+ LayerData,
52
+ MapLayers,
53
+ MapOptionsConfig,
54
+ DescriptiveMemorial,
55
+ MeasureCompleteEvent
56
+ } from '../types'
57
+ import Loading from './loading/Loading.vue'
58
+ import Map from './map/LeafletMap.vue'
59
+ import LayerMenu from './menu/LayerMenu.vue'
60
+ import CoordinatePanel from './coordinate/CoordinatePanel.vue'
61
+ import { isMemorialLayer, MEMORIAL_KEY } from '../utils/memorialLayer'
62
+ import { calculateLayerArea } from '../utils/geometryCalculator'
63
+ import { resolveDrawingPathOptions } from '../utils/drawingPathOptions'
64
+ import type { MemorialDrawShape } from '../utils/drawingPathOptions'
65
+ import type { Feature, MultiPolygon, Polygon } from 'geojson'
66
+
67
+ type MapaDPGProps = {
68
+ layers: MapLayers
69
+ options: MapOptionsConfig
70
+ showLoading: boolean
71
+ disableLoading: boolean
72
+ descriptiveMemorial: DescriptiveMemorial
73
+ }
74
+
75
+ const props = withDefaults(defineProps<MapaDPGProps>(), {
76
+ options: () => ({
77
+ map: {},
78
+ layersMenu: {
79
+ size: 'medium',
80
+ persist: false
81
+ }
82
+ }),
83
+ descriptiveMemorial: () => ({
84
+ show: false
85
+ })
86
+ })
87
+
88
+ const emit = defineEmits<{
89
+ (e: 'onGroupLayerToggle', data: GroupLayerData): void
90
+ (e: 'onChildLayerToggle', data: LayerData): void
91
+ (e: 'onDrawing', data: DrawingEvent): void
92
+ (e: 'onCoordinateSystemChange', system: string): void
93
+ (e: 'onFullscreenChange', active: boolean): void
94
+ (e: 'onMeasureComplete', data: MeasureCompleteEvent): void
95
+ }>()
96
+
97
+ type MapRef = {
98
+ map: L.Map
99
+ layerControl: L.Control.Layers
100
+ drawItemsGroup: L.FeatureGroup
101
+ leaflet: typeof L
102
+ getDrawingPathOptions: (shape: MemorialDrawShape) => L.PathOptions
103
+ centerMap: () => void
104
+ enterFullscreen: () => void
105
+ exitFullscreen: () => void
106
+ toggleFullscreen: () => void
107
+ toggleMeasureArea: () => void
108
+ }
109
+
110
+ const mapRef = ref<MapRef>()
111
+ const mapContainerRef = ref<HTMLElement | null>(null)
112
+ const coordinatePanelRef = ref()
113
+ const isLoading = ref<boolean>(false)
114
+
115
+ const getMemorialPathOptions = (shape: MemorialDrawShape): L.PathOptions =>
116
+ mapRef.value?.getDrawingPathOptions(shape) ??
117
+ resolveDrawingPathOptions(mapRef.value?.map, props.options.drawing, shape)
118
+
119
+ const handleCoordinateSystemChange = (system: string) => {
120
+ emit('onCoordinateSystemChange', system)
121
+ }
122
+
123
+ const incrementLayerWithDrawnArea = (layer: L.Layer): IncrementedLayer => {
124
+ if (layer instanceof L.GeoJSON) {
125
+ const innerLayer = layer.getLayers()[0]
126
+ const drawnArea = innerLayer ? calculateLayerArea(innerLayer) : { m2: 0, km2: 0, ha: 0 }
127
+ return Object.assign(layer, { drawnArea }) as IncrementedLayer
128
+ }
129
+
130
+ const incrementedLayer = layer as IncrementedLayer
131
+ incrementedLayer.drawnArea = calculateLayerArea(layer)
132
+ return incrementedLayer
133
+ }
134
+
135
+ const handleGeometryChange = (geometry: string) => {
136
+ if (!mapRef.value?.map || !mapRef.value?.drawItemsGroup) return
137
+
138
+ const coordinates = geometry
139
+ .replace(/[A-Z()]/g, '')
140
+ .trim()
141
+ .split(',')
142
+ .map(coord => {
143
+ const [x, y] = coord.trim().split(' ')
144
+ return [parseFloat(y), parseFloat(x)] as [number, number]
145
+ })
146
+
147
+ const polylineStyle = getMemorialPathOptions('polyline')
148
+ const polygonStyle = getMemorialPathOptions('polygon')
149
+
150
+ let leafletGeometry: L.Layer & { options: { memorialKey?: string } }
151
+
152
+ if (geometry.startsWith('POINT')) {
153
+ leafletGeometry = L.marker(coordinates[0])
154
+ } else if (geometry.startsWith('LINESTRING')) {
155
+ leafletGeometry = L.polyline(coordinates as [number, number][], polylineStyle)
156
+ } else if (geometry.startsWith('POLYGON')) {
157
+ leafletGeometry = L.polygon(coordinates as [number, number][], polygonStyle)
158
+ } else {
159
+ console.error('Tipo de geometria não suportado:', geometry)
160
+ return
161
+ }
162
+
163
+ leafletGeometry.options.memorialKey = MEMORIAL_KEY
164
+
165
+ mapRef.value.drawItemsGroup.addLayer(leafletGeometry)
166
+
167
+ emit('onDrawing', {
168
+ type: 'created',
169
+ layer: incrementLayerWithDrawnArea(leafletGeometry)
170
+ })
171
+
172
+ if (leafletGeometry instanceof L.Marker) {
173
+ mapRef.value.map.setView(coordinates[0], 15)
174
+ } else if (leafletGeometry instanceof L.Polyline || leafletGeometry instanceof L.Polygon) {
175
+ mapRef.value.map.fitBounds(leafletGeometry.getBounds())
176
+ }
177
+ }
178
+
179
+ const removeMemorialLayers = (): L.Layer[] => {
180
+ if (!mapRef.value?.drawItemsGroup) return []
181
+
182
+ const layersToRemove: L.Layer[] = []
183
+
184
+ mapRef.value.drawItemsGroup.eachLayer(layer => {
185
+ if (isMemorialLayer(layer)) {
186
+ layersToRemove.push(layer)
187
+ }
188
+ })
189
+
190
+ layersToRemove.forEach(layer => {
191
+ mapRef.value?.drawItemsGroup.removeLayer(layer)
192
+ })
193
+
194
+ return layersToRemove
195
+ }
196
+
197
+ const handleGeometryGeoJsonChange = (feature: Feature<Polygon | MultiPolygon>) => {
198
+ if (!mapRef.value?.map || !mapRef.value?.drawItemsGroup) return
199
+
200
+ removeMemorialLayers()
201
+
202
+ const polygonStyle = getMemorialPathOptions('polygon')
203
+
204
+ const leafletGeometry = L.geoJSON(feature, {
205
+ style: polygonStyle,
206
+ onEachFeature: (_geoJsonFeature, layer) => {
207
+ ;(layer as L.Layer & { options: { memorialKey?: string } }).options.memorialKey = MEMORIAL_KEY
208
+ }
209
+ }) as L.Layer & { options: { memorialKey?: string } }
210
+
211
+ leafletGeometry.options.memorialKey = MEMORIAL_KEY
212
+
213
+ mapRef.value.drawItemsGroup.addLayer(leafletGeometry)
214
+ mapRef.value.map.fitBounds(leafletGeometry.getBounds())
215
+
216
+ emit('onDrawing', {
217
+ type: 'created',
218
+ layer: incrementLayerWithDrawnArea(leafletGeometry)
219
+ })
220
+ }
221
+
222
+ const handleGeometryRemoved = () => {
223
+ if (!mapRef.value?.map || !mapRef.value?.drawItemsGroup) return
224
+
225
+ const layersToRemove = removeMemorialLayers()
226
+
227
+ if (layersToRemove.length > 0) {
228
+ emit('onDrawing', {
229
+ type: 'deleted',
230
+ layers: layersToRemove
231
+ })
232
+ }
233
+ }
234
+
235
+ const toggleCoordinatePanel = () => {
236
+ if (coordinatePanelRef.value) {
237
+ coordinatePanelRef.value.togglePanel()
238
+ }
239
+ }
240
+
241
+ const closeCoordinatePanel = () => {
242
+ if (coordinatePanelRef.value) {
243
+ coordinatePanelRef.value.closePanel()
244
+ }
245
+ }
246
+
247
+ const centerMap = () => {
248
+ mapRef.value?.centerMap()
249
+ }
250
+
251
+ const enterFullscreen = () => {
252
+ mapRef.value?.enterFullscreen()
253
+ }
254
+
255
+ const exitFullscreen = () => {
256
+ mapRef.value?.exitFullscreen()
257
+ }
258
+
259
+ const toggleFullscreen = () => {
260
+ mapRef.value?.toggleFullscreen()
261
+ }
262
+
263
+ const toggleMeasureArea = () => {
264
+ mapRef.value?.toggleMeasureArea()
265
+ }
266
+
267
+ defineExpose({
268
+ map: computed(() => mapRef.value?.map),
269
+ layerControl: computed(() => mapRef.value?.layerControl),
270
+ drawItemsGroup: computed(() => mapRef.value?.drawItemsGroup),
271
+ leaflet: computed(() => mapRef.value?.leaflet),
272
+ getDrawingPathOptions: getMemorialPathOptions,
273
+ toggleCoordinatePanel,
274
+ closeCoordinatePanel,
275
+ centerMap,
276
+ enterFullscreen,
277
+ exitFullscreen,
278
+ toggleFullscreen,
279
+ toggleMeasureArea
280
+ })
281
+ </script>
282
+
283
+ <style>
284
+ @import '/src/assets/main.css';
285
+
286
+ .map-container {
287
+ position: relative;
288
+ width: 100%;
289
+ height: 100%;
290
+ overflow: hidden;
291
+ border-radius: var(--mapa-base-radius-5);
292
+ }
293
+
294
+ .map-container--fullscreen {
295
+ position: fixed;
296
+ inset: 0;
297
+ z-index: 9999;
298
+ width: 100vw;
299
+ height: 100vh;
300
+ border-radius: 0;
301
+ }
302
+ </style>