@rural-environmental-registry/map_component 1.1.0 → 2.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.
- package/README.md +1 -0
- package/dist/handlers/measureToolsHandler.d.ts +1 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.mjs +16337 -14954
- package/dist/types/index.d.ts +118 -15
- package/dist/utils/geometryFileParseResult.d.ts +8 -0
- package/dist/utils/layersConfigNormalizer.d.ts +16 -0
- package/dist/utils/menuHistory.d.ts +3 -3
- package/dist/utils/normalizeGeoJsonToFeatures.d.ts +2 -0
- package/dist/utils/parseGeoJsonFile.d.ts +2 -0
- package/dist/utils/parseKmlFile.d.ts +2 -0
- package/dist/utils/parseShapefileZip.d.ts +2 -8
- package/dist/utils/{validateShapefileGeometry.d.ts → validateImportedPolygonGeometry.d.ts} +2 -2
- package/package.json +3 -2
- package/src/components/MapDPG.vue +90 -2
- package/src/components/coordinate/CoordinatePanel.vue +31 -8
- package/src/components/fa-icon/FontAwesomeIcon.vue +35 -5
- package/src/components/map/LeafletMap.vue +3 -1
- package/src/components/menu/ChildMenu.vue +307 -27
- package/src/components/menu/LayerMenu.vue +232 -37
- package/src/components/menu/ParentMenu.vue +261 -27
- package/src/components/menu/SectionMenu.vue +512 -0
- package/src/constants/coordinatePanel.ts +6 -5
- package/src/handlers/mapToolsHandler.ts +3 -1
- package/src/handlers/measureToolsHandler.ts +36 -27
- package/src/handlers/toolsConstants.ts +1 -0
- package/src/index.ts +47 -0
- package/src/types/index.ts +149 -14
- package/src/utils/geometryFileParseResult.ts +5 -0
- package/src/utils/layersConfigNormalizer.ts +273 -0
- package/src/utils/menuHistory.ts +35 -19
- package/src/utils/normalizeGeoJsonToFeatures.ts +52 -0
- package/src/utils/parseGeoJsonFile.ts +23 -0
- package/src/utils/parseKmlFile.ts +31 -0
- package/src/utils/parseShapefileZip.ts +4 -31
- package/src/utils/validateImportedPolygonGeometry.ts +62 -0
- package/src/utils/validateShapefileGeometry.ts +0 -54
|
@@ -0,0 +1,512 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
class="section-menu"
|
|
4
|
+
:class="{ 'section-menu--editing': isEditing }"
|
|
5
|
+
>
|
|
6
|
+
<div
|
|
7
|
+
v-if="sections.length"
|
|
8
|
+
class="section-menu-selector"
|
|
9
|
+
role="tablist"
|
|
10
|
+
aria-label="Seções do menu de camadas"
|
|
11
|
+
>
|
|
12
|
+
<button
|
|
13
|
+
v-for="item in sections"
|
|
14
|
+
:key="item.key"
|
|
15
|
+
type="button"
|
|
16
|
+
role="tab"
|
|
17
|
+
class="section-menu-selector-item"
|
|
18
|
+
:class="{ 'section-menu-selector-item--active': item.key === activeSectionKey }"
|
|
19
|
+
:aria-selected="item.key === activeSectionKey"
|
|
20
|
+
@click.stop="onSelectSection(item.key)"
|
|
21
|
+
>
|
|
22
|
+
{{ item.name || item.key }}
|
|
23
|
+
</button>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<template v-if="section">
|
|
27
|
+
<template v-if="isEditing && editingLayer && editingGroup">
|
|
28
|
+
<div class="section-edit-panel">
|
|
29
|
+
<ChildMenu
|
|
30
|
+
:actionDefaults="section.actionDefaults"
|
|
31
|
+
:data="editingLayer"
|
|
32
|
+
:groupKey="editingGroup.key"
|
|
33
|
+
:hideControls="true"
|
|
34
|
+
:persist="persist"
|
|
35
|
+
:sectionKey="section.key"
|
|
36
|
+
:visibilityMode="visibilityMode"
|
|
37
|
+
@onChildLayerToggle="emit('onChildLayerToggle', $event)"
|
|
38
|
+
@onLayerAction="emit('onLayerAction', $event)"
|
|
39
|
+
/>
|
|
40
|
+
|
|
41
|
+
<div
|
|
42
|
+
v-if="editPanelActions.length"
|
|
43
|
+
class="section-edit-panel-actions"
|
|
44
|
+
>
|
|
45
|
+
<button
|
|
46
|
+
v-for="action in editPanelActions"
|
|
47
|
+
:key="action.key"
|
|
48
|
+
type="button"
|
|
49
|
+
class="section-edit-action-button"
|
|
50
|
+
:style="actionButtonStyle(action)"
|
|
51
|
+
:disabled="action.disabled"
|
|
52
|
+
@click.stop="onEditPanelAction(action)"
|
|
53
|
+
>
|
|
54
|
+
<FontAwesomeIcon
|
|
55
|
+
v-if="action.icon"
|
|
56
|
+
:iconName="action.icon"
|
|
57
|
+
/>
|
|
58
|
+
<span>{{ action.name }}</span>
|
|
59
|
+
</button>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<div
|
|
63
|
+
v-if="editingMetrics.length"
|
|
64
|
+
class="section-edit-metrics"
|
|
65
|
+
>
|
|
66
|
+
<div
|
|
67
|
+
v-for="(metric, index) in editingMetrics"
|
|
68
|
+
:key="`${metric.title}-${metric.type}-${index}`"
|
|
69
|
+
class="section-metric-row"
|
|
70
|
+
>
|
|
71
|
+
<span class="section-metric-title">{{ metric.title }} :</span>
|
|
72
|
+
<span
|
|
73
|
+
class="section-metric-value-label"
|
|
74
|
+
:style="metricValueLabelStyle(metric)"
|
|
75
|
+
>
|
|
76
|
+
{{ metric.value }}
|
|
77
|
+
</span>
|
|
78
|
+
<span class="section-metric-type">{{ metric.type }}</span>
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
|
|
82
|
+
<div class="section-edit-footer">
|
|
83
|
+
<button
|
|
84
|
+
v-if="cancelAction.visible !== false"
|
|
85
|
+
type="button"
|
|
86
|
+
class="section-edit-footer-button"
|
|
87
|
+
:style="actionButtonStyle(cancelAction)"
|
|
88
|
+
:disabled="cancelAction.disabled"
|
|
89
|
+
@click.stop="onEditControlAction(cancelAction)"
|
|
90
|
+
>
|
|
91
|
+
<FontAwesomeIcon
|
|
92
|
+
v-if="cancelAction.icon"
|
|
93
|
+
:iconName="cancelAction.icon"
|
|
94
|
+
/>
|
|
95
|
+
<span>{{ cancelAction.name }}</span>
|
|
96
|
+
</button>
|
|
97
|
+
|
|
98
|
+
<button
|
|
99
|
+
v-if="concludeAction.visible !== false"
|
|
100
|
+
type="button"
|
|
101
|
+
class="section-edit-footer-button section-edit-footer-button--end"
|
|
102
|
+
:style="actionButtonStyle(concludeAction)"
|
|
103
|
+
:disabled="concludeAction.disabled"
|
|
104
|
+
@click.stop="onEditControlAction(concludeAction)"
|
|
105
|
+
>
|
|
106
|
+
<FontAwesomeIcon
|
|
107
|
+
v-if="concludeAction.icon"
|
|
108
|
+
:iconName="concludeAction.icon"
|
|
109
|
+
/>
|
|
110
|
+
<span>{{ concludeAction.name }}</span>
|
|
111
|
+
</button>
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
</template>
|
|
115
|
+
|
|
116
|
+
<template v-else>
|
|
117
|
+
<ParentMenu
|
|
118
|
+
v-for="group in section.groups"
|
|
119
|
+
:key="group.key"
|
|
120
|
+
:actionDefaults="section.actionDefaults"
|
|
121
|
+
:groupData="group"
|
|
122
|
+
:persist="persist"
|
|
123
|
+
:sectionKey="section.key"
|
|
124
|
+
:visibilityMode="visibilityMode"
|
|
125
|
+
@onChildLayerToggle="emit('onChildLayerToggle', $event)"
|
|
126
|
+
@onGroupLayerToggle="emit('onGroupLayerToggle', $event)"
|
|
127
|
+
@onLayerAction="emit('onLayerAction', $event)"
|
|
128
|
+
/>
|
|
129
|
+
</template>
|
|
130
|
+
</template>
|
|
131
|
+
</div>
|
|
132
|
+
</template>
|
|
133
|
+
|
|
134
|
+
<script lang="ts" setup>
|
|
135
|
+
import { computed } from 'vue'
|
|
136
|
+
import FontAwesomeIcon from '../fa-icon/FontAwesomeIcon.vue'
|
|
137
|
+
import ParentMenu from './ParentMenu.vue'
|
|
138
|
+
import ChildMenu from './ChildMenu.vue'
|
|
139
|
+
import {
|
|
140
|
+
GroupLayerData,
|
|
141
|
+
LayerActionConfig,
|
|
142
|
+
LayerActionPayload,
|
|
143
|
+
LayerActionStyle,
|
|
144
|
+
LayerData,
|
|
145
|
+
LayerMetricsConfig,
|
|
146
|
+
SectionConfig
|
|
147
|
+
} from '../../types'
|
|
148
|
+
import {
|
|
149
|
+
resolveEditControlAction,
|
|
150
|
+
resolveLayerActions,
|
|
151
|
+
resolveLayerMetrics
|
|
152
|
+
} from '../../utils/layersConfigNormalizer'
|
|
153
|
+
|
|
154
|
+
const DEFAULT_ACTION_STYLE: Required<LayerActionStyle> = {
|
|
155
|
+
backgroundColor: 'var(--mapa-base-green)',
|
|
156
|
+
color: 'var(--mapa-base-white)',
|
|
157
|
+
borderColor: 'var(--mapa-base-white)'
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const resolveActionStyle = (style?: LayerActionStyle): Required<LayerActionStyle> => {
|
|
161
|
+
const color = style?.color ?? DEFAULT_ACTION_STYLE.color
|
|
162
|
+
return {
|
|
163
|
+
backgroundColor: style?.backgroundColor ?? DEFAULT_ACTION_STYLE.backgroundColor,
|
|
164
|
+
color,
|
|
165
|
+
borderColor: style?.borderColor ?? color
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const actionButtonStyle = (action: LayerActionConfig): Required<LayerActionStyle> =>
|
|
170
|
+
resolveActionStyle(action.style)
|
|
171
|
+
|
|
172
|
+
const firstColor = (...values: Array<string | null | undefined>): string | undefined =>
|
|
173
|
+
values.find((value) => typeof value === 'string' && value.trim() !== '')
|
|
174
|
+
|
|
175
|
+
const metricValueLabelStyle = (
|
|
176
|
+
metric: LayerMetricsConfig
|
|
177
|
+
): Pick<Required<LayerActionStyle>, 'backgroundColor' | 'borderColor'> => {
|
|
178
|
+
const style = metric.style
|
|
179
|
+
return {
|
|
180
|
+
backgroundColor: firstColor(style?.backgroundColor) ?? '#ffffff',
|
|
181
|
+
borderColor: firstColor(style?.borderColor, style?.color) ?? 'transparent'
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
type SectionMenuProps = {
|
|
186
|
+
sections: SectionConfig[]
|
|
187
|
+
selectedSectionKey?: string | null
|
|
188
|
+
persist: boolean
|
|
189
|
+
editingLayerKey?: string | null
|
|
190
|
+
visibilityMode?: 'switch' | 'eye'
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const props = withDefaults(defineProps<SectionMenuProps>(), {
|
|
194
|
+
visibilityMode: 'switch',
|
|
195
|
+
editingLayerKey: null,
|
|
196
|
+
selectedSectionKey: null
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
const emit = defineEmits<{
|
|
200
|
+
onChildLayerToggle: [LayerData]
|
|
201
|
+
onGroupLayerToggle: [GroupLayerData]
|
|
202
|
+
onLayerAction: [LayerActionPayload]
|
|
203
|
+
onSelectedSectionChange: [string]
|
|
204
|
+
}>()
|
|
205
|
+
|
|
206
|
+
const activeSectionKey = computed((): string | null => {
|
|
207
|
+
const sections = props.sections
|
|
208
|
+
if (!sections.length) return null
|
|
209
|
+
|
|
210
|
+
const selected = props.selectedSectionKey
|
|
211
|
+
if (selected && sections.some((item) => item.key === selected)) {
|
|
212
|
+
return selected
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return sections[0].key
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
const section = computed((): SectionConfig | null => {
|
|
219
|
+
const key = activeSectionKey.value
|
|
220
|
+
if (!key) return null
|
|
221
|
+
return props.sections.find((item) => item.key === key) ?? null
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
const findLayerContext = (
|
|
225
|
+
layerKey: string | null | undefined
|
|
226
|
+
): { layer: LayerData; group: GroupLayerData } | null => {
|
|
227
|
+
if (!layerKey || !section.value) return null
|
|
228
|
+
for (const group of section.value.groups) {
|
|
229
|
+
const layer = group.layers?.find((item) => item.key === layerKey)
|
|
230
|
+
if (layer) return { layer, group }
|
|
231
|
+
}
|
|
232
|
+
return null
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const editingContext = computed(() => findLayerContext(props.editingLayerKey))
|
|
236
|
+
const editingLayer = computed(() => editingContext.value?.layer ?? null)
|
|
237
|
+
const editingGroup = computed(() => editingContext.value?.group ?? null)
|
|
238
|
+
const isEditing = computed(() => !!editingLayer.value)
|
|
239
|
+
|
|
240
|
+
const editingMetrics = computed((): LayerMetricsConfig[] =>
|
|
241
|
+
resolveLayerMetrics(editingLayer.value)
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
const editPanelActions = computed((): LayerActionConfig[] => {
|
|
245
|
+
const layer = editingLayer.value
|
|
246
|
+
const currentSection = section.value
|
|
247
|
+
if (!layer || !currentSection) return []
|
|
248
|
+
|
|
249
|
+
const sourceActions =
|
|
250
|
+
Array.isArray(layer.editActions) && layer.editActions.length > 0
|
|
251
|
+
? layer.editActions
|
|
252
|
+
: resolveLayerActions(layer, currentSection.actionDefaults)
|
|
253
|
+
|
|
254
|
+
return sourceActions.filter((action) => action.visible !== false)
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
const cancelAction = computed(() =>
|
|
258
|
+
resolveEditControlAction(section.value?.actionDefaults, 'cancel')
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
const concludeAction = computed(() =>
|
|
262
|
+
resolveEditControlAction(section.value?.actionDefaults, 'conclude')
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
const onSelectSection = (sectionKey: string): void => {
|
|
266
|
+
if (sectionKey === activeSectionKey.value) return
|
|
267
|
+
emit('onSelectedSectionChange', sectionKey)
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const emitEditPanelAction = (action: LayerActionConfig): void => {
|
|
271
|
+
const layer = editingLayer.value
|
|
272
|
+
const currentSection = section.value
|
|
273
|
+
if (!layer || !currentSection || action.disabled) return
|
|
274
|
+
|
|
275
|
+
emit('onLayerAction', {
|
|
276
|
+
actionKey: action.key,
|
|
277
|
+
actionType: action.type,
|
|
278
|
+
sectionKey: currentSection.key,
|
|
279
|
+
groupKey: editingGroup.value?.key,
|
|
280
|
+
layerKey: layer.key,
|
|
281
|
+
layer,
|
|
282
|
+
source: 'edit-panel'
|
|
283
|
+
})
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const onEditPanelAction = (action: LayerActionConfig): void => {
|
|
287
|
+
emitEditPanelAction(action)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const onEditControlAction = (action: LayerActionConfig): void => {
|
|
291
|
+
emitEditPanelAction(action)
|
|
292
|
+
}
|
|
293
|
+
</script>
|
|
294
|
+
|
|
295
|
+
<style>
|
|
296
|
+
.section-menu {
|
|
297
|
+
display: flex;
|
|
298
|
+
flex-direction: column;
|
|
299
|
+
gap: var(--mapa-size-base-5);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.section-menu--editing {
|
|
303
|
+
flex: 1 1 auto;
|
|
304
|
+
min-height: 100%;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
.section-menu-selector {
|
|
308
|
+
display: flex;
|
|
309
|
+
flex-direction: row;
|
|
310
|
+
flex-wrap: nowrap;
|
|
311
|
+
align-items: stretch;
|
|
312
|
+
gap: var(--mapa-size-base-5);
|
|
313
|
+
width: 100%;
|
|
314
|
+
box-sizing: border-box;
|
|
315
|
+
padding: var(--mapa-size-base-5) var(--mapa-size-base-10);
|
|
316
|
+
border-bottom: var(--mapa-size-base-1) solid rgba(0, 0, 0, 0.08);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
.section-menu-selector-item {
|
|
320
|
+
display: inline-flex;
|
|
321
|
+
align-items: center;
|
|
322
|
+
justify-content: center;
|
|
323
|
+
flex: 1 1 0;
|
|
324
|
+
min-width: 0;
|
|
325
|
+
min-height: var(--mapa-size-base-30);
|
|
326
|
+
height: auto;
|
|
327
|
+
padding: var(--mapa-size-base-5) var(--mapa-size-base-10);
|
|
328
|
+
border: none;
|
|
329
|
+
border-bottom: var(--mapa-size-base-2) solid transparent;
|
|
330
|
+
border-radius: 0;
|
|
331
|
+
background: transparent;
|
|
332
|
+
color: var(--mapa-base-gray);
|
|
333
|
+
font-size: var(--mapa-fs-12);
|
|
334
|
+
font-weight: 600;
|
|
335
|
+
text-align: center;
|
|
336
|
+
white-space: normal;
|
|
337
|
+
overflow-wrap: break-word;
|
|
338
|
+
word-break: normal;
|
|
339
|
+
line-height: 1.3;
|
|
340
|
+
cursor: pointer;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
.section-menu-selector-item:hover {
|
|
344
|
+
color: var(--mapa-base-green);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
.section-menu-selector-item--active {
|
|
348
|
+
color: var(--mapa-base-green);
|
|
349
|
+
border-bottom-color: var(--mapa-base-green);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
.section-edit-panel {
|
|
353
|
+
display: flex;
|
|
354
|
+
flex-direction: column;
|
|
355
|
+
flex: 1 1 auto;
|
|
356
|
+
min-height: 0;
|
|
357
|
+
width: 100%;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
.section-edit-panel .child-menu {
|
|
361
|
+
padding-left: var(--mapa-size-base-20) !important;
|
|
362
|
+
padding-right: var(--mapa-size-base-20) !important;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
.section-edit-metrics {
|
|
366
|
+
display: flex;
|
|
367
|
+
flex-direction: column;
|
|
368
|
+
align-items: stretch;
|
|
369
|
+
gap: var(--mapa-size-base-5);
|
|
370
|
+
width: 100%;
|
|
371
|
+
box-sizing: border-box;
|
|
372
|
+
margin-top: var(--mapa-size-base-15);
|
|
373
|
+
padding: var(--mapa-size-base-10) var(--mapa-size-base-20);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
.section-metric-row {
|
|
377
|
+
display: flex;
|
|
378
|
+
flex: 0 0 auto;
|
|
379
|
+
flex-wrap: nowrap;
|
|
380
|
+
align-items: center;
|
|
381
|
+
justify-content: flex-start;
|
|
382
|
+
gap: var(--mapa-size-base-5);
|
|
383
|
+
width: 100%;
|
|
384
|
+
height: var(--mapa-size-base-40);
|
|
385
|
+
padding: 0 var(--mapa-size-base-10);
|
|
386
|
+
box-sizing: border-box;
|
|
387
|
+
font-size: var(--mapa-fs-12);
|
|
388
|
+
color: #000000;
|
|
389
|
+
white-space: nowrap;
|
|
390
|
+
overflow: hidden;
|
|
391
|
+
text-overflow: ellipsis;
|
|
392
|
+
font-weight: bold;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
.section-metric-title {
|
|
396
|
+
flex-shrink: 0;
|
|
397
|
+
color: #000000;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
.section-metric-value-label {
|
|
401
|
+
display: inline-flex;
|
|
402
|
+
flex-shrink: 0;
|
|
403
|
+
align-items: center;
|
|
404
|
+
justify-content: center;
|
|
405
|
+
height: var(--mapa-size-base-20);
|
|
406
|
+
padding: 0 var(--mapa-size-base-8);
|
|
407
|
+
border: 1px solid;
|
|
408
|
+
border-radius: 100em;
|
|
409
|
+
font-size: var(--mapa-fs-12);
|
|
410
|
+
font-weight: 600;
|
|
411
|
+
line-height: 1;
|
|
412
|
+
color: #000000;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
.section-metric-type {
|
|
416
|
+
flex-shrink: 0;
|
|
417
|
+
color: #000000;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
.section-edit-panel-actions {
|
|
421
|
+
display: flex;
|
|
422
|
+
flex-direction: column;
|
|
423
|
+
align-items: stretch;
|
|
424
|
+
gap: var(--mapa-size-base-5);
|
|
425
|
+
width: 100%;
|
|
426
|
+
box-sizing: border-box;
|
|
427
|
+
padding: var(--mapa-size-base-10) var(--mapa-size-base-20);
|
|
428
|
+
}
|
|
429
|
+
.section-edit-action-button {
|
|
430
|
+
display: inline-flex;
|
|
431
|
+
flex: 0 0 auto;
|
|
432
|
+
align-items: center;
|
|
433
|
+
justify-content: center;
|
|
434
|
+
gap: var(--mapa-size-base-5);
|
|
435
|
+
width: 100%;
|
|
436
|
+
height: var(--mapa-size-base-40);
|
|
437
|
+
padding: 0 var(--mapa-size-base-10);
|
|
438
|
+
border: 1px solid;
|
|
439
|
+
border-radius: 100em;
|
|
440
|
+
font-size: var(--mapa-fs-15);
|
|
441
|
+
font-weight: 600;
|
|
442
|
+
white-space: nowrap;
|
|
443
|
+
overflow: hidden;
|
|
444
|
+
text-overflow: ellipsis;
|
|
445
|
+
position: relative;
|
|
446
|
+
text-align: center;
|
|
447
|
+
vertical-align: middle;
|
|
448
|
+
cursor: pointer;
|
|
449
|
+
margin-top: var(--mapa-size-base-20);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
.section-edit-action-button:not(:disabled):hover {
|
|
453
|
+
background-image: linear-gradient(rgba(0, 0, 0, 0.16), rgba(0, 0, 0, 0.16));
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
.section-edit-action-button:not(:disabled):active {
|
|
457
|
+
background-image: linear-gradient(rgba(0, 0, 0, 0.32), rgba(0, 0, 0, 0.32));
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
.section-edit-action-button:disabled {
|
|
461
|
+
opacity: 0.5;
|
|
462
|
+
cursor: not-allowed;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
.section-edit-footer {
|
|
466
|
+
display: flex;
|
|
467
|
+
justify-content: space-between;
|
|
468
|
+
align-items: center;
|
|
469
|
+
gap: var(--mapa-size-base-5);
|
|
470
|
+
width: 100%;
|
|
471
|
+
box-sizing: border-box;
|
|
472
|
+
margin-top: auto;
|
|
473
|
+
padding: var(--mapa-size-base-10) var(--mapa-size-base-20);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
.section-edit-footer-button {
|
|
477
|
+
display: inline-flex;
|
|
478
|
+
align-items: center;
|
|
479
|
+
justify-content: center;
|
|
480
|
+
gap: var(--mapa-size-base-5);
|
|
481
|
+
height: var(--mapa-size-base-40);
|
|
482
|
+
padding: 0 var(--mapa-size-base-20);
|
|
483
|
+
border: 1px solid;
|
|
484
|
+
border-radius: 100em;
|
|
485
|
+
font-size: var(--mapa-fs-15);
|
|
486
|
+
font-weight: 600;
|
|
487
|
+
white-space: nowrap;
|
|
488
|
+
overflow: hidden;
|
|
489
|
+
text-overflow: ellipsis;
|
|
490
|
+
position: relative;
|
|
491
|
+
text-align: center;
|
|
492
|
+
vertical-align: middle;
|
|
493
|
+
cursor: pointer;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
.section-edit-footer-button--end {
|
|
497
|
+
margin-left: auto;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
.section-edit-footer-button:not(:disabled):hover {
|
|
501
|
+
background-image: linear-gradient(rgba(0, 0, 0, 0.16), rgba(0, 0, 0, 0.16));
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
.section-edit-footer-button:not(:disabled):active {
|
|
505
|
+
background-image: linear-gradient(rgba(0, 0, 0, 0.32), rgba(0, 0, 0, 0.32));
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
.section-edit-footer-button:disabled {
|
|
509
|
+
opacity: 0.5;
|
|
510
|
+
cursor: not-allowed;
|
|
511
|
+
}
|
|
512
|
+
</style>
|
|
@@ -45,12 +45,13 @@ export const COORDINATE_PANEL_TEXTS: CoordinatePanelTexts = {
|
|
|
45
45
|
csvColumnsInfo: 'The file must contain the columns: X, Y, AZIMUTH, DISTANCE',
|
|
46
46
|
applyCsvCoordinates: 'Apply CSV Coordinates',
|
|
47
47
|
|
|
48
|
-
shapefileUpload: 'Shapefile Upload',
|
|
49
|
-
shapefileFileUpload: 'Shapefile Upload',
|
|
50
|
-
dragShapefileZip: 'Drag
|
|
48
|
+
shapefileUpload: 'Shapefile, KML and Geojson Upload',
|
|
49
|
+
shapefileFileUpload: 'Shapefile, KML and Geojson Upload',
|
|
50
|
+
dragShapefileZip: 'Drag file or click to upload',
|
|
51
51
|
shapefileZipInfo:
|
|
52
|
-
'Upload a .zip
|
|
53
|
-
shapefileAppliedSuccess: '
|
|
52
|
+
'Upload a .zip (shapefile), .kml, .geojson or .json with a single Polygon or MultiPolygon geometry',
|
|
53
|
+
shapefileAppliedSuccess: 'Geometry applied successfully',
|
|
54
|
+
geometryImportUnsupportedFormat: 'Unsupported file format. Use .zip, .kml, .geojson or .json',
|
|
54
55
|
|
|
55
56
|
placeholderLongitude: 'e.g., -46.6333',
|
|
56
57
|
placeholderLatitude: 'e.g., -23.5505',
|
|
@@ -198,7 +198,9 @@ export default class MapToolsHandler {
|
|
|
198
198
|
|
|
199
199
|
this._control = new MapToolsControl()
|
|
200
200
|
this._map.addControl(this._control)
|
|
201
|
-
|
|
201
|
+
if (config.zoom?.show !== false) {
|
|
202
|
+
this.removeNativeZoomControl()
|
|
203
|
+
}
|
|
202
204
|
this.alignTopRightControls()
|
|
203
205
|
}
|
|
204
206
|
|
|
@@ -16,7 +16,7 @@ type MeasureToolsCallbacks = {
|
|
|
16
16
|
type MeasureMode = 'line' | 'polygon'
|
|
17
17
|
|
|
18
18
|
const LINE_ICON =
|
|
19
|
-
'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="
|
|
19
|
+
'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21.3 15.3a2.4 2.4 0 0 1 0 3.4l-2.6 2.6a2.4 2.4 0 0 1-3.4 0L2.7 8.7a2.41 2.41 0 0 1 0-3.4l2.6-2.6a2.41 2.41 0 0 1 3.4 0Z"/><path d="m14.5 12.5 2-2"/><path d="m11.5 9.5 2-2"/><path d="m8.5 6.5 2-2"/><path d="m17.5 15.5 2-2"/></svg>'
|
|
20
20
|
|
|
21
21
|
const POLYGON_ICON =
|
|
22
22
|
'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2l8 5v10l-8 5-8-5V7z"/></svg>'
|
|
@@ -135,28 +135,34 @@ export default class MeasureToolsHandler {
|
|
|
135
135
|
)
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
-
handler.
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
138
|
+
if (handler.isInteractionPanelEnabled()) {
|
|
139
|
+
handler._interactionPanel = L.DomUtil.create(
|
|
140
|
+
'div',
|
|
141
|
+
'measure-tools-interaction js-measure-interaction',
|
|
142
|
+
container
|
|
143
|
+
)
|
|
144
|
+
handler._interactionPanel.style.display = 'none'
|
|
145
|
+
handler._interactionPanel.innerHTML = handler.buildInteractionHtml(config)
|
|
146
|
+
|
|
147
|
+
handler._resultsEl = handler._interactionPanel.querySelector('.js-results')
|
|
148
|
+
handler._helpEl = handler._interactionPanel.querySelector('.js-measure-help')
|
|
149
|
+
|
|
150
|
+
const cancelBtn = handler._interactionPanel.querySelector('.js-cancel')
|
|
151
|
+
const finishBtn = handler._interactionPanel.querySelector('.js-finish')
|
|
152
|
+
|
|
153
|
+
if (cancelBtn instanceof HTMLElement) {
|
|
154
|
+
L.DomEvent.on(cancelBtn, 'click', (e) => {
|
|
155
|
+
L.DomEvent.stop(e)
|
|
156
|
+
handler.cancel()
|
|
157
|
+
})
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (finishBtn instanceof HTMLElement) {
|
|
161
|
+
L.DomEvent.on(finishBtn, 'click', (e) => {
|
|
162
|
+
L.DomEvent.stop(e)
|
|
163
|
+
handler.finishDrawing()
|
|
164
|
+
})
|
|
165
|
+
}
|
|
160
166
|
}
|
|
161
167
|
|
|
162
168
|
L.DomEvent.disableClickPropagation(container)
|
|
@@ -170,6 +176,10 @@ export default class MeasureToolsHandler {
|
|
|
170
176
|
this._control.addTo(this._map)
|
|
171
177
|
}
|
|
172
178
|
|
|
179
|
+
private isInteractionPanelEnabled(): boolean {
|
|
180
|
+
return this._config.showInteractionPanel !== false
|
|
181
|
+
}
|
|
182
|
+
|
|
173
183
|
private buildInteractionHtml(config: MapToolsConfig): string {
|
|
174
184
|
const title = config.texts?.measurePanelTitle ?? 'Measure distances and areas'
|
|
175
185
|
const cancel = config.texts?.measureCancel ?? 'Cancel'
|
|
@@ -228,6 +238,7 @@ export default class MeasureToolsHandler {
|
|
|
228
238
|
this.setMeasureActive(true)
|
|
229
239
|
this.updateButtons()
|
|
230
240
|
this.showInteractionPanel(mode)
|
|
241
|
+
document.addEventListener('keydown', this._boundEscapeKey)
|
|
231
242
|
|
|
232
243
|
if (this._map.doubleClickZoom.enabled()) {
|
|
233
244
|
this._map.doubleClickZoom.disable()
|
|
@@ -271,6 +282,7 @@ export default class MeasureToolsHandler {
|
|
|
271
282
|
this._map.options.zoomAnimation = this._restoreZoomAnimation
|
|
272
283
|
this.updateButtons()
|
|
273
284
|
this.hideInteractionPanel()
|
|
285
|
+
document.removeEventListener('keydown', this._boundEscapeKey)
|
|
274
286
|
|
|
275
287
|
if (!this._map.doubleClickZoom.enabled()) {
|
|
276
288
|
this._map.doubleClickZoom.enable()
|
|
@@ -377,7 +389,7 @@ export default class MeasureToolsHandler {
|
|
|
377
389
|
}
|
|
378
390
|
|
|
379
391
|
private showInteractionPanel(mode: MeasureMode): void {
|
|
380
|
-
if (!this._interactionPanel || !this._helpEl) return
|
|
392
|
+
if (!this.isInteractionPanelEnabled() || !this._interactionPanel || !this._helpEl) return
|
|
381
393
|
|
|
382
394
|
this._interactionPanel.style.removeProperty('display')
|
|
383
395
|
this._interactionPanel.closest('.leaflet-control-measure-tools')?.classList.add('measure-tools-expanded')
|
|
@@ -395,8 +407,6 @@ export default class MeasureToolsHandler {
|
|
|
395
407
|
if (this._resultsEl) {
|
|
396
408
|
this._resultsEl.innerHTML = ''
|
|
397
409
|
}
|
|
398
|
-
|
|
399
|
-
document.addEventListener('keydown', this._boundEscapeKey)
|
|
400
410
|
}
|
|
401
411
|
|
|
402
412
|
private hideInteractionPanel(): void {
|
|
@@ -404,7 +414,6 @@ export default class MeasureToolsHandler {
|
|
|
404
414
|
|
|
405
415
|
this._interactionPanel.style.display = 'none'
|
|
406
416
|
this._interactionPanel.closest('.leaflet-control-measure-tools')?.classList.remove('measure-tools-expanded')
|
|
407
|
-
document.removeEventListener('keydown', this._boundEscapeKey)
|
|
408
417
|
}
|
|
409
418
|
|
|
410
419
|
private updateButtons(): void {
|