@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
package/dist/types/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { MapOptions, Layer, PathOptions, ControlOptions, ControlPosition } from 'leaflet';
|
|
2
2
|
import { GeoJsonObject } from 'geojson';
|
|
3
3
|
import { PM } from '@geoman-io/leaflet-geoman-free';
|
|
4
|
-
export type FaIconName = 'check' | 'xmark' | 'chevron-right' | 'chevron-left' | 'terminal' | 'file-lines' | 'upload' | 'pencil' | 'trash' | 'chevron-down';
|
|
4
|
+
export type FaIconName = 'check' | 'xmark' | 'chevron-right' | 'chevron-left' | 'terminal' | 'file-lines' | 'upload' | 'pencil' | 'trash' | 'chevron-down' | 'eye' | 'eye-slash' | 'circle-info' | 'circle-exclamation' | 'triangle-exclamation' | 'circle-check' | 'circle-xmark' | 'ban' | 'lock' | 'unlock' | 'thumbtack' | 'thumb-tack' | 'map-pin';
|
|
5
5
|
export type DrawnArea = {
|
|
6
6
|
m2: number;
|
|
7
7
|
km2: number;
|
|
@@ -10,37 +10,135 @@ export type DrawnArea = {
|
|
|
10
10
|
export type IncrementedLayer = Layer & {
|
|
11
11
|
drawnArea: DrawnArea;
|
|
12
12
|
};
|
|
13
|
-
export type
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
export type LayerActionStyle = {
|
|
14
|
+
backgroundColor: string;
|
|
15
|
+
color: string;
|
|
16
|
+
borderColor?: string;
|
|
17
|
+
};
|
|
18
|
+
export type LayerActionDefaultItem = {
|
|
19
|
+
key?: string;
|
|
19
20
|
name: string;
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
icon?: FaIconName;
|
|
22
|
+
style?: LayerActionStyle;
|
|
23
|
+
disabled?: boolean;
|
|
24
|
+
visible?: boolean;
|
|
25
|
+
};
|
|
26
|
+
export type LayerActionDefaults = {
|
|
27
|
+
edit?: LayerActionDefaultItem;
|
|
28
|
+
import?: LayerActionDefaultItem;
|
|
29
|
+
delete?: LayerActionDefaultItem;
|
|
30
|
+
cancel?: LayerActionDefaultItem;
|
|
31
|
+
conclude?: LayerActionDefaultItem;
|
|
32
|
+
};
|
|
33
|
+
export type LayerActionConfig = {
|
|
34
|
+
key: string;
|
|
35
|
+
name: string;
|
|
36
|
+
icon?: FaIconName;
|
|
37
|
+
type?: 'edit' | 'import' | 'delete' | 'visibility' | 'custom' | 'cancel' | 'conclude';
|
|
38
|
+
disabled?: boolean;
|
|
39
|
+
visible?: boolean;
|
|
40
|
+
style?: LayerActionStyle;
|
|
41
|
+
};
|
|
42
|
+
export type LayerMetricsConfig = {
|
|
43
|
+
title: string;
|
|
44
|
+
type: string;
|
|
45
|
+
value: string | number;
|
|
46
|
+
style?: LayerActionStyle;
|
|
47
|
+
};
|
|
48
|
+
/** @deprecated Use LayerMetricsConfig */
|
|
49
|
+
export type LayerMetrics = LayerMetricsConfig;
|
|
50
|
+
export type LayerMetricsMap = Record<string, LayerMetricsConfig[]>;
|
|
51
|
+
export type LayerInfoIconConfig = {
|
|
52
|
+
key?: string;
|
|
53
|
+
icon: FaIconName;
|
|
22
54
|
active: boolean;
|
|
55
|
+
tooltip?: string;
|
|
56
|
+
style?: Partial<Pick<LayerActionStyle, 'color' | 'backgroundColor'>>;
|
|
57
|
+
};
|
|
58
|
+
export type LayerInfoIconsMap = Record<string, LayerInfoIconConfig[]>;
|
|
59
|
+
export type GroupActionConfig = LayerActionConfig & {
|
|
60
|
+
active: boolean;
|
|
61
|
+
};
|
|
62
|
+
export type GroupActionsMap = Record<string, GroupActionConfig[]>;
|
|
63
|
+
export type SectionConfig = {
|
|
64
|
+
name?: string;
|
|
23
65
|
key: string;
|
|
24
|
-
|
|
66
|
+
groups: GroupLayerData[];
|
|
67
|
+
actionDefaults?: LayerActionDefaults;
|
|
68
|
+
};
|
|
69
|
+
/** @deprecated Use SectionConfig */
|
|
70
|
+
export type SectionData = SectionConfig;
|
|
71
|
+
export type LayerData = {
|
|
72
|
+
key: string;
|
|
73
|
+
name: string;
|
|
74
|
+
active: boolean;
|
|
75
|
+
activeDefault: boolean;
|
|
76
|
+
role?: 'layer' | 'separator';
|
|
77
|
+
tooltip?: string;
|
|
78
|
+
toggle?: {
|
|
25
79
|
active: string;
|
|
26
80
|
inactive: string;
|
|
27
81
|
};
|
|
28
|
-
|
|
82
|
+
visibility?: {
|
|
83
|
+
labelShow?: string;
|
|
84
|
+
labelHide?: string;
|
|
85
|
+
show?: boolean;
|
|
86
|
+
};
|
|
87
|
+
style?: {
|
|
29
88
|
color: string;
|
|
30
89
|
fillColor: string;
|
|
90
|
+
icon?: string;
|
|
31
91
|
};
|
|
32
|
-
|
|
92
|
+
baseUrl?: string;
|
|
93
|
+
layers?: string;
|
|
94
|
+
format?: string;
|
|
95
|
+
transparent?: boolean;
|
|
96
|
+
geojson?: GeoJsonObject | GeoJsonObject[];
|
|
97
|
+
cqlFilter?: string;
|
|
98
|
+
options?: Record<string, unknown>;
|
|
99
|
+
mapSource?: 'wms' | 'geojson' | 'none' | 'consumer';
|
|
100
|
+
actions?: LayerActionConfig[];
|
|
101
|
+
metrics?: LayerMetricsConfig[];
|
|
102
|
+
infoIcons?: LayerInfoIconConfig[];
|
|
103
|
+
required?: boolean;
|
|
104
|
+
editActions?: LayerActionConfig[];
|
|
105
|
+
meta?: Record<string, unknown>;
|
|
33
106
|
};
|
|
34
107
|
export type GroupLayerData = {
|
|
35
108
|
name: string;
|
|
36
109
|
key: string;
|
|
37
|
-
toggle
|
|
110
|
+
toggle?: {
|
|
38
111
|
active: string;
|
|
39
112
|
inactive: string;
|
|
40
113
|
};
|
|
114
|
+
visibility?: {
|
|
115
|
+
show?: boolean;
|
|
116
|
+
labelShow?: string;
|
|
117
|
+
labelHide?: string;
|
|
118
|
+
};
|
|
119
|
+
collapsed?: boolean;
|
|
120
|
+
actions?: GroupActionConfig[];
|
|
41
121
|
layers: LayerData[];
|
|
122
|
+
meta?: Record<string, unknown>;
|
|
123
|
+
};
|
|
124
|
+
export type LayersConfig = GroupLayerData[] | SectionConfig[];
|
|
125
|
+
export type LayerActionPayload = {
|
|
126
|
+
actionKey: string;
|
|
127
|
+
actionType?: LayerActionConfig['type'];
|
|
128
|
+
sectionKey?: string;
|
|
129
|
+
groupKey?: string;
|
|
130
|
+
layerKey?: string;
|
|
131
|
+
layer?: LayerData;
|
|
132
|
+
source: 'child-menu' | 'edit-panel' | 'group-menu';
|
|
133
|
+
};
|
|
134
|
+
export type SectionEditStatePayload = {
|
|
135
|
+
sectionKey: string | null;
|
|
136
|
+
layerKey: string | null;
|
|
137
|
+
layer: LayerData | null;
|
|
138
|
+
};
|
|
139
|
+
export type SectionSelectPayload = {
|
|
140
|
+
sectionKey: string;
|
|
42
141
|
};
|
|
43
|
-
export type LayersConfig = GroupLayerData[];
|
|
44
142
|
export type DrawingEvent = {
|
|
45
143
|
type: 'created' | 'edited' | 'deleted';
|
|
46
144
|
layer: IncrementedLayer;
|
|
@@ -66,7 +164,6 @@ export type MapConfigConfig = MapOptions & {
|
|
|
66
164
|
id: string;
|
|
67
165
|
removeControlLayers?: boolean;
|
|
68
166
|
zoomControlPosition?: ControlPosition;
|
|
69
|
-
/** Reposiciona marcadores após zoom (evita drift de divIcon). Padrão: true. */
|
|
70
167
|
stabilizeMarkersOnZoom?: boolean;
|
|
71
168
|
};
|
|
72
169
|
export type MapConfig = {
|
|
@@ -76,6 +173,10 @@ export type LayersMenuConfig = {
|
|
|
76
173
|
size: 'small' | 'medium' | 'large';
|
|
77
174
|
removeMenu?: boolean;
|
|
78
175
|
persist: boolean;
|
|
176
|
+
editingLayerKey?: string | null;
|
|
177
|
+
selectedSectionKey?: string | null;
|
|
178
|
+
visibilityMode?: 'switch' | 'eye';
|
|
179
|
+
defaultOpen?: boolean;
|
|
79
180
|
};
|
|
80
181
|
export type MemorialConfig = {
|
|
81
182
|
show: boolean;
|
|
@@ -113,6 +214,7 @@ export type MapToolsConfig = {
|
|
|
113
214
|
show?: boolean;
|
|
114
215
|
title?: string;
|
|
115
216
|
};
|
|
217
|
+
showInteractionPanel?: boolean;
|
|
116
218
|
texts?: {
|
|
117
219
|
measureResult?: string;
|
|
118
220
|
measureLength?: string;
|
|
@@ -211,6 +313,7 @@ export type CoordinatePanelTexts = {
|
|
|
211
313
|
dragShapefileZip?: string;
|
|
212
314
|
shapefileZipInfo?: string;
|
|
213
315
|
shapefileAppliedSuccess?: string;
|
|
316
|
+
geometryImportUnsupportedFormat?: string;
|
|
214
317
|
placeholderLongitude?: string;
|
|
215
318
|
placeholderLatitude?: string;
|
|
216
319
|
placeholderAzimuth?: string;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { GroupActionConfig, GroupActionsMap, GroupLayerData, LayerActionConfig, LayerActionDefaults, LayerData, LayerInfoIconConfig, LayerInfoIconsMap, LayerMetricsConfig, LayerMetricsMap, LayersConfig, SectionConfig } from '../types';
|
|
2
|
+
export declare const isSectionConfig: (item: unknown) => item is SectionConfig;
|
|
3
|
+
export declare const isGroupConfig: (item: unknown) => item is GroupLayerData;
|
|
4
|
+
export declare const normalizeLayersConfig: (config?: LayersConfig | null) => SectionConfig[];
|
|
5
|
+
export declare const resolveLayerActions: (layer: LayerData, defaults?: LayerActionDefaults) => LayerActionConfig[];
|
|
6
|
+
export declare const resolveEditControlAction: (defaults: LayerActionDefaults | undefined, kind: "cancel" | "conclude") => LayerActionConfig;
|
|
7
|
+
export declare const isMenuSeparator: (layer: LayerData | null | undefined) => boolean;
|
|
8
|
+
export declare const shouldApplyMapOverlay: (layer: LayerData) => boolean;
|
|
9
|
+
export declare const collectLayerMetricsMap: (config?: LayersConfig | null) => LayerMetricsMap;
|
|
10
|
+
export declare const resolveLayerMetrics: (layer: LayerData | null | undefined) => LayerMetricsConfig[];
|
|
11
|
+
export declare const collectLayerInfoIconsMap: (config?: LayersConfig | null) => LayerInfoIconsMap;
|
|
12
|
+
export declare const resolveActiveLayerInfoIcons: (layer: LayerData | null | undefined) => LayerInfoIconConfig[];
|
|
13
|
+
export declare const collectGroupActionsMap: (config?: LayersConfig | null) => GroupActionsMap;
|
|
14
|
+
export declare const resolveActiveGroupActions: (group: GroupLayerData | null | undefined) => GroupActionConfig[];
|
|
15
|
+
export declare const withLayerInfoIconActive: (infoIcons: LayerInfoIconConfig[] | undefined, iconRef: string, active: boolean) => LayerInfoIconConfig[] | null;
|
|
16
|
+
export declare const withGroupActionActive: (actions: GroupActionConfig[] | undefined, actionKey: string, active: boolean) => GroupActionConfig[] | null;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { LayerData } from '../types';
|
|
2
2
|
export declare const setHistory: (layer: LayerData) => void;
|
|
3
|
-
/** Retorna o estado salvo da camada ou `undefined` se não houver histórico. */
|
|
4
3
|
export declare const getHistory: (layerKey: string) => boolean | undefined;
|
|
5
|
-
|
|
4
|
+
export declare const setGroupCollapsedHistory: (groupKey: string, collapsed: boolean) => void;
|
|
5
|
+
export declare const getGroupCollapsedHistory: (groupKey: string) => boolean | undefined;
|
|
6
6
|
export declare const resolveLayerActiveState: (layer: LayerData, persist: boolean) => LayerData;
|
|
7
|
-
|
|
7
|
+
export declare const resolveGroupCollapsedState: (groupKey: string, collapsedFromConfig: boolean | undefined, persist: boolean) => boolean;
|
|
8
8
|
export declare const shouldInitLayerOnMap: (layer: LayerData, persist: boolean) => boolean;
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export type ShapefileParseResult =
|
|
3
|
-
ok: true;
|
|
4
|
-
features: Feature[];
|
|
5
|
-
} | {
|
|
6
|
-
ok: false;
|
|
7
|
-
error: string;
|
|
8
|
-
};
|
|
1
|
+
import type { GeometryFileParseResult } from './geometryFileParseResult';
|
|
2
|
+
export type ShapefileParseResult = GeometryFileParseResult;
|
|
9
3
|
export declare function parseShapefileZip(file: File): Promise<ShapefileParseResult>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { Feature, MultiPolygon, Polygon } from 'geojson';
|
|
2
|
-
export type
|
|
2
|
+
export type ImportedPolygonValidationResult = {
|
|
3
3
|
ok: true;
|
|
4
4
|
feature: Feature<Polygon | MultiPolygon>;
|
|
5
5
|
} | {
|
|
6
6
|
ok: false;
|
|
7
7
|
error: string;
|
|
8
8
|
};
|
|
9
|
-
export declare function
|
|
9
|
+
export declare function validateImportedPolygonGeometry(features: Feature[]): ImportedPolygonValidationResult;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rural-environmental-registry/map_component",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Map component for Vue.js applications",
|
|
5
5
|
"main": "dist/index.mjs",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -47,7 +47,8 @@
|
|
|
47
47
|
"leaflet": "1.9.4",
|
|
48
48
|
"leaflet-draw": "1.0.4",
|
|
49
49
|
"papaparse": "5.5.3",
|
|
50
|
-
"shpjs": "6.1.0"
|
|
50
|
+
"shpjs": "6.1.0",
|
|
51
|
+
"@tmcw/togeojson": "7.1.2"
|
|
51
52
|
},
|
|
52
53
|
"devDependencies": {
|
|
53
54
|
"@types/geojson": "7946.0.16",
|
|
@@ -25,6 +25,9 @@
|
|
|
25
25
|
:options="options.layersMenu"
|
|
26
26
|
@onChildLayerToggle="emit('onChildLayerToggle', $event)"
|
|
27
27
|
@onGroupLayerToggle="emit('onGroupLayerToggle', $event)"
|
|
28
|
+
@onLayerAction="emit('onLayerAction', $event)"
|
|
29
|
+
@onSectionEditStateChange="emit('onSectionEditStateChange', $event)"
|
|
30
|
+
@onSelectedSectionChange="emit('onSelectedSectionChange', $event)"
|
|
28
31
|
@startLoading="isLoading = true"
|
|
29
32
|
@stopLoading="isLoading = false"
|
|
30
33
|
/>
|
|
@@ -46,13 +49,22 @@
|
|
|
46
49
|
import { computed, ref } from 'vue'
|
|
47
50
|
import {
|
|
48
51
|
DrawingEvent,
|
|
52
|
+
GroupActionConfig,
|
|
53
|
+
GroupActionsMap,
|
|
49
54
|
GroupLayerData,
|
|
50
55
|
IncrementedLayer,
|
|
56
|
+
LayerActionPayload,
|
|
51
57
|
LayerData,
|
|
58
|
+
LayerInfoIconConfig,
|
|
59
|
+
LayerInfoIconsMap,
|
|
60
|
+
LayerMetricsConfig,
|
|
61
|
+
LayerMetricsMap,
|
|
52
62
|
MapLayers,
|
|
53
63
|
MapOptionsConfig,
|
|
54
64
|
DescriptiveMemorial,
|
|
55
|
-
MeasureCompleteEvent
|
|
65
|
+
MeasureCompleteEvent,
|
|
66
|
+
SectionEditStatePayload,
|
|
67
|
+
SectionSelectPayload
|
|
56
68
|
} from '../types'
|
|
57
69
|
import Loading from './loading/Loading.vue'
|
|
58
70
|
import Map from './map/LeafletMap.vue'
|
|
@@ -61,6 +73,14 @@
|
|
|
61
73
|
import { isMemorialLayer, MEMORIAL_KEY } from '../utils/memorialLayer'
|
|
62
74
|
import { calculateLayerArea } from '../utils/geometryCalculator'
|
|
63
75
|
import { resolveDrawingPathOptions } from '../utils/drawingPathOptions'
|
|
76
|
+
import {
|
|
77
|
+
collectGroupActionsMap,
|
|
78
|
+
collectLayerInfoIconsMap,
|
|
79
|
+
collectLayerMetricsMap,
|
|
80
|
+
normalizeLayersConfig,
|
|
81
|
+
withGroupActionActive,
|
|
82
|
+
withLayerInfoIconActive
|
|
83
|
+
} from '../utils/layersConfigNormalizer'
|
|
64
84
|
import type { MemorialDrawShape } from '../utils/drawingPathOptions'
|
|
65
85
|
import type { Feature, MultiPolygon, Polygon } from 'geojson'
|
|
66
86
|
|
|
@@ -88,6 +108,12 @@
|
|
|
88
108
|
const emit = defineEmits<{
|
|
89
109
|
(e: 'onGroupLayerToggle', data: GroupLayerData): void
|
|
90
110
|
(e: 'onChildLayerToggle', data: LayerData): void
|
|
111
|
+
(e: 'onLayerAction', payload: LayerActionPayload): void
|
|
112
|
+
(e: 'onSectionEditStateChange', payload: SectionEditStatePayload): void
|
|
113
|
+
(e: 'onSelectedSectionChange', payload: SectionSelectPayload): void
|
|
114
|
+
(e: 'onLayerMetricsUpdate', payload: { layerKey: string; metrics: LayerMetricsConfig[] }): void
|
|
115
|
+
(e: 'onLayerInfoIconsUpdate', payload: { layerKey: string; infoIcons: LayerInfoIconConfig[] }): void
|
|
116
|
+
(e: 'onGroupActionsUpdate', payload: { groupKey: string; actions: GroupActionConfig[] }): void
|
|
91
117
|
(e: 'onDrawing', data: DrawingEvent): void
|
|
92
118
|
(e: 'onCoordinateSystemChange', system: string): void
|
|
93
119
|
(e: 'onFullscreenChange', active: boolean): void
|
|
@@ -112,6 +138,60 @@
|
|
|
112
138
|
const coordinatePanelRef = ref()
|
|
113
139
|
const isLoading = ref<boolean>(false)
|
|
114
140
|
|
|
141
|
+
const metrics = computed((): LayerMetricsMap =>
|
|
142
|
+
collectLayerMetricsMap(props.layers?.customLayers)
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
const infoIcons = computed((): LayerInfoIconsMap =>
|
|
146
|
+
collectLayerInfoIconsMap(props.layers?.customLayers)
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
const groupActions = computed((): GroupActionsMap =>
|
|
150
|
+
collectGroupActionsMap(props.layers?.customLayers)
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
const setLayerMetrics = (layerKey: string, nextMetrics: LayerMetricsConfig[]): void => {
|
|
154
|
+
emit('onLayerMetricsUpdate', { layerKey, metrics: nextMetrics })
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const findLayerInfoIcons = (layerKey: string): LayerInfoIconConfig[] | undefined => {
|
|
158
|
+
for (const section of normalizeLayersConfig(props.layers?.customLayers)) {
|
|
159
|
+
for (const group of section.groups) {
|
|
160
|
+
const layer = group.layers?.find((item) => item.key === layerKey)
|
|
161
|
+
if (layer) return layer.infoIcons
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return undefined
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const findGroupActions = (groupKey: string): GroupActionConfig[] | undefined => {
|
|
168
|
+
for (const section of normalizeLayersConfig(props.layers?.customLayers)) {
|
|
169
|
+
const group = section.groups.find((item) => item.key === groupKey)
|
|
170
|
+
if (group) return group.actions
|
|
171
|
+
}
|
|
172
|
+
return undefined
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const setLayerInfoIconActive = (layerKey: string, iconRef: string, active: boolean): void => {
|
|
176
|
+
const next = withLayerInfoIconActive(findLayerInfoIcons(layerKey), iconRef, active)
|
|
177
|
+
if (!next) return
|
|
178
|
+
emit('onLayerInfoIconsUpdate', { layerKey, infoIcons: next })
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const setLayerInfoIcons = (layerKey: string, nextInfoIcons: LayerInfoIconConfig[]): void => {
|
|
182
|
+
emit('onLayerInfoIconsUpdate', { layerKey, infoIcons: nextInfoIcons })
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const setGroupActionActive = (groupKey: string, actionKey: string, active: boolean): void => {
|
|
186
|
+
const next = withGroupActionActive(findGroupActions(groupKey), actionKey, active)
|
|
187
|
+
if (!next) return
|
|
188
|
+
emit('onGroupActionsUpdate', { groupKey, actions: next })
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const setGroupActions = (groupKey: string, nextActions: GroupActionConfig[]): void => {
|
|
192
|
+
emit('onGroupActionsUpdate', { groupKey, actions: nextActions })
|
|
193
|
+
}
|
|
194
|
+
|
|
115
195
|
const getMemorialPathOptions = (shape: MemorialDrawShape): L.PathOptions =>
|
|
116
196
|
mapRef.value?.getDrawingPathOptions(shape) ??
|
|
117
197
|
resolveDrawingPathOptions(mapRef.value?.map, props.options.drawing, shape)
|
|
@@ -276,7 +356,15 @@
|
|
|
276
356
|
enterFullscreen,
|
|
277
357
|
exitFullscreen,
|
|
278
358
|
toggleFullscreen,
|
|
279
|
-
toggleMeasureArea
|
|
359
|
+
toggleMeasureArea,
|
|
360
|
+
metrics,
|
|
361
|
+
setLayerMetrics,
|
|
362
|
+
infoIcons,
|
|
363
|
+
setLayerInfoIcons,
|
|
364
|
+
setLayerInfoIconActive,
|
|
365
|
+
groupActions,
|
|
366
|
+
setGroupActions,
|
|
367
|
+
setGroupActionActive
|
|
280
368
|
})
|
|
281
369
|
</script>
|
|
282
370
|
|
|
@@ -320,9 +320,9 @@
|
|
|
320
320
|
<input
|
|
321
321
|
ref="shapefileInputRef"
|
|
322
322
|
type="file"
|
|
323
|
-
accept=".zip"
|
|
323
|
+
accept=".zip,.kml,.geojson,.json"
|
|
324
324
|
class="shapefile-input-hidden"
|
|
325
|
-
@change="
|
|
325
|
+
@change="handleGeometryFileInputChange"
|
|
326
326
|
/>
|
|
327
327
|
</div>
|
|
328
328
|
</template>
|
|
@@ -353,7 +353,10 @@
|
|
|
353
353
|
import MemorialButtonControl from '../../handlers/memorialButtonControl'
|
|
354
354
|
import type { DescriptiveMemorial } from '../../types'
|
|
355
355
|
import { parseShapefileZip } from '../../utils/parseShapefileZip'
|
|
356
|
-
import {
|
|
356
|
+
import { parseGeoJsonFile } from '../../utils/parseGeoJsonFile'
|
|
357
|
+
import { parseKmlFile } from '../../utils/parseKmlFile'
|
|
358
|
+
import { validateImportedPolygonGeometry } from '../../utils/validateImportedPolygonGeometry'
|
|
359
|
+
import type { GeometryFileParseResult } from '../../utils/geometryFileParseResult'
|
|
357
360
|
import type { Feature, MultiPolygon, Polygon } from 'geojson'
|
|
358
361
|
|
|
359
362
|
interface CSVRow {
|
|
@@ -669,18 +672,38 @@
|
|
|
669
672
|
shapefileInputRef.value?.click()
|
|
670
673
|
}
|
|
671
674
|
|
|
672
|
-
const
|
|
675
|
+
const getGeometryFileExtension = (fileName: string): 'zip' | 'kml' | 'geojson' | null => {
|
|
676
|
+
const lower = fileName.toLowerCase()
|
|
677
|
+
|
|
678
|
+
if (lower.endsWith('.zip')) return 'zip'
|
|
679
|
+
if (lower.endsWith('.kml')) return 'kml'
|
|
680
|
+
if (lower.endsWith('.geojson') || lower.endsWith('.json')) return 'geojson'
|
|
681
|
+
|
|
682
|
+
return null
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
const parseGeometryFile = async (file: File): Promise<GeometryFileParseResult> => {
|
|
686
|
+
const extension = getGeometryFileExtension(file.name)
|
|
687
|
+
|
|
688
|
+
if (extension === 'zip') return parseShapefileZip(file)
|
|
689
|
+
if (extension === 'kml') return parseKmlFile(file)
|
|
690
|
+
if (extension === 'geojson') return parseGeoJsonFile(file)
|
|
691
|
+
|
|
692
|
+
return { ok: false, error: texts.value.geometryImportUnsupportedFormat || 'Unsupported file format' }
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
const processGeometryFile = async (file: File) => {
|
|
673
696
|
emit('geometryRemoved')
|
|
674
697
|
csvData.value = []
|
|
675
698
|
shapefileLoaded.value = false
|
|
676
699
|
|
|
677
|
-
const parseResult = await
|
|
700
|
+
const parseResult = await parseGeometryFile(file)
|
|
678
701
|
if (!parseResult.ok) {
|
|
679
702
|
ElMessage.error(parseResult.error)
|
|
680
703
|
return
|
|
681
704
|
}
|
|
682
705
|
|
|
683
|
-
const validationResult =
|
|
706
|
+
const validationResult = validateImportedPolygonGeometry(parseResult.features)
|
|
684
707
|
if (!validationResult.ok) {
|
|
685
708
|
ElMessage.error(validationResult.error)
|
|
686
709
|
return
|
|
@@ -691,12 +714,12 @@
|
|
|
691
714
|
ElMessage.success(texts.value.shapefileAppliedSuccess)
|
|
692
715
|
}
|
|
693
716
|
|
|
694
|
-
const
|
|
717
|
+
const handleGeometryFileInputChange = async (event: Event) => {
|
|
695
718
|
const input = event.target as HTMLInputElement
|
|
696
719
|
const file = input.files?.[0]
|
|
697
720
|
if (!file) return
|
|
698
721
|
|
|
699
|
-
await
|
|
722
|
+
await processGeometryFile(file)
|
|
700
723
|
input.value = ''
|
|
701
724
|
}
|
|
702
725
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<FontAwesomeIcon :icon="['fas',
|
|
2
|
+
<FontAwesomeIcon :icon="['fas', resolvedIconName]" />
|
|
3
3
|
</template>
|
|
4
4
|
|
|
5
5
|
<script setup lang="ts">
|
|
6
|
+
import { computed } from 'vue'
|
|
6
7
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
|
7
8
|
import {
|
|
8
9
|
faCheck,
|
|
@@ -14,16 +15,33 @@
|
|
|
14
15
|
faUpload,
|
|
15
16
|
faPencil,
|
|
16
17
|
faTrash,
|
|
17
|
-
faChevronDown
|
|
18
|
+
faChevronDown,
|
|
19
|
+
faEye,
|
|
20
|
+
faEyeSlash,
|
|
21
|
+
faCircleInfo,
|
|
22
|
+
faCircleExclamation,
|
|
23
|
+
faTriangleExclamation,
|
|
24
|
+
faCircleCheck,
|
|
25
|
+
faCircleXmark,
|
|
26
|
+
faBan,
|
|
27
|
+
faLock,
|
|
28
|
+
faUnlock,
|
|
29
|
+
faThumbtack,
|
|
30
|
+
faMapPin
|
|
18
31
|
} from '@fortawesome/free-solid-svg-icons'
|
|
19
32
|
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
|
|
20
33
|
import { FaIconName } from '../../types'
|
|
21
34
|
|
|
22
35
|
type IconProps = {
|
|
23
|
-
iconName: FaIconName
|
|
36
|
+
iconName: FaIconName | string
|
|
24
37
|
}
|
|
25
38
|
|
|
26
|
-
defineProps<IconProps>()
|
|
39
|
+
const props = defineProps<IconProps>()
|
|
40
|
+
|
|
41
|
+
const resolvedIconName = computed(() => {
|
|
42
|
+
const raw = props.iconName?.trim() ?? ''
|
|
43
|
+
return raw.replace(/^(fas|far|fal|fab)\s+/i, '').replace(/^fa-/i, '')
|
|
44
|
+
})
|
|
27
45
|
|
|
28
46
|
library.add(
|
|
29
47
|
faCheck,
|
|
@@ -35,7 +53,19 @@
|
|
|
35
53
|
faUpload,
|
|
36
54
|
faPencil,
|
|
37
55
|
faTrash,
|
|
38
|
-
faChevronDown
|
|
56
|
+
faChevronDown,
|
|
57
|
+
faEye,
|
|
58
|
+
faEyeSlash,
|
|
59
|
+
faCircleInfo,
|
|
60
|
+
faCircleExclamation,
|
|
61
|
+
faTriangleExclamation,
|
|
62
|
+
faCircleCheck,
|
|
63
|
+
faCircleXmark,
|
|
64
|
+
faBan,
|
|
65
|
+
faLock,
|
|
66
|
+
faUnlock,
|
|
67
|
+
faThumbtack,
|
|
68
|
+
faMapPin
|
|
39
69
|
)
|
|
40
70
|
</script>
|
|
41
71
|
|
|
@@ -81,10 +81,12 @@
|
|
|
81
81
|
|
|
82
82
|
const initMap = (): void => {
|
|
83
83
|
const { config } = props.mapOptions
|
|
84
|
+
const toolsConfig = resolveMapToolsConfig(props.toolsOptions)
|
|
85
|
+
const useToolsZoom = !!toolsConfig && toolsConfig.zoom?.show !== false
|
|
84
86
|
const mapConfig: MapConfigConfig = {
|
|
85
87
|
...DEFAULT_MAP_OPTIONS,
|
|
86
88
|
...config,
|
|
87
|
-
...(
|
|
89
|
+
...(useToolsZoom ? { zoomControl: false } : {})
|
|
88
90
|
}
|
|
89
91
|
|
|
90
92
|
mapHandlerInstance = new MapHandler(mapConfig)
|