@vcmap/ui 6.1.0-rc.7 → 6.1.1
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/build/bundle.js +3 -3
- package/config/base.config.json +7 -3
- package/config/cluster.config.json +1 -1
- package/config/dev.config.json +172 -56
- package/config/projects.config.json +2 -1
- package/config/vectorTile.config.json +42 -1
- package/dist/assets/cesium.js +1 -1
- package/dist/assets/{core-52c2ef11.js → core-5ae90f6d.js} +7515 -5451
- package/dist/assets/core.js +1 -1
- package/dist/assets/ol.js +1 -1
- package/dist/assets/{ui-dccb9009.css → ui-e659989f.css} +1 -1
- package/dist/assets/{ui-dccb9009.js → ui-e659989f.js} +21736 -20926
- package/dist/assets/ui.js +1 -1
- package/dist/assets/vue.js +1 -1
- package/dist/assets/{vuetify-43a20e18.css → vuetify-cc6a8213.css} +2 -2
- package/dist/assets/{vuetify-43a20e18.js → vuetify-cc6a8213.js} +6694 -6593
- package/dist/assets/vuetify.js +1 -1
- package/index.d.ts +14 -6
- package/index.js +14 -5
- package/package.json +18 -9
- package/plugins/@vcmap-show-case/vector-properties-example/src/LayerSettings.vue +39 -0
- package/plugins/@vcmap-show-case/vector-properties-example/src/VectorPropertiesExample.vue +3 -0
- package/plugins/@vcmap-show-case/vector-properties-example/src/lib.js +13 -0
- package/plugins/@vcmap-show-case/window-tester/src/WindowExample.vue +9 -0
- package/plugins/package.json +9 -5
- package/src/actions/actionHelper.d.ts +6 -0
- package/src/actions/actionHelper.js +30 -2
- package/src/actions/deepPickingAction.d.ts +23 -0
- package/src/actions/deepPickingAction.js +404 -0
- package/src/actions/extentActions.js +20 -6
- package/src/actions/flightActions.js +5 -1
- package/src/application/VcsApp.vue +33 -21
- package/src/application/VcsApp.vue.d.ts +4 -0
- package/src/application/VcsAttributionsFooter.vue +1 -0
- package/src/application/VcsContainer.vue +1 -0
- package/src/application/VcsContainer.vue.d.ts +4 -0
- package/src/application/VcsMobileMenuList.vue +34 -41
- package/src/application/VcsNavbar.vue +3 -0
- package/src/application/VcsNavbarMobile.vue +6 -18
- package/src/application/VcsNavbarMobile.vue.d.ts +0 -1
- package/src/application/VcsPositionDisplay.vue +1 -0
- package/src/callback/activateLayersCallback.js +9 -1
- package/src/callback/addModuleCallback.js +2 -1
- package/src/components/buttons/VcsActionButtonList.vue +1 -0
- package/src/components/form-inputs-controls/VcsSelect.vue +8 -6
- package/src/components/icons/+all.d.ts +5 -0
- package/src/components/icons/+all.js +14 -0
- package/src/components/lists/VcsActionList.vue +1 -0
- package/src/components/lists/VcsGroupedList.vue +2 -1
- package/src/components/lists/VcsListItemComponent.vue +1 -0
- package/src/components/lists/VcsTreeNode.vue +5 -1
- package/src/components/lists/VcsTreeview.vue +14 -2
- package/src/components/style/{MenuWrapper.vue → StyleMenuWrapper.vue} +2 -1
- package/src/components/style/VcsFillMenu.vue +4 -4
- package/src/components/style/VcsImageMenu.vue +4 -4
- package/src/components/style/VcsStrokeMenu.vue +4 -4
- package/src/components/style/VcsTextMenu.vue +4 -4
- package/src/contentTree/LayerTree.vue +8 -46
- package/src/contentTree/LayerTree.vue.d.ts +1 -3
- package/src/contentTree/contentTreeCollection.d.ts +7 -0
- package/src/contentTree/contentTreeCollection.js +30 -10
- package/src/contentTree/contentTreeItem.d.ts +4 -4
- package/src/contentTree/contentTreeItem.js +2 -2
- package/src/contentTree/groupContentTreeItem.d.ts +5 -0
- package/src/contentTree/groupContentTreeItem.js +1 -1
- package/src/contentTree/layerContentTreeItem.js +1 -1
- package/src/contentTree/layerGroupContentTreeItem.js +11 -1
- package/src/contentTree/nodeContentTreeItem.d.ts +21 -0
- package/src/contentTree/nodeContentTreeItem.js +31 -2
- package/src/contentTree/wmsChildContentTreeItem.d.ts +56 -0
- package/src/contentTree/wmsChildContentTreeItem.js +159 -0
- package/src/contentTree/wmsGroupContentTreeItem.d.ts +171 -0
- package/src/contentTree/wmsGroupContentTreeItem.js +620 -0
- package/src/featureInfo/ClusterFeatureComponent.vue +47 -11
- package/src/featureInfo/ClusterFeatureComponent.vue.d.ts +1 -0
- package/src/featureInfo/balloonFeatureInfoView.d.ts +3 -0
- package/src/featureInfo/balloonFeatureInfoView.js +78 -11
- package/src/featureInfo/balloonHelper.js +8 -12
- package/src/featureInfo/featureInfo.d.ts +32 -7
- package/src/featureInfo/featureInfo.js +193 -91
- package/src/i18n/de.d.ts +22 -16
- package/src/i18n/de.js +4 -0
- package/src/i18n/en.d.ts +22 -16
- package/src/i18n/en.js +4 -0
- package/src/legend/legendHelper.d.ts +15 -0
- package/src/legend/legendHelper.js +28 -3
- package/src/manager/toolbox/GroupToolboxComponent.vue +1 -0
- package/src/manager/toolbox/SelectToolboxComponent.vue +2 -0
- package/src/manager/toolbox/ToolboxManagerComponent.vue +1 -0
- package/src/manager/window/windowManager.d.ts +2 -2
- package/src/manager/window/windowManager.js +17 -16
- package/src/navigation/MapNavigation.vue +3 -1
- package/src/navigation/overviewMap.js +1 -1
- package/src/notifier/NotifierComponent.vue +1 -0
- package/src/search/ResultsComponent.vue +10 -1
- package/src/search/SearchComponent.vue +11 -6
- package/src/search/search.js +3 -16
- package/src/state.d.ts +2 -1
- package/src/state.js +2 -1
- package/src/uiConfig.d.ts +9 -0
- package/src/uiConfig.js +1 -0
- package/src/vcsUiApp.js +7 -1
- /package/dist/assets/{cesium-6c6aa853.js → cesium-be8a1422.js} +0 -0
- /package/dist/assets/{ol-b0589b0c.js → ol-d5f8aba6.js} +0 -0
- /package/dist/assets/{vue-f7a0b088.js → vue-3435e55b.js} +0 -0
- /package/src/components/style/{MenuWrapper.vue.d.ts → StyleMenuWrapper.vue.d.ts} +0 -0
@@ -0,0 +1,404 @@
|
|
1
|
+
import {
|
2
|
+
cartesianToMercator,
|
3
|
+
FeatureProviderInteraction,
|
4
|
+
getFeatureFromPickObject,
|
5
|
+
isProvidedClusterFeature,
|
6
|
+
isProvidedFeature,
|
7
|
+
markVolatile,
|
8
|
+
maxZIndex,
|
9
|
+
mercatorProjection,
|
10
|
+
mercatorToCartesian,
|
11
|
+
moduleIdSymbol,
|
12
|
+
originalFeatureSymbol,
|
13
|
+
vcsLayerName,
|
14
|
+
vectorClusterGroupName,
|
15
|
+
VectorLayer,
|
16
|
+
VectorStyleItem,
|
17
|
+
volatileModuleId,
|
18
|
+
} from '@vcmap/core';
|
19
|
+
import { Feature } from 'ol';
|
20
|
+
import { Point, LineString } from 'ol/geom.js';
|
21
|
+
import { Icon } from 'ol/style.js';
|
22
|
+
import { Cartesian3, Ray } from '@vcmap-cesium/engine';
|
23
|
+
import { watch } from 'vue';
|
24
|
+
import { getLogger } from '@vcsuite/logger';
|
25
|
+
import { getColorByKey } from '../vuePlugins/vuetify.js';
|
26
|
+
import ClusterFeatureComponent from '../featureInfo/ClusterFeatureComponent.vue';
|
27
|
+
import { WindowSlot } from '../manager/window/windowManager.js';
|
28
|
+
import { vcsAppSymbol } from '../pluginHelper.js';
|
29
|
+
import {
|
30
|
+
featureInfoViewSymbol,
|
31
|
+
getFeatureInfoViewForFeature,
|
32
|
+
getGroupedFeatureList,
|
33
|
+
} from '../featureInfo/featureInfo.js';
|
34
|
+
import { getColoredMapIcon } from '../components/icons/+all.js';
|
35
|
+
|
36
|
+
const scratchCartesian = new Cartesian3();
|
37
|
+
const pickingZOffset = 10.0;
|
38
|
+
const iconScale = 1.5;
|
39
|
+
|
40
|
+
export const deepPickingWindowId = 'deep-picking-window';
|
41
|
+
|
42
|
+
/**
|
43
|
+
* @param {import("@vcmap/ui").VcsUiApp} app
|
44
|
+
* @returns {{ layer: import("@vcmap/core").VectorLayer, destroy: () => void }}
|
45
|
+
*/
|
46
|
+
export function setupDeepPickingLayer(app) {
|
47
|
+
const layer = new VectorLayer({
|
48
|
+
zIndex: maxZIndex,
|
49
|
+
projection: mercatorProjection.toJSON(),
|
50
|
+
vectorProperties: {
|
51
|
+
altitudeMode: 'absolute',
|
52
|
+
eyeOffset: [0, 0, -200],
|
53
|
+
},
|
54
|
+
allowPicking: false,
|
55
|
+
});
|
56
|
+
markVolatile(layer);
|
57
|
+
app.layers.add(layer);
|
58
|
+
layer.activate().catch(() => {
|
59
|
+
getLogger('deepPickingAction').error(
|
60
|
+
'Could not activate deep picking layer',
|
61
|
+
);
|
62
|
+
});
|
63
|
+
|
64
|
+
const style = new VectorStyleItem({
|
65
|
+
image: {
|
66
|
+
...getColoredMapIcon(getColorByKey(app, 'primary')),
|
67
|
+
scale: iconScale,
|
68
|
+
},
|
69
|
+
fill: {
|
70
|
+
color: 'rgba(237, 237, 237, 0.1)',
|
71
|
+
},
|
72
|
+
stroke: {
|
73
|
+
color: getColorByKey(app, 'primary'),
|
74
|
+
width: 5,
|
75
|
+
},
|
76
|
+
});
|
77
|
+
layer.setStyle(style);
|
78
|
+
|
79
|
+
function setIconColor() {
|
80
|
+
const color = getColorByKey(app, 'primary');
|
81
|
+
style.stroke?.setColor(color);
|
82
|
+
style.image = new Icon({ ...getColoredMapIcon(color), scale: iconScale });
|
83
|
+
layer.forceRedraw();
|
84
|
+
}
|
85
|
+
|
86
|
+
const themChangedListener = app.themeChanged.addEventListener(setIconColor);
|
87
|
+
|
88
|
+
const destroy = () => {
|
89
|
+
layer.deactivate();
|
90
|
+
app.layers.remove(layer);
|
91
|
+
layer.destroy();
|
92
|
+
themChangedListener();
|
93
|
+
};
|
94
|
+
|
95
|
+
return { layer, destroy };
|
96
|
+
}
|
97
|
+
|
98
|
+
/**
|
99
|
+
* Retrieves features from an OpenLayers map at a given pixel.
|
100
|
+
* @param {import("ol/Map.js").OLMap} map
|
101
|
+
* @param {[number, number]} pixel
|
102
|
+
* @param {number} hitTolerance
|
103
|
+
* @param {number} drill
|
104
|
+
* @returns {import("ol").Feature[]}
|
105
|
+
*/
|
106
|
+
function getFeaturesFromOlMap(map, pixel, hitTolerance, drill) {
|
107
|
+
const features = [];
|
108
|
+
let i = 0;
|
109
|
+
map.forEachFeatureAtPixel(
|
110
|
+
pixel,
|
111
|
+
(feat) => {
|
112
|
+
if (
|
113
|
+
feat &&
|
114
|
+
(feat.get('olcs_allowPicking') == null ||
|
115
|
+
feat.get('olcs_allowPicking') === true)
|
116
|
+
) {
|
117
|
+
const feature = feat[originalFeatureSymbol] || feat;
|
118
|
+
if (!feature[vectorClusterGroupName]) {
|
119
|
+
features.push(feature);
|
120
|
+
}
|
121
|
+
}
|
122
|
+
i += 1;
|
123
|
+
return i >= drill;
|
124
|
+
},
|
125
|
+
{ hitTolerance },
|
126
|
+
);
|
127
|
+
|
128
|
+
return features;
|
129
|
+
}
|
130
|
+
|
131
|
+
/**
|
132
|
+
* Retrieves features from a Cesium scene at a given window position.
|
133
|
+
* @param {import("@vcmap-cesium/engine").Scene} scene
|
134
|
+
* @param {import("@vcmap-cesium/engine").Ray} ray
|
135
|
+
* @param {number} hitTolerance
|
136
|
+
* @param {number} drill
|
137
|
+
* @returns {Promise<{ features: import("@vcmap/core").EventFeature[], minZ: number }>}
|
138
|
+
*/
|
139
|
+
async function getFeaturesFromScene(scene, ray, hitTolerance, drill) {
|
140
|
+
const { depthTestAgainstTerrain } = scene.globe;
|
141
|
+
scene.globe.depthTestAgainstTerrain = false;
|
142
|
+
|
143
|
+
let minZ = 0;
|
144
|
+
const objects = await scene.drillPickFromRay(
|
145
|
+
ray,
|
146
|
+
drill,
|
147
|
+
undefined,
|
148
|
+
hitTolerance,
|
149
|
+
);
|
150
|
+
|
151
|
+
scene.globe.depthTestAgainstTerrain = depthTestAgainstTerrain;
|
152
|
+
|
153
|
+
const features = objects
|
154
|
+
.map(({ object, position }) => {
|
155
|
+
let feature;
|
156
|
+
if (object) {
|
157
|
+
if (position) {
|
158
|
+
const z = cartesianToMercator(position)[2];
|
159
|
+
minZ = Math.min(minZ, z);
|
160
|
+
}
|
161
|
+
feature = getFeatureFromPickObject(object);
|
162
|
+
if (feature?.[vectorClusterGroupName]) {
|
163
|
+
const clusterFeatures = feature.get('features');
|
164
|
+
return [...clusterFeatures];
|
165
|
+
}
|
166
|
+
}
|
167
|
+
return feature;
|
168
|
+
})
|
169
|
+
.filter((f, i, a) => !!f && a.indexOf(f) === i);
|
170
|
+
return { features, minZ };
|
171
|
+
}
|
172
|
+
|
173
|
+
/**
|
174
|
+
* @param {import("@vcmap/core").InteractionEvent} event
|
175
|
+
* @param {number} [hitTolerance=10]
|
176
|
+
* @param {number} [drillLimit]
|
177
|
+
* @returns {Promise<{ features: import("@vcmap/core").EventFeature[], minZ: number }>}
|
178
|
+
*/
|
179
|
+
async function getDeepPickingFeatures(
|
180
|
+
event,
|
181
|
+
hitTolerance = 10,
|
182
|
+
drillLimit = undefined,
|
183
|
+
) {
|
184
|
+
let features = [];
|
185
|
+
let minZ = 0;
|
186
|
+
if (
|
187
|
+
event.map.className === 'OpenlayersMap' ||
|
188
|
+
event.map.className === 'ObliqueMap'
|
189
|
+
) {
|
190
|
+
features = getFeaturesFromOlMap(
|
191
|
+
event.map.olMap,
|
192
|
+
[event.windowPosition.x, event.windowPosition.y],
|
193
|
+
hitTolerance,
|
194
|
+
drillLimit,
|
195
|
+
);
|
196
|
+
} else if (event.map.className === 'CesiumMap') {
|
197
|
+
const cesiumMap = event.map;
|
198
|
+
const scene = cesiumMap.getScene();
|
199
|
+
|
200
|
+
if (!scene) {
|
201
|
+
return features;
|
202
|
+
}
|
203
|
+
|
204
|
+
const [x, y, z] = event.position;
|
205
|
+
const origin = mercatorToCartesian([
|
206
|
+
x,
|
207
|
+
y,
|
208
|
+
Number.isNaN(z) ? pickingZOffset : z + pickingZOffset,
|
209
|
+
]);
|
210
|
+
const direction = Cartesian3.normalize(
|
211
|
+
Cartesian3.negate(origin, scratchCartesian),
|
212
|
+
scratchCartesian,
|
213
|
+
);
|
214
|
+
const ray = new Ray(origin, direction);
|
215
|
+
|
216
|
+
({ features, minZ } = await getFeaturesFromScene(
|
217
|
+
scene,
|
218
|
+
ray,
|
219
|
+
hitTolerance,
|
220
|
+
drillLimit,
|
221
|
+
));
|
222
|
+
}
|
223
|
+
|
224
|
+
if (
|
225
|
+
event.feature &&
|
226
|
+
!event.feature[isProvidedFeature] && // provided features will be provided again.
|
227
|
+
!features.includes(event.feature)
|
228
|
+
) {
|
229
|
+
features.unshift(event.feature);
|
230
|
+
}
|
231
|
+
|
232
|
+
return { features, minZ };
|
233
|
+
}
|
234
|
+
|
235
|
+
/**
|
236
|
+
* @param {import("@vcmap/core").AbstractInteraction} interaction
|
237
|
+
* @param {import("@vcmap/core").InteractionEvent} event
|
238
|
+
* @returns {Promise<import("@vcmap/core").EventFeature[]>}
|
239
|
+
*/
|
240
|
+
async function getInteractionFeatures(interaction, event) {
|
241
|
+
const pipedEvent = await interaction.pipe({
|
242
|
+
...event,
|
243
|
+
feature: undefined,
|
244
|
+
});
|
245
|
+
const { feature } = pipedEvent;
|
246
|
+
if (feature) {
|
247
|
+
if (feature[isProvidedClusterFeature]) {
|
248
|
+
return feature.get('features');
|
249
|
+
}
|
250
|
+
return [feature];
|
251
|
+
}
|
252
|
+
return [];
|
253
|
+
}
|
254
|
+
|
255
|
+
/**
|
256
|
+
* @returns {{ collectFeatures: (event: import("@vcmap/core").InteractionEvent) => Promise<{ features: import("@vcmap/core").EventFeature[], minZ: number }>, destroy: () => void}}
|
257
|
+
*/
|
258
|
+
function createCollectFeatures() {
|
259
|
+
const featureProviderInteraction = new FeatureProviderInteraction();
|
260
|
+
return {
|
261
|
+
async collectFeatures(event) {
|
262
|
+
const { features: deepPickingFeatures, minZ } =
|
263
|
+
await getDeepPickingFeatures(event);
|
264
|
+
return {
|
265
|
+
features: [
|
266
|
+
...deepPickingFeatures,
|
267
|
+
...(await getInteractionFeatures(featureProviderInteraction, event)),
|
268
|
+
],
|
269
|
+
minZ,
|
270
|
+
};
|
271
|
+
},
|
272
|
+
destroy() {
|
273
|
+
featureProviderInteraction.destroy();
|
274
|
+
},
|
275
|
+
};
|
276
|
+
}
|
277
|
+
|
278
|
+
/**
|
279
|
+
* @param {import("../vcsUiApp.js").default} app
|
280
|
+
* @param {import("ol/Feature").default} f
|
281
|
+
* @returns {boolean}
|
282
|
+
*/
|
283
|
+
function featurePredicate(app, f) {
|
284
|
+
if (f[featureInfoViewSymbol]) {
|
285
|
+
return true;
|
286
|
+
}
|
287
|
+
|
288
|
+
const l = app.layers.getByKey(f[vcsLayerName]);
|
289
|
+
if (l?.[moduleIdSymbol] === volatileModuleId) {
|
290
|
+
return !!getFeatureInfoViewForFeature(app, f);
|
291
|
+
}
|
292
|
+
|
293
|
+
return !!l;
|
294
|
+
}
|
295
|
+
|
296
|
+
/**
|
297
|
+
* @param {import("../vcsUiApp.js").default} app
|
298
|
+
* @param {import("@vcmap/core").VectorLayer} layer
|
299
|
+
* @param {(event: import("@vcmap/core").InteractionEvent) => Promise<import("@vcmap/core").EventFeature[]>} collectFeatures
|
300
|
+
* @param {import("@vcmap/core").InteractionEvent} event
|
301
|
+
* @returns {import("./actionHelper.js").VcsAction}
|
302
|
+
*/
|
303
|
+
export function createDeepPickingAction(app, layer, collectFeatures, event) {
|
304
|
+
return {
|
305
|
+
name: 'featureInfo.deepPicking.title',
|
306
|
+
icon: '$vcsInfo',
|
307
|
+
async callback() {
|
308
|
+
const { features, minZ } = await collectFeatures(event);
|
309
|
+
const { items, groups } = getGroupedFeatureList(
|
310
|
+
app,
|
311
|
+
features.filter((f) => featurePredicate(app, f)),
|
312
|
+
event.position,
|
313
|
+
);
|
314
|
+
|
315
|
+
if (app.windowManager.has(deepPickingWindowId)) {
|
316
|
+
app.windowManager.remove(deepPickingWindowId);
|
317
|
+
}
|
318
|
+
|
319
|
+
app.windowManager.add(
|
320
|
+
{
|
321
|
+
id: deepPickingWindowId,
|
322
|
+
component: ClusterFeatureComponent,
|
323
|
+
props: {
|
324
|
+
items,
|
325
|
+
groups,
|
326
|
+
},
|
327
|
+
state: {
|
328
|
+
headerTitle: 'featureInfo.deepPicking.headerTitle',
|
329
|
+
headerIcon: '$vcsInfo',
|
330
|
+
},
|
331
|
+
slot: WindowSlot.DYNAMIC_LEFT,
|
332
|
+
},
|
333
|
+
vcsAppSymbol,
|
334
|
+
);
|
335
|
+
|
336
|
+
const windowListener = app.windowManager.removed.addEventListener(
|
337
|
+
({ id: windowId }) => {
|
338
|
+
if (windowId === deepPickingWindowId) {
|
339
|
+
layer.removeAllFeatures();
|
340
|
+
windowListener();
|
341
|
+
}
|
342
|
+
},
|
343
|
+
);
|
344
|
+
|
345
|
+
const [x, y, z] = event.position;
|
346
|
+
const coordinate = [
|
347
|
+
x,
|
348
|
+
y,
|
349
|
+
Number.isNaN(z) ? pickingZOffset : z + pickingZOffset,
|
350
|
+
];
|
351
|
+
const pickFeature = new Feature({
|
352
|
+
geometry: new Point(coordinate),
|
353
|
+
});
|
354
|
+
const rayFeature = new Feature({
|
355
|
+
geometry: new LineString([coordinate, [x, y, minZ]]),
|
356
|
+
});
|
357
|
+
layer.addFeatures([pickFeature, rayFeature]);
|
358
|
+
},
|
359
|
+
};
|
360
|
+
}
|
361
|
+
|
362
|
+
/**
|
363
|
+
* This adds deep picking action to the context menu, if not disabled in uiConfig
|
364
|
+
* @param {import("../vcsUiApp.js").default} app
|
365
|
+
* @returns {() => void}
|
366
|
+
*/
|
367
|
+
export function setupDeepPicking(app) {
|
368
|
+
const { layer, destroy: destroyLayer } = setupDeepPickingLayer(app);
|
369
|
+
const { collectFeatures, destroy: destroyCollectFeatures } =
|
370
|
+
createCollectFeatures();
|
371
|
+
|
372
|
+
const handler = async (event) => {
|
373
|
+
if (event.windowPosition) {
|
374
|
+
return [createDeepPickingAction(app, layer, collectFeatures, event)];
|
375
|
+
}
|
376
|
+
return [];
|
377
|
+
};
|
378
|
+
|
379
|
+
if (app.uiConfig.enableDeepPicking !== false) {
|
380
|
+
app.contextMenuManager.addEventHandler(handler, vcsAppSymbol);
|
381
|
+
}
|
382
|
+
|
383
|
+
const stopWatching = watch(
|
384
|
+
() => app.uiConfig.config.enableDeepPicking,
|
385
|
+
(value, oldValue) => {
|
386
|
+
if (value !== false) {
|
387
|
+
if (!(oldValue !== false)) {
|
388
|
+
app.contextMenuManager.addEventHandler(handler, vcsAppSymbol);
|
389
|
+
}
|
390
|
+
} else {
|
391
|
+
app.contextMenuManager.removeHandler(handler);
|
392
|
+
}
|
393
|
+
},
|
394
|
+
);
|
395
|
+
|
396
|
+
return () => {
|
397
|
+
stopWatching();
|
398
|
+
destroyLayer();
|
399
|
+
destroyCollectFeatures();
|
400
|
+
layer.deactivate();
|
401
|
+
layer.destroy();
|
402
|
+
app.layers.remove(layer);
|
403
|
+
};
|
404
|
+
}
|
@@ -20,6 +20,7 @@ import { fromExtent } from 'ol/geom/Polygon.js';
|
|
20
20
|
import { createOrUpdateFromCoordinates } from 'ol/extent.js';
|
21
21
|
import { Polygon } from 'ol/geom.js';
|
22
22
|
import { unByKey } from 'ol/Observable.js';
|
23
|
+
import { getLogger } from '@vcsuite/logger';
|
23
24
|
|
24
25
|
/**
|
25
26
|
* @param {import("@src/vcsUiApp.js").default} app
|
@@ -52,9 +53,12 @@ export function createLayerToggleAction(layer, disabled) {
|
|
52
53
|
icon: '$vcsEye',
|
53
54
|
active: false,
|
54
55
|
disabled,
|
55
|
-
|
56
|
+
callback() {
|
56
57
|
if (!this.active) {
|
57
|
-
|
58
|
+
layer.activate().catch(() => {
|
59
|
+
getLogger('extentActions').warn('Failed to activate layer');
|
60
|
+
this.title = 'components.extent.show';
|
61
|
+
});
|
58
62
|
this.title = 'components.extent.hide';
|
59
63
|
} else {
|
60
64
|
layer.deactivate();
|
@@ -96,7 +100,11 @@ export function createExtentFeatureAction(
|
|
96
100
|
callback() {
|
97
101
|
if (!this.active) {
|
98
102
|
this.active = true;
|
99
|
-
layer.activate()
|
103
|
+
layer.activate().catch(() => {
|
104
|
+
getLogger('extentActions').warn('Failed to activate layer');
|
105
|
+
session?.stop();
|
106
|
+
this.active = false;
|
107
|
+
});
|
100
108
|
const feature = layer.getFeatureById(featureId);
|
101
109
|
layer.removeFeaturesById([featureId]);
|
102
110
|
session = startCreateFeatureSession(app, layer, GeometryType.BBox);
|
@@ -176,7 +184,7 @@ function setupTranslateAction(
|
|
176
184
|
title: 'components.extent.translate',
|
177
185
|
icon: 'mdi-axis-arrow',
|
178
186
|
active: false,
|
179
|
-
|
187
|
+
callback() {
|
180
188
|
if (session) {
|
181
189
|
session.stop();
|
182
190
|
} else {
|
@@ -189,7 +197,10 @@ function setupTranslateAction(
|
|
189
197
|
suspendFeatureUpdate.value = false;
|
190
198
|
});
|
191
199
|
});
|
192
|
-
|
200
|
+
layer.activate().catch(() => {
|
201
|
+
getLogger('extentActions').warn('Failed to activate layer');
|
202
|
+
session?.stop();
|
203
|
+
});
|
193
204
|
session = startEditFeaturesSession(app, layer);
|
194
205
|
session.stopped.addEventListener(() => {
|
195
206
|
action.active = false;
|
@@ -246,7 +257,10 @@ function setupVertexAction(
|
|
246
257
|
suspendFeatureUpdate.value = false;
|
247
258
|
});
|
248
259
|
});
|
249
|
-
|
260
|
+
layer.activate().catch(() => {
|
261
|
+
getLogger('extentActions').warn('Failed to activate layer');
|
262
|
+
session?.stop();
|
263
|
+
});
|
250
264
|
session = startEditGeometrySession(app, layer);
|
251
265
|
session.stopped.addEventListener(() => {
|
252
266
|
action.active = false;
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import { reactive } from 'vue';
|
2
2
|
import { check, maybe, ofEnum } from '@vcsuite/check';
|
3
|
+
import { getLogger } from '@vcsuite/logger';
|
3
4
|
import {
|
4
5
|
createFlightVisualization,
|
5
6
|
exportFlightAsGeoJson,
|
@@ -378,7 +379,10 @@ export async function createFlightVisualizationAction(
|
|
378
379
|
if (this.active) {
|
379
380
|
flightVis.deactivate();
|
380
381
|
} else {
|
381
|
-
|
382
|
+
flightVis.activate().catch(() => {
|
383
|
+
getLogger('flightActions').warn('Failed to activate layer');
|
384
|
+
this.active = false;
|
385
|
+
});
|
382
386
|
}
|
383
387
|
this.active = !this.active;
|
384
388
|
},
|
@@ -79,6 +79,7 @@
|
|
79
79
|
createMapButtonAction,
|
80
80
|
createToggleAction,
|
81
81
|
} from '../actions/actionHelper.js';
|
82
|
+
import { setupDeepPicking } from '../actions/deepPickingAction.js';
|
82
83
|
import VcsSettings from './VcsSettings.vue';
|
83
84
|
import { WindowSlot } from '../manager/window/windowManager.js';
|
84
85
|
import CollectionManager from '../manager/collectionManager/CollectionManager.vue';
|
@@ -89,7 +90,11 @@
|
|
89
90
|
isMobileLandscape,
|
90
91
|
} from '../vuePlugins/vuetify.js';
|
91
92
|
import VcsLegend from '../legend/VcsLegend.vue';
|
92
|
-
import {
|
93
|
+
import {
|
94
|
+
getLayerLegend,
|
95
|
+
getLegendEntries,
|
96
|
+
getStyleLegend,
|
97
|
+
} from '../legend/legendHelper.js';
|
93
98
|
import VcsAttributionsFooter from './VcsAttributionsFooter.vue';
|
94
99
|
import VcsObliqueFooter from './VcsObliqueFooter.vue';
|
95
100
|
import VcsTextPageFooter from './VcsTextPageFooter.vue';
|
@@ -279,9 +284,32 @@
|
|
279
284
|
);
|
280
285
|
}
|
281
286
|
};
|
287
|
+
|
288
|
+
/**
|
289
|
+
* Handles legend button and window.
|
290
|
+
* Adds a button, if legend definitions are available or removes legend otherwise.
|
291
|
+
*/
|
292
|
+
const handleLegend = () => {
|
293
|
+
const layersWithLegend = [...app.layers].filter((layer) =>
|
294
|
+
getLayerLegend(layer),
|
295
|
+
);
|
296
|
+
const stylesWithLegend = [...app.styles].filter((style) =>
|
297
|
+
getStyleLegend(style),
|
298
|
+
);
|
299
|
+
if (layersWithLegend < 1 && stylesWithLegend < 1) {
|
300
|
+
app.navbarManager.remove(legendComponentId);
|
301
|
+
app.windowManager.remove(legendComponentId);
|
302
|
+
} else {
|
303
|
+
addLegend();
|
304
|
+
}
|
305
|
+
};
|
306
|
+
|
282
307
|
const { xs } = useDisplay();
|
283
308
|
let currentEntryLength = entries.length;
|
284
309
|
const watchEntries = watch(entries, (newValue) => {
|
310
|
+
if (newValue.length > currentEntryLength) {
|
311
|
+
handleLegend();
|
312
|
+
}
|
285
313
|
if (
|
286
314
|
app.uiConfig.config.openLegendOnAdd &&
|
287
315
|
newValue.length > currentEntryLength &&
|
@@ -308,34 +336,16 @@
|
|
308
336
|
currentEntryLength = newValue.length;
|
309
337
|
});
|
310
338
|
|
311
|
-
/**
|
312
|
-
* Handles legend button and window.
|
313
|
-
* Adds a button, if legend definitions are available or removes legend otherwise.
|
314
|
-
*/
|
315
|
-
const handleLegend = () => {
|
316
|
-
const layersWithLegend = [...app.layers].filter(
|
317
|
-
(layer) => layer.style?.properties?.legend ?? layer.properties?.legend,
|
318
|
-
);
|
319
|
-
const stylesWithLegend = [...app.styles].filter(
|
320
|
-
(style) => style?.properties?.legend,
|
321
|
-
);
|
322
|
-
if (layersWithLegend < 1 && stylesWithLegend < 1) {
|
323
|
-
app.navbarManager.remove(legendComponentId);
|
324
|
-
app.windowManager.remove(legendComponentId);
|
325
|
-
} else {
|
326
|
-
addLegend();
|
327
|
-
}
|
328
|
-
};
|
329
339
|
handleLegend();
|
330
340
|
|
331
341
|
const listeners = [
|
332
342
|
app.layers.added.addEventListener((layer) => {
|
333
|
-
if (layer
|
343
|
+
if (getLayerLegend(layer)) {
|
334
344
|
addLegend();
|
335
345
|
}
|
336
346
|
}),
|
337
347
|
app.styles.added.addEventListener((style) => {
|
338
|
-
if (style
|
348
|
+
if (getStyleLegend(style)) {
|
339
349
|
addLegend();
|
340
350
|
}
|
341
351
|
}),
|
@@ -814,6 +824,7 @@
|
|
814
824
|
const destroyDisplayQualityListener = setupUiConfigDisplayQuality(app);
|
815
825
|
const { attributionEntries, attributionAction, destroyAttributions } =
|
816
826
|
setupAttributions(app);
|
827
|
+
const destroyDeepPicking = setupDeepPicking(app);
|
817
828
|
|
818
829
|
let pluginMountedListener;
|
819
830
|
onMounted(() => {
|
@@ -853,6 +864,7 @@
|
|
853
864
|
destroyThemingListener();
|
854
865
|
destroyDisplayQualityListener();
|
855
866
|
destroyAttributions();
|
867
|
+
destroyDeepPicking();
|
856
868
|
});
|
857
869
|
|
858
870
|
const { smAndUp, xs } = useDisplay();
|
@@ -112,6 +112,10 @@ declare const _default: import("vue").DefineComponent<{
|
|
112
112
|
* - an optional flag whether to activate feature info on startup (default active)
|
113
113
|
*/
|
114
114
|
readonly startingFeatureInfo?: boolean | undefined;
|
115
|
+
/**
|
116
|
+
* - an optional flag whether to enable deep picking via right click context menu (default active)
|
117
|
+
*/
|
118
|
+
readonly enableDeepPicking?: boolean | undefined;
|
115
119
|
/**
|
116
120
|
* - mouse event, when position display is updated. Either 'click' (default) or 'move'.
|
117
121
|
*/
|
@@ -26,6 +26,10 @@ declare const _default: import("vue").DefineComponent<{
|
|
26
26
|
* - an optional flag whether to activate feature info on startup (default active)
|
27
27
|
*/
|
28
28
|
readonly startingFeatureInfo?: boolean | undefined;
|
29
|
+
/**
|
30
|
+
* - an optional flag whether to enable deep picking via right click context menu (default active)
|
31
|
+
*/
|
32
|
+
readonly enableDeepPicking?: boolean | undefined;
|
29
33
|
/**
|
30
34
|
* - mouse event, when position display is updated. Either 'click' (default) or 'move'.
|
31
35
|
*/
|