@vcmap/ui 5.0.0-rc.10 → 5.0.0-rc.13

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 (165) hide show
  1. package/README.md +12 -5
  2. package/build/build.js +6 -3
  3. package/build/buildHelpers.js +12 -4
  4. package/build/buildPreview.js +7 -0
  5. package/build/getPluginProxies.js +4 -0
  6. package/config/aerowest.config.json +13 -3
  7. package/config/base.config.json +398 -219
  8. package/config/codes.config.json +397 -0
  9. package/config/dev.config.json +375 -1
  10. package/config/graphFeatureInfo.config.json +100 -0
  11. package/config/www.config.json +1232 -0
  12. package/dist/assets/{cesium.eb5667.js → cesium.21663e.js} +0 -0
  13. package/dist/assets/cesium.js +1 -1
  14. package/dist/assets/core.63242d.js +4 -0
  15. package/dist/assets/core.js +1 -1
  16. package/dist/assets/font/OFL.txt +93 -0
  17. package/dist/assets/font/TitilliumWeb-Regular.woff2 +0 -0
  18. package/dist/assets/{index.4ccd4433.js → index.44b91cfe.js} +1 -1
  19. package/dist/assets/{ol.ef03b1.js → ol.88ba9d.js} +0 -0
  20. package/dist/assets/ol.js +1 -1
  21. package/dist/assets/ui.3c2933.css +1 -0
  22. package/dist/assets/ui.3c2933.js +71 -0
  23. package/dist/assets/ui.js +1 -1
  24. package/dist/assets/vue.c897fc.js +9 -0
  25. package/dist/assets/vue.js +2 -1
  26. package/dist/assets/{vuetify.401a29.css → vuetify.147c3a.css} +1 -1
  27. package/dist/assets/{vuetify.401a29.js → vuetify.147c3a.js} +72 -72
  28. package/dist/assets/vuetify.js +2 -2
  29. package/dist/index.html +1 -5
  30. package/index.js +39 -5
  31. package/lib/vue.js +1 -0
  32. package/map.config.json +15 -6
  33. package/package.json +17 -8
  34. package/plugins/@vcmap/create-link/fallbackCreateLink.vue +71 -0
  35. package/plugins/@vcmap/create-link/index.js +83 -0
  36. package/plugins/@vcmap/create-link/package.json +6 -0
  37. package/plugins/@vcmap/pluginExample/index.js +2 -2
  38. package/plugins/@vcmap/pluginExample/pluginExampleComponent.vue +20 -3
  39. package/plugins/@vcmap/project-selector/ProjectSelectorComponent.vue +1 -1
  40. package/plugins/@vcmap/project-selector/index.js +1 -1
  41. package/plugins/@vcmap/project-selector/package.json +1 -2
  42. package/plugins/@vcmap/theme-changer/ThemeChangerComponent.vue +1 -1
  43. package/plugins/@vcmap/theme-changer/index.js +1 -1
  44. package/plugins/@vcmap/theme-changer/package.json +1 -2
  45. package/plugins/categoryTest/Categories.vue +89 -1
  46. package/plugins/categoryTest/Category.vue +1 -1
  47. package/plugins/example/index.js +10 -23
  48. package/plugins/simple-graph/README.md +51 -0
  49. package/plugins/simple-graph/SimpleGraphComponent.vue +70 -0
  50. package/plugins/simple-graph/index.js +17 -0
  51. package/plugins/simple-graph/package.json +11 -0
  52. package/plugins/simple-graph/simpleGraphView.js +76 -0
  53. package/plugins/test/editor.vue +1 -1
  54. package/plugins/test/index.js +76 -9
  55. package/plugins/test/toolbox-data.js +82 -57
  56. package/plugins/test/windowManagerExample.vue +1 -1
  57. package/src/actions/stateRefAction.js +2 -2
  58. package/src/actions/styleSelector.vue +1 -1
  59. package/src/application/Navbar.vue +13 -2
  60. package/src/application/VcsApp.vue +301 -116
  61. package/src/application/VcsMap.vue +1 -1
  62. package/src/application/VcsSettings.vue +1 -1
  63. package/src/application/vcsAppWrapper.vue +1 -0
  64. package/src/assets/font/OFL.txt +93 -0
  65. package/src/assets/font/TitilliumWeb-Regular.woff2 +0 -0
  66. package/src/components/form-inputs-controls/VcsCheckbox.vue +13 -0
  67. package/src/components/form-inputs-controls/VcsColorPicker.vue +1 -1
  68. package/src/components/form-inputs-controls/VcsRadio.vue +123 -0
  69. package/src/components/form-output/VcsFormattedNumber.vue +1 -1
  70. package/src/components/lists/VcsActionList.vue +22 -7
  71. package/src/components/lists/VcsTreeview.vue +4 -4
  72. package/src/components/lists/VcsTreeviewLeaf.vue +10 -3
  73. package/src/components/lists/VcsTreeviewSearchbar.vue +1 -2
  74. package/src/components/tables/VcsTable.vue +245 -0
  75. package/src/contentTree/LayerTree.vue +1 -1
  76. package/src/contentTree/contentTreeCollection.js +4 -4
  77. package/src/contentTree/contentTreeItem.js +9 -9
  78. package/src/contentTree/groupContentTreeItem.js +1 -1
  79. package/src/contentTree/layerContentTreeItem.js +15 -1
  80. package/src/contentTree/layerGroupContentTreeItem.js +21 -1
  81. package/src/contentTree/nodeContentTreeItem.js +1 -1
  82. package/src/featureInfo/AddressBalloonComponent.vue +47 -0
  83. package/src/featureInfo/BalloonComponent.vue +140 -0
  84. package/src/featureInfo/abstractFeatureInfoView.js +313 -0
  85. package/src/featureInfo/addressBalloonFeatureInfoView.js +118 -0
  86. package/src/featureInfo/balloonFeatureInfoView.js +151 -0
  87. package/src/featureInfo/balloonHelper.js +132 -0
  88. package/src/featureInfo/featureInfo.js +457 -0
  89. package/src/featureInfo/featureInfoInteraction.js +42 -0
  90. package/src/featureInfo/iframeFeatureInfoView.js +95 -0
  91. package/src/featureInfo/tableFeatureInfoView.js +106 -0
  92. package/src/i18n/de.js +26 -0
  93. package/src/i18n/en.js +26 -0
  94. package/src/i18n/i18nCollection.js +17 -0
  95. package/src/icons/+all.js +80 -0
  96. package/src/icons/ClippingHorizontalIcon.vue +7 -0
  97. package/src/icons/ClippingIcon.vue +7 -0
  98. package/src/icons/ClippingVerticalIcon.vue +7 -0
  99. package/src/icons/ColorPickerIcon.vue +7 -0
  100. package/src/icons/ComponentsIcon.vue +2 -2
  101. package/src/icons/DimensionsHouseIcon.vue +11 -9
  102. package/src/icons/EditIcon.vue +7 -0
  103. package/src/icons/GlobalTerrainIcon.vue +9 -0
  104. package/src/icons/GroundIcon.vue +18 -0
  105. package/src/icons/HideIcon.vue +12 -0
  106. package/src/icons/LogoutIcon.vue +7 -0
  107. package/src/icons/ObjectAttributeIcon.vue +2 -13
  108. package/src/icons/PedestrianIcon.vue +2 -3
  109. package/src/icons/PenIcon.vue +2 -9
  110. package/src/icons/PoiIcon.vue +5 -2
  111. package/src/icons/PointSelectIcon.vue +4 -2
  112. package/src/icons/QueryIcon.vue +6 -7
  113. package/src/icons/ScreenshotIcon.vue +16 -0
  114. package/src/icons/ShareIcon.vue +4 -16
  115. package/src/icons/SkipNextIcon.vue +3 -1
  116. package/src/icons/TerrainBoxIcon.vue +9 -0
  117. package/src/icons/ToolsIcon.vue +4 -30
  118. package/src/icons/UploadIcon.vue +2 -9
  119. package/src/icons/UserProfileIcon.vue +7 -0
  120. package/src/icons/UserShareIcon.vue +7 -0
  121. package/src/icons/VideoRecorderIcon.vue +5 -9
  122. package/src/icons/ViewpointFlightIcon.vue +11 -0
  123. package/src/icons/ViewpointIcon.vue +11 -0
  124. package/src/icons/Viewshed360Icon.vue +7 -0
  125. package/src/icons/ViewshedConeIcon.vue +7 -0
  126. package/src/icons/ViewshedIcon.vue +7 -0
  127. package/src/icons/WallIcon.vue +4 -9
  128. package/src/legend/legendHelper.js +193 -0
  129. package/src/legend/styleLegendItem.vue +129 -0
  130. package/src/legend/vcsLegend.vue +92 -0
  131. package/src/manager/buttonManager.js +7 -12
  132. package/src/manager/categoryManager/ComponentsManager.vue +30 -0
  133. package/src/manager/categoryManager/categoryManager.js +500 -0
  134. package/src/manager/contextMenu/contextMenuComponent.vue +43 -0
  135. package/src/manager/contextMenu/contextMenuInteraction.js +42 -0
  136. package/src/manager/contextMenu/contextMenuManager.js +197 -0
  137. package/src/manager/navbarManager.js +9 -9
  138. package/src/manager/toolbox/GroupToolboxComponent.vue +118 -0
  139. package/src/manager/toolbox/SelectToolboxComponent.vue +128 -0
  140. package/src/manager/toolbox/ToolboxManager.vue +116 -98
  141. package/src/manager/toolbox/toolboxManager.js +235 -86
  142. package/src/manager/window/WindowComponent.vue +1 -1
  143. package/src/manager/window/WindowManager.vue +5 -3
  144. package/src/manager/window/windowManager.js +118 -14
  145. package/src/navigation/mapNavigation.vue +3 -5
  146. package/src/navigation/overviewMap.js +28 -5
  147. package/src/navigation/vcsCompass.vue +1 -1
  148. package/src/pluginHelper.js +42 -10
  149. package/src/setup.js +0 -2
  150. package/src/state.js +256 -0
  151. package/src/styles/_theming.scss +0 -5
  152. package/src/styles/variables.scss +7 -0
  153. package/src/styles/vcsFont.scss +17 -0
  154. package/src/uiConfig.js +79 -0
  155. package/src/vcsUiApp.js +213 -22
  156. package/src/vuePlugins/vuetify.js +14 -4
  157. package/config/berlin.config.json +0 -510
  158. package/dist/assets/core.216494.js +0 -4
  159. package/dist/assets/ui.99a1a7.css +0 -1
  160. package/dist/assets/ui.99a1a7.js +0 -70
  161. package/dist/assets/vue-composition-api.c5aca1.js +0 -14
  162. package/dist/assets/vue-composition-api.js +0 -2
  163. package/dist/assets/vue.762edd.js +0 -9
  164. package/lib/vue-composition-api.js +0 -2
  165. package/src/manager/toolbox/ToolboxGroupComponent.vue +0 -128
@@ -0,0 +1,457 @@
1
+ import {
2
+ EventType,
3
+ makeOverrideCollection,
4
+ Collection,
5
+ getObjectFromClassRegistry,
6
+ VcsEvent,
7
+ vcsLayerName,
8
+ OverrideClassRegistry,
9
+ ClassRegistry,
10
+ fromCesiumColor,
11
+ VectorLayer,
12
+ isProvidedFeature,
13
+ mercatorProjection,
14
+ getDefaultVectorStyleItemOptions,
15
+ VectorStyleItem,
16
+ markVolatile,
17
+ maxZIndex,
18
+ } from '@vcmap/core';
19
+ import { getLogger as getLoggerByName } from '@vcsuite/logger';
20
+ import {
21
+ Cesium3DTileFeature,
22
+ Cesium3DTilePointFeature,
23
+ Color,
24
+ Entity,
25
+ } from '@vcmap/cesium';
26
+ import { Feature } from 'ol';
27
+ import { check, checkMaybe } from '@vcsuite/check';
28
+ import { v4 as uuidv4 } from 'uuid';
29
+
30
+ import { ToolboxType } from '@vcmap/ui';
31
+ import { vcsAppSymbol } from '../pluginHelper.js';
32
+ import FeatureInfoInteraction from './featureInfoInteraction.js';
33
+ import AbstractFeatureInfoView from './abstractFeatureInfoView.js';
34
+ import TableFeatureInfoView from './tableFeatureInfoView.js';
35
+ import IframeFeatureInfoView from './iframeFeatureInfoView.js';
36
+ import AddressBalloonFeatureInfoView from './addressBalloonFeatureInfoView.js';
37
+ import BalloonFeatureInfoView from './balloonFeatureInfoView.js';
38
+ import { defaultPrimaryColor } from '../vuePlugins/vuetify.js';
39
+
40
+ /** @typedef {import("ol").Feature<import("ol/geom/Geometry").default>|import("@vcmap/cesium").Cesium3DTileFeature|import("@vcmap/cesium").Cesium3DTilePointFeature|import("@vcmap/cesium").Entity} FeatureType */
41
+
42
+ /**
43
+ * @typedef {Object} FeatureInfoEvent
44
+ * @property {FeatureType} feature
45
+ * @property {import("ol/coordinate").Coordinate} [position] - potential position to place the balloon at
46
+ * @property {import("ol/coordinate").Coordinate} [windowPosition] - potential window position to initially place the balloon at
47
+ */
48
+
49
+ /**
50
+ * @returns {Logger}
51
+ */
52
+ function getLogger() {
53
+ return getLoggerByName('featureInfo');
54
+ }
55
+
56
+ /**
57
+ * @param {FeatureType} feature
58
+ * @param {import("@vcmap/core").Layer} layer
59
+ * @param {string} defaultFillColor
60
+ * @returns {import("ol/style/Style").default|import("@vcmap/core").VectorStyleItem}
61
+ */
62
+ function getHighlightStyle(feature, layer, defaultFillColor) {
63
+ if (layer && layer.highlightStyle) {
64
+ return layer.highlightStyle;
65
+ }
66
+
67
+ const fillColor = Color.fromCssColorString(defaultFillColor).withAlpha(0.8);
68
+ if (feature instanceof Feature) {
69
+ let style = feature.getStyle() ?? layer?.style?.style;
70
+ if (typeof style === 'function') {
71
+ style = style(feature, 1);
72
+ }
73
+ style = style?.clone?.() ?? new VectorStyleItem(getDefaultVectorStyleItemOptions()).style;
74
+ if (style.getText()) {
75
+ if (style.getText().getFill()) {
76
+ style.getText().getFill().setColor(fillColor.toCssColorString());
77
+ }
78
+ style.getText().setScale((style.getText().getScale() ?? 1) * 2);
79
+ }
80
+ if (style.getImage()) {
81
+ style.getImage().setScale(style.getImage().getScale() * 2);
82
+ }
83
+ if (style.getStroke()) {
84
+ style.getStroke().setColor(fillColor.toCssColorString());
85
+ style.getStroke().setWidth(style.getStroke().getWidth() * 2);
86
+ }
87
+ if (style.getFill()) {
88
+ const color = fillColor.toBytes();
89
+ color[3] /= 255;
90
+ style.getFill().setColor(color);
91
+ }
92
+ return style;
93
+ }
94
+ return fromCesiumColor(fillColor);
95
+ }
96
+
97
+ /**
98
+ * @param {VcsUiApp} app
99
+ * @returns {FeatureInfoSession}
100
+ */
101
+ export function createFeatureInfoSession(app) {
102
+ const { eventHandler } = app.maps;
103
+ /** @type {function():void} */
104
+ let stop;
105
+ const interaction = new FeatureInfoInteraction(app.featureInfo);
106
+ const listener = eventHandler.addExclusiveInteraction(
107
+ interaction,
108
+ () => { stop?.(); },
109
+ );
110
+ const currentFeatureInteractionEvent = eventHandler.featureInteraction.active;
111
+ eventHandler.featureInteraction.setActive(EventType.CLICK);
112
+
113
+ const stopped = new VcsEvent();
114
+ stop = () => {
115
+ listener();
116
+ interaction.destroy();
117
+ eventHandler.featureInteraction.setActive(currentFeatureInteractionEvent);
118
+ stopped.raiseEvent();
119
+ stopped.destroy();
120
+ };
121
+
122
+ return {
123
+ stopped,
124
+ stop,
125
+ };
126
+ }
127
+
128
+ /**
129
+ * @param {VcsUiApp} app
130
+ */
131
+ function setupFeatureInfoTool(app) {
132
+ /** @type {FeatureInfoSession|null} */
133
+ let session = null;
134
+
135
+ const action = {
136
+ name: 'featureInfoToggle',
137
+ title: 'featureInfo.activateToolTitle',
138
+ icon: '$vcsInfo',
139
+ active: false,
140
+ callback() {
141
+ if (session) {
142
+ session.stop();
143
+ this.title = 'featureInfo.activateToolTitle';
144
+ } else {
145
+ session = createFeatureInfoSession(app);
146
+ session.stopped.addEventListener(() => {
147
+ this.active = false;
148
+ session = null;
149
+ app.featureInfo.clear();
150
+ });
151
+ this.active = true;
152
+ this.title = 'featureInfo.deactivateToolTitle';
153
+ }
154
+ },
155
+ };
156
+
157
+ app.toolboxManager.add(
158
+ {
159
+ id: 'featureInfo',
160
+ type: ToolboxType.SINGLE,
161
+ action,
162
+ },
163
+ vcsAppSymbol,
164
+ );
165
+ }
166
+
167
+ /**
168
+ * @typedef {Object} FeatureInfoSession
169
+ * @property {VcsEvent<void>} stopped
170
+ * @property {function():void} stop
171
+ */
172
+
173
+ /**
174
+ * @type {ClassRegistry<AbstractFeatureInfoView>}
175
+ */
176
+ export const featureInfoClassRegistry = new ClassRegistry();
177
+
178
+ /**
179
+ * @class FeatureInfo
180
+ * @description Provides registration of featureInfoClasses and stores featureInfoView instances in its collection.
181
+ */
182
+ class FeatureInfo {
183
+ /**
184
+ * @param {VcsUiApp} app
185
+ */
186
+ constructor(app) {
187
+ /**
188
+ * @type {VcsUiApp}
189
+ * @private
190
+ */
191
+ this._app = app;
192
+ /**
193
+ * @type {import("@vcmap/core").OverrideCollection<AbstractFeatureInfoView>}
194
+ * @private
195
+ */
196
+ this._collection = makeOverrideCollection(
197
+ new Collection(),
198
+ () => this._app.dynamicContextId,
199
+ null,
200
+ config => getObjectFromClassRegistry(this._featureInfoClassRegistry, config),
201
+ AbstractFeatureInfoView,
202
+ );
203
+ /**
204
+ * @type {OverrideClassRegistry<AbstractFeatureInfoView>}
205
+ * @private
206
+ */
207
+ this._featureInfoClassRegistry = new OverrideClassRegistry(featureInfoClassRegistry);
208
+ /**
209
+ * @type {function():void|null}
210
+ * @private
211
+ */
212
+ this._clearHighlightingCb = null;
213
+ /**
214
+ * @type {string|null}
215
+ * @private
216
+ */
217
+ this._windowId = null;
218
+ /**
219
+ * @type {VcsEvent<FeatureType>}
220
+ * @private
221
+ */
222
+ this._featureChanged = new VcsEvent();
223
+ /**
224
+ * @type {FeatureType|null}
225
+ * @private
226
+ */
227
+ this._selectedFeature = null;
228
+ /**
229
+ * @type {Array<function():void>}
230
+ * @private
231
+ */
232
+ this._listeners = [
233
+ this._app.maps.mapActivated.addEventListener((map) => {
234
+ if (
235
+ this._windowId &&
236
+ this._app.windowManager.has(this._windowId)
237
+ ) {
238
+ const { layerName } = this._app.windowManager.get(this._windowId).props;
239
+ const layer = this._app.layers.getByKey(layerName);
240
+ if (layer && !layer.isSupported(map)) {
241
+ this._app.windowManager.remove(this._windowId);
242
+ }
243
+ }
244
+ }),
245
+ this._app.layers.stateChanged.addEventListener((layer) => {
246
+ if (
247
+ this._windowId &&
248
+ this._app.windowManager.has(this._windowId) &&
249
+ this._app.windowManager.get(this._windowId).props.layerName === layer.name
250
+ ) {
251
+ this._app.windowManager.remove(this._windowId);
252
+ }
253
+ }),
254
+ this._app.windowManager.removed.addEventListener(({ id }) => {
255
+ if (id === this._windowId) {
256
+ this.clear();
257
+ }
258
+ }),
259
+ this._app.contextAdded.addEventListener(() => this.clear()),
260
+ this._app.contextRemoved.addEventListener(() => this.clear()),
261
+ ];
262
+ /**
263
+ * A vector layer to render provided features on
264
+ * @type {VectorLayer|null}
265
+ * @private
266
+ */
267
+ this._scratchLayer = null;
268
+
269
+ setupFeatureInfoTool(this._app);
270
+ }
271
+
272
+ /**
273
+ * @type {import("@vcmap/core").OverrideCollection<AbstractFeatureInfoView>}
274
+ * @readonly
275
+ */
276
+ get collection() { return this._collection; }
277
+
278
+ /**
279
+ * @type {OverrideClassRegistry<AbstractFeatureInfoView>}
280
+ * @readonly
281
+ */
282
+ get classRegistry() { return this._featureInfoClassRegistry; }
283
+
284
+ /**
285
+ * @type {VcsEvent<null|FeatureType>}
286
+ * @readonly
287
+ */
288
+ get featureChanged() { return this._featureChanged; }
289
+
290
+ /**
291
+ * @type {null|FeatureType}
292
+ * @readonly
293
+ */
294
+ get selectedFeature() { return this._selectedFeature; }
295
+
296
+ /**
297
+ * The window id of the current features FeatureInfoView window
298
+ * @type {string|null}
299
+ * @readonly
300
+ */
301
+ get windowId() {
302
+ return this._windowId;
303
+ }
304
+
305
+ /**
306
+ * @private
307
+ */
308
+ _ensureScratchLayer() {
309
+ if (!this._scratchLayer) {
310
+ this._scratchLayer = new VectorLayer({
311
+ zIndex: maxZIndex,
312
+ projection: mercatorProjection.toJSON(),
313
+ });
314
+ markVolatile(this._scratchLayer);
315
+ this._app.layers.add(this._scratchLayer);
316
+ this._scratchLayer.activate();
317
+ }
318
+ }
319
+
320
+ /**
321
+ * @param {FeatureType} feature
322
+ * @returns {null|AbstractFeatureInfoView}
323
+ * @private
324
+ */
325
+ _getFeatureInfoViewForFeature(feature) {
326
+ const layer = this._app.layers.getByKey(feature[vcsLayerName]);
327
+ const name = layer?.properties?.featureInfo;
328
+ if (!name) {
329
+ getLogger().debug(`No view has been configured for layer '${layer?.name}'.`);
330
+ return null;
331
+ }
332
+ if (!this._collection.hasKey(name)) {
333
+ getLogger().warning(`No view with name '${name}' has been registered.`);
334
+ return null;
335
+ }
336
+ return /** @type {AbstractFeatureInfoView} */ this._collection.getByKey(name);
337
+ }
338
+
339
+ /**
340
+ * Selecting a feature highlights said feature and opens a FeatureInfoView, if configured on the layer. For a successful selection,
341
+ * the feature must meet the following criteria: a) the feature must be part of a layer, b) said layer must be managed in
342
+ * the same VcsApp as provided to the FeatureInfo on construction. if not providing a feature info view, then c) said layer must have a featureInfo property set on
343
+ * its properties bag and d) said featureInfo property must provide the name of a FeatureInfoView present on this FeatureInfos
344
+ * collection.
345
+ * If passing a feature create by a FeatureProvider, the feature will be highlighted on an internal scratch layer.
346
+ * @param {FeatureType} feature
347
+ * @param {import("ol/coordinate").Coordinate=} [position] - optional clicked position. If not given feature's center point is used to place balloons
348
+ * @param {import("ol/coordinate").Coordinate=} [windowPosition] - optional clicked window position. If not given derived from position for balloons
349
+ * @param {AbstractFeatureInfoView=} featureInfoView
350
+ * @returns {Promise<void>}
351
+ */
352
+ async selectFeature(feature, position, windowPosition, featureInfoView) {
353
+ check(feature, [Feature, Entity, Cesium3DTileFeature, Cesium3DTilePointFeature]);
354
+ checkMaybe(position, [Number]);
355
+ checkMaybe(windowPosition, [Number]);
356
+ checkMaybe(featureInfoView, AbstractFeatureInfoView);
357
+
358
+ const usedFeatureInfoView = featureInfoView ?? this._getFeatureInfoViewForFeature(feature);
359
+ const layer = this._app.layers.getByKey(feature[vcsLayerName]);
360
+
361
+ if (usedFeatureInfoView && layer) {
362
+ this._clearInternal();
363
+ if (feature[isProvidedFeature]) {
364
+ this._ensureScratchLayer();
365
+ this._scratchLayer.addFeatures([feature]);
366
+ const featureId = feature.getId(); // make sure to grab ID after adding it to the layer
367
+ this._scratchLayer.featureVisibility.highlight({
368
+ [featureId]: getHighlightStyle(
369
+ feature,
370
+ layer,
371
+ this._app.uiConfig.config.value.primaryColor ?? defaultPrimaryColor,
372
+ ),
373
+ });
374
+ this._clearHighlightingCb = () => this._scratchLayer.featureVisibility.unHighlight([featureId]);
375
+ } else if (layer.featureVisibility) {
376
+ const featureId = feature.getId();
377
+ layer.featureVisibility.highlight({
378
+ [featureId]: getHighlightStyle(
379
+ feature,
380
+ layer,
381
+ this._app.uiConfig.config.value.primaryColor ?? defaultPrimaryColor,
382
+ ),
383
+ });
384
+ this._clearHighlightingCb = () => layer.featureVisibility.unHighlight([featureId]);
385
+ }
386
+ this._windowId = uuidv4(); // we need to create a uuid, otherwise the window manager gets confused if we recreate a window in the same thread with the same id
387
+ this._app.windowManager.add(
388
+ {
389
+ id: this._windowId,
390
+ ...usedFeatureInfoView.getWindowComponentOptions(
391
+ { feature, position, windowPosition },
392
+ layer,
393
+ ),
394
+ },
395
+ vcsAppSymbol,
396
+ );
397
+
398
+ this._selectedFeature = feature;
399
+ this._featureChanged.raiseEvent(this._selectedFeature);
400
+ } else {
401
+ this.clear();
402
+ }
403
+ }
404
+
405
+ /**
406
+ * Clears the current feature. remove window, highlighting and provided feature.
407
+ * @private
408
+ */
409
+ _clearInternal() {
410
+ if (this._clearHighlightingCb) {
411
+ this._clearHighlightingCb();
412
+ this._clearHighlightingCb = null;
413
+ }
414
+ if (this._windowId) {
415
+ this._app.windowManager.remove(this._windowId);
416
+ this._windowId = null;
417
+ }
418
+
419
+ if (this._scratchLayer) {
420
+ this._scratchLayer.removeAllFeatures();
421
+ }
422
+ }
423
+
424
+ /**
425
+ * Deselecting feature clears highlighting and closes FeatureInfoView. fires feature changed with null
426
+ */
427
+ clear() {
428
+ this._clearInternal();
429
+ if (this._selectedFeature) {
430
+ this._selectedFeature = null;
431
+ this._featureChanged.raiseEvent(this._selectedFeature);
432
+ }
433
+ }
434
+
435
+ /**
436
+ * Destroys the feature info and all its events & listeners
437
+ */
438
+ destroy() {
439
+ this._clearInternal();
440
+ this._featureChanged.destroy();
441
+ this._app.toolboxManager.remove('featureInfo');
442
+ if (this._scratchLayer) {
443
+ this._app.layers.remove(this._scratchLayer);
444
+ this._scratchLayer.destroy();
445
+ }
446
+ this._listeners.forEach(cb => cb());
447
+ this._listeners.splice(0);
448
+ this._collection.destroy();
449
+ this._featureInfoClassRegistry.destroy();
450
+ }
451
+ }
452
+
453
+ export default FeatureInfo;
454
+ featureInfoClassRegistry.registerClass(TableFeatureInfoView.className, TableFeatureInfoView);
455
+ featureInfoClassRegistry.registerClass(IframeFeatureInfoView.className, IframeFeatureInfoView);
456
+ featureInfoClassRegistry.registerClass(BalloonFeatureInfoView.className, BalloonFeatureInfoView);
457
+ featureInfoClassRegistry.registerClass(AddressBalloonFeatureInfoView.className, AddressBalloonFeatureInfoView);
@@ -0,0 +1,42 @@
1
+ import { AbstractInteraction, EventType, ModificationKeyType } from '@vcmap/core';
2
+
3
+ /**
4
+ * @class
5
+ * @extends {import("@vcmap/core").AbstractInteraction}
6
+ */
7
+ class FeatureInfoInteraction extends AbstractInteraction {
8
+ /**
9
+ * @param {FeatureInfo} featureInfo
10
+ */
11
+ constructor(featureInfo) {
12
+ super(EventType.CLICK, ModificationKeyType.NONE);
13
+ /**
14
+ * @type {FeatureInfo}
15
+ * @private
16
+ */
17
+ this._featureInfo = featureInfo;
18
+ this.setActive();
19
+ }
20
+
21
+ /**
22
+ * @param {import("@vcmap/core").InteractionEvent} event
23
+ * @returns {Promise<import("@vcmap/core").InteractionEvent>}
24
+ */
25
+ async pipe(event) {
26
+ if (event.feature) {
27
+ if (!this._featureInfo.selectedFeature || event.feature.getId() !== this._featureInfo.selectedFeature.getId()) {
28
+ event.stopPropagation = true;
29
+ await this._featureInfo.selectFeature(
30
+ event.feature,
31
+ event.position,
32
+ [event.windowPosition.x, event.windowPosition.y],
33
+ );
34
+ }
35
+ } else {
36
+ await this._featureInfo.clear();
37
+ }
38
+ return event;
39
+ }
40
+ }
41
+
42
+ export default FeatureInfoInteraction;
@@ -0,0 +1,95 @@
1
+ import AbstractFeatureInfoView from './abstractFeatureInfoView.js';
2
+
3
+ /**
4
+ * @description An iframe component
5
+ * @vue-prop {string} src - Specifies the address of the document to embed in the <iframe>
6
+ * @vue-prop {string} [title] - optional title for the <iframe>
7
+ */
8
+ const IframeComponent = {
9
+ name: 'IframeComponent',
10
+ props: {
11
+ src: {
12
+ type: String,
13
+ required: true,
14
+ },
15
+ title: {
16
+ type: String,
17
+ default: undefined,
18
+ },
19
+ },
20
+ template: '<iframe :src="src" :title="title" />',
21
+ };
22
+
23
+ /**
24
+ * @typedef {FeatureInfoViewOptions} IframeFeatureInfoViewOptions
25
+ * @property {string} src - Specifies the address of the document to embed in the <iframe>. Variables wrapped in `${}` are replaced by their values, e.g. `${featureId}` or `${attributes.gml:name}`
26
+ * @property {string} [title] - optional title for the <iframe>
27
+ */
28
+
29
+ /**
30
+ * @typedef {FeatureInfoProps} IframeFeatureInfoViewProps
31
+ * @property {string} src
32
+ * @property {string|undefined} title
33
+ */
34
+
35
+ /**
36
+ * @class
37
+ * @description An iframe view.
38
+ * @extends {AbstractFeatureInfoView}
39
+ */
40
+ class IframeFeatureInfoView extends AbstractFeatureInfoView {
41
+ /**
42
+ * @type {string}
43
+ */
44
+ static get className() { return 'IframeFeatureInfoView'; }
45
+
46
+ /**
47
+ * @param {IframeFeatureInfoViewOptions} options
48
+ */
49
+ constructor(options) {
50
+ super(options, IframeComponent);
51
+
52
+ /**
53
+ * @type {string}
54
+ */
55
+ this.src = options.src;
56
+ /**
57
+ * @type {string|undefined}
58
+ */
59
+ this.title = options.title || undefined;
60
+ }
61
+
62
+ /**
63
+ * Variables wrapped in `${}` within `src` are replaced by their values, e.g. `${featureId}` or `${attributes.gml:name}`
64
+ * @param {FeatureInfoEvent} featureInfo
65
+ * @param {import("@vcmap/core").Layer} layer
66
+ * @returns {IframeFeatureInfoViewProps}
67
+ */
68
+ getProperties(featureInfo, layer) {
69
+ const properties = super.getProperties(featureInfo, layer);
70
+ return {
71
+ ...properties,
72
+ src: this.src.replace(/\$\{(.*?)}/g, (match, token) => {
73
+ const variable = token.split('.');
74
+ return variable.reduce((obj, prop) => obj?.[prop], properties);
75
+ }),
76
+ title: this.title,
77
+ };
78
+ }
79
+
80
+ /**
81
+ * @returns {IframeFeatureInfoViewOptions}
82
+ */
83
+ toJSON() {
84
+ const config = super.toJSON();
85
+ if (this.src) {
86
+ config.src = this.src;
87
+ }
88
+ if (this.title) {
89
+ config.title = this.title;
90
+ }
91
+ return config;
92
+ }
93
+ }
94
+
95
+ export default IframeFeatureInfoView;
@@ -0,0 +1,106 @@
1
+ import AbstractFeatureInfoView from './abstractFeatureInfoView.js';
2
+ import VcsTable from '../components/tables/VcsTable.vue';
3
+
4
+ /**
5
+ * @typedef {FeatureInfoViewOptions} TableFeatureInfoViewOptions
6
+ * @property {number} [itemsPerPage=10] - default has to be one of itemsPerPageArray
7
+ * @property {number[]} [itemsPerPageArray=[5, 10, 15]]
8
+ * @property {boolean} [showSearchbar]
9
+ * @property {string} [searchbarPlaceholder]
10
+ */
11
+
12
+ /**
13
+ * @typedef {FeatureInfoProps} TableFeatureInfoViewProps
14
+ * @property {number} [itemsPerPage=10]
15
+ * @property {number[]} [itemsPerPageArray=[5, 10, 15]]
16
+ * @property {boolean} [showGroupBtn]
17
+ * @property {boolean} [showSearchbar]
18
+ * @property {string} [searchbarPlaceholder]
19
+ */
20
+
21
+ /**
22
+ * @class
23
+ * @description A table view for feature attributes
24
+ * @extends {AbstractFeatureInfoView}
25
+ */
26
+ class TableFeatureInfoView extends AbstractFeatureInfoView {
27
+ /**
28
+ * @type {string}
29
+ */
30
+ static get className() { return 'TableFeatureInfoView'; }
31
+
32
+ /** @returns {TableFeatureInfoViewOptions} */
33
+ static getDefaultOptions() {
34
+ return {
35
+ itemsPerPageArray: [5, 10, 15],
36
+ itemsPerPage: 10,
37
+ showSearchbar: true,
38
+ };
39
+ }
40
+
41
+ /**
42
+ * @param {TableFeatureInfoViewOptions} options
43
+ */
44
+ constructor(options) {
45
+ super(options, VcsTable);
46
+ const defaultOptions = TableFeatureInfoView.getDefaultOptions();
47
+ /**
48
+ * @type {number[]}
49
+ */
50
+ this.itemsPerPageArray = options.itemsPerPageArray || defaultOptions.itemsPerPageArray;
51
+
52
+ const itemsPerPage = options.itemsPerPage || defaultOptions.itemsPerPage;
53
+ /**
54
+ * @type {number}
55
+ */
56
+ this.itemsPerPage = this.itemsPerPageArray.includes(itemsPerPage) ? itemsPerPage : this.itemsPerPageArray[0];
57
+ /**
58
+ * @type {boolean}
59
+ */
60
+ this.showSearchbar = options.showSearchbar || defaultOptions.showSearchbar;
61
+ /**
62
+ * @type {string}
63
+ */
64
+ this.searchbarPlaceholder = options.searchbarPlaceholder;
65
+ }
66
+
67
+ /**
68
+ * @param {FeatureInfoEvent} featureInfo
69
+ * @param {import("@vcmap/core").Layer} layer
70
+ * @returns {TableFeatureInfoViewProps}
71
+ */
72
+ getProperties(featureInfo, layer) {
73
+ const properties = super.getProperties(featureInfo, layer);
74
+ return {
75
+ ...properties,
76
+ itemsPerPage: this.itemsPerPage,
77
+ itemsPerPageArray: this.itemsPerPageArray,
78
+ showSearchbar: this.showSearchbar,
79
+ searchbarPlaceholder: this.searchbarPlaceholder,
80
+ };
81
+ }
82
+
83
+ /**
84
+ * @returns {TableFeatureInfoViewOptions}
85
+ */
86
+ toJSON() {
87
+ const config = super.toJSON();
88
+ const defaultOptions = TableFeatureInfoView.getDefaultOptions();
89
+ if (this.itemsPerPageArray.length !== defaultOptions.itemsPerPageArray.length ||
90
+ this.itemsPerPageArray.some((e, idx) => e !== defaultOptions.itemsPerPageArray[idx])) {
91
+ config.itemsPerPageArray = this.itemsPerPageArray;
92
+ }
93
+ if (this.itemsPerPage !== defaultOptions.itemsPerPage) {
94
+ config.itemsPerPage = this.itemsPerPage;
95
+ }
96
+ if (this.showSearchbar !== defaultOptions.showSearchbar) {
97
+ config.showSearchbar = this.showSearchbar;
98
+ }
99
+ if (this.searchbarPlaceholder) {
100
+ config.searchbarPlaceholder = this.searchbarPlaceholder;
101
+ }
102
+ return config;
103
+ }
104
+ }
105
+
106
+ export default TableFeatureInfoView;