@vcmap/ui 6.2.4 → 6.3.0-rc.2

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 (60) hide show
  1. package/config/base.config.json +6 -3
  2. package/config/cluster.config.json +2 -1
  3. package/config/dev.config.json +12 -0
  4. package/config/geofence.config.json +19 -0
  5. package/config/pano.config.json +313 -7
  6. package/config/projects.config.json +2 -1
  7. package/dist/assets/cesium.js +1 -1
  8. package/dist/assets/{core-b61fb7c0.js → core-c23fc5f1.js} +10212 -9921
  9. package/dist/assets/core-workers/panoramaImageWorker.js +1 -1
  10. package/dist/assets/core.js +1 -1
  11. package/dist/assets/ol.js +1 -1
  12. package/dist/assets/ui-e61976d4.css +1 -0
  13. package/dist/assets/{ui-f33a5ee2.js → ui-e61976d4.js} +7045 -6910
  14. package/dist/assets/ui.js +1 -1
  15. package/dist/assets/vue.js +1 -1
  16. package/dist/assets/{vuetify-2fc014c4.js → vuetify-de6f6eb0.js} +1 -1
  17. package/dist/assets/vuetify.js +1 -1
  18. package/package.json +2 -2
  19. package/plugins/@vcmap-show-case/panel-tester/src/TextPanelExample.vue +1 -1
  20. package/plugins/@vcmap-show-case/panorama-inspector/src/PanoramaDebugTools.vue +28 -3
  21. package/plugins/@vcmap-show-case/panorama-inspector/src/api.js +8 -23
  22. package/plugins/@vcmap-show-case/panorama-inspector/src/index.js +1 -1
  23. package/plugins/package.json +5 -3
  24. package/src/application/VcsApp.vue +15 -1
  25. package/src/application/VcsApp.vue.d.ts +32 -0
  26. package/src/application/VcsAttributions.vue +9 -0
  27. package/src/application/VcsAttributionsFooter.vue.d.ts +1 -0
  28. package/src/application/VcsContainer.vue.d.ts +31 -0
  29. package/src/application/VcsMobileMenuList.vue +16 -1
  30. package/src/application/VcsObliqueFooter.vue +19 -6
  31. package/src/application/VcsObliqueFooter.vue.d.ts +1 -0
  32. package/src/application/VcsPanoramaFooter.vue +72 -0
  33. package/src/application/VcsPanoramaFooter.vue.d.ts +2 -0
  34. package/src/application/VcsTextPageFooter.vue +4 -0
  35. package/src/application/attributionsHelper.d.ts +7 -1
  36. package/src/application/attributionsHelper.js +7 -2
  37. package/src/application/uiConfigHelper.d.ts +6 -0
  38. package/src/application/uiConfigHelper.js +28 -0
  39. package/src/components/vector-properties/VcsFeatureEditingWindow.vue +15 -5
  40. package/src/components/vector-properties/VcsFeatureEditingWindow.vue.d.ts +123 -1
  41. package/src/contentTree/layerContentTreeItem.d.ts +4 -0
  42. package/src/contentTree/layerContentTreeItem.js +26 -20
  43. package/src/contentTree/layerGroupContentTreeItem.d.ts +1 -0
  44. package/src/contentTree/layerGroupContentTreeItem.js +32 -26
  45. package/src/contentTree/wmsGroupContentTreeItem.d.ts +1 -0
  46. package/src/contentTree/wmsGroupContentTreeItem.js +26 -19
  47. package/src/featureInfo/balloonHelper.js +8 -2
  48. package/src/manager/panel/PanelComponent.vue +48 -27
  49. package/src/manager/panel/PanelComponent.vue.d.ts +0 -1
  50. package/src/manager/panel/PanelManagerComponent.vue +42 -19
  51. package/src/manager/panel/PanelManagerComponent.vue.d.ts +4 -3
  52. package/src/search/search.js +2 -0
  53. package/src/uiConfig.d.ts +46 -0
  54. package/src/uiConfig.js +3 -0
  55. package/dist/assets/ui-f33a5ee2.css +0 -1
  56. /package/dist/assets/{cesium-bc979301.js → cesium-8369e63b.js} +0 -0
  57. /package/dist/assets/core-workers/{panoramaImageWorker.js-2cf50d2d.js → panoramaImageWorker.js-f9c706f1.js} +0 -0
  58. /package/dist/assets/{ol-28f9c83c.js → ol-9f59d99f.js} +0 -0
  59. /package/dist/assets/{vue-004523e0.js → vue-f6136dc6.js} +0 -0
  60. /package/dist/assets/{vuetify-2fc014c4.css → vuetify-de6f6eb0.css} +0 -0
@@ -6,6 +6,7 @@ import { ObliqueMap } from '@vcmap/core';
6
6
  * @property {string} provider - name of the data provider
7
7
  * @property {number} [year] - year of dataset
8
8
  * @property {string} url - link to data provider
9
+ * @property {string} [icon] - provider logo
9
10
  */
10
11
 
11
12
  /**
@@ -18,12 +19,12 @@ import { ObliqueMap } from '@vcmap/core';
18
19
  /**
19
20
  * merges attribution entries of same providers
20
21
  * @param {Array<AttributionEntry>} entries
21
- * @returns {Array<{provider: string, years: string, url: string}>}
22
+ * @returns {Array<{provider: string, years: string, url: string, icon?:string}>}
22
23
  */
23
24
  export function mergeAttributions(entries) {
24
25
  const providers = {};
25
26
  entries.forEach(({ attributions }) => {
26
- attributions.forEach(({ provider, year, url }) => {
27
+ attributions.forEach(({ provider, year, url, icon }) => {
27
28
  const providerObject = providers[provider];
28
29
  if (providerObject) {
29
30
  if (year) {
@@ -36,12 +37,16 @@ export function mergeAttributions(entries) {
36
37
  const set = new Set([...providerObject.years, Number(year)]);
37
38
  providerObject.years = [...set].sort((a, b) => a - b);
38
39
  }
40
+ if (icon && !providerObject.icon) {
41
+ providerObject.icon = icon;
42
+ }
39
43
  }
40
44
  }
41
45
  } else {
42
46
  providers[provider] = {
43
47
  years: year ? [Number(year)] : [],
44
48
  url,
49
+ ...(icon && { icon }),
45
50
  };
46
51
  }
47
52
  });
@@ -10,6 +10,12 @@ export function getDataProtection(uiConfig: import("../uiConfig.js").UiConfigObj
10
10
  * @returns {import('vue').ComputedRef<import('../uiConfig.js').TextPageType|undefined>}
11
11
  */
12
12
  export function getImprint(uiConfig: import("../uiConfig.js").UiConfigObject): import('vue').ComputedRef<import('../uiConfig.js').TextPageType | undefined>;
13
+ /**
14
+ * Creates a computed property for additional footer information configuration.
15
+ * @param {import("../uiConfig.js").UiConfigObject} uiConfig - The UI configuration object from the app.
16
+ * @returns {import('vue').ComputedRef<import('../uiConfig.js').TextPageType[]|undefined>}
17
+ */
18
+ export function getFooterInformation(uiConfig: import("../uiConfig.js").UiConfigObject): import('vue').ComputedRef<import('../uiConfig.js').TextPageType[] | undefined>;
13
19
  /**
14
20
  * Creates a computed property for mobile logo.
15
21
  * @param {import("../vcsUiApp.js").default} app - The VcsUiApp.
@@ -1,3 +1,4 @@
1
+ import { getLogger } from '@vcsuite/logger';
1
2
  import { computed } from 'vue';
2
3
 
3
4
  /**
@@ -35,6 +36,33 @@ export function getImprint(uiConfig) {
35
36
  return undefined;
36
37
  });
37
38
  }
39
+ /**
40
+ * Creates a computed property for additional footer information configuration.
41
+ * @param {import("../uiConfig.js").UiConfigObject} uiConfig - The UI configuration object from the app.
42
+ * @returns {import('vue').ComputedRef<import('../uiConfig.js').TextPageType[]|undefined>}
43
+ */
44
+ export function getFooterInformation(uiConfig) {
45
+ return computed(() => {
46
+ if (uiConfig?.footerInformation) {
47
+ return uiConfig.footerInformation
48
+ .filter((info) => {
49
+ if (!info.title && !info.url) {
50
+ getLogger('uiConfigHelper').warn(
51
+ 'Footer information item skipped, missing title or url',
52
+ info,
53
+ );
54
+ return false;
55
+ }
56
+ return true;
57
+ })
58
+ .map((info) => ({
59
+ title: info.title || new URL(info.url, window.location.href).hostname,
60
+ ...info,
61
+ }));
62
+ }
63
+ return undefined;
64
+ });
65
+ }
38
66
 
39
67
  /**
40
68
  * Creates a computed property for mobile logo.
@@ -59,6 +59,7 @@
59
59
  CesiumMap,
60
60
  GeometryType,
61
61
  is2DLayout,
62
+ PanoramaMap,
62
63
  SessionType,
63
64
  TransformationMode,
64
65
  VectorProperties,
@@ -280,12 +281,21 @@
280
281
  }),
281
282
  );
282
283
 
283
- function updateIs3D() {
284
- is3D.value = vcsApp.maps.activeMap instanceof CesiumMap;
284
+ const defaultVectorProperties = reactive(
285
+ VectorProperties.getDefaultOptions(),
286
+ );
287
+ function activeMapHandler() {
288
+ const isPanorama = vcsApp.maps.activeMap instanceof PanoramaMap;
289
+ is3D.value = vcsApp.maps.activeMap instanceof CesiumMap || isPanorama;
290
+
291
+ defaultVectorProperties.altitudeMode = isPanorama
292
+ ? 'absolute'
293
+ : 'clampToGround';
285
294
  }
295
+
286
296
  const mapActivatedListener =
287
- vcsApp.maps.mapActivated.addEventListener(updateIs3D);
288
- updateIs3D();
297
+ vcsApp.maps.mapActivated.addEventListener(activeMapHandler);
298
+ activeMapHandler();
289
299
 
290
300
  const isGeometryEditing = computed(
291
301
  () => editSession.value?.type === SessionType.EDIT_GEOMETRY,
@@ -476,7 +486,7 @@
476
486
  is2DFeature,
477
487
  isGeometryEditing,
478
488
  updateFeatureProperties,
479
- defaultVectorProperties: VectorProperties.getDefaultOptions(),
489
+ defaultVectorProperties,
480
490
  showInputs: computed(
481
491
  () =>
482
492
  !currentTransformationMode.value &&
@@ -1,3 +1,5 @@
1
+ /// <reference types="@vcmap-cesium/engine" />
2
+ /// <reference types="@vcmap/core/dist/cesium.js" />
1
3
  /**
2
4
  * Returns the allowed transformation modes for the provided geometry types and number of features. Rotate is e.g. not allowed for a single point but for multiple points.
3
5
  * @param {Set<GeometryType>} geometryTypes A set with all geometry types of the features.
@@ -59,7 +61,127 @@ declare const _default: import("vue").DefineComponent<{
59
61
  is2DFeature: import("vue").ComputedRef<boolean>;
60
62
  isGeometryEditing: import("vue").ComputedRef<boolean>;
61
63
  updateFeatureProperties: (update: import("@vcmap/core").VectorPropertiesOptions) => void;
62
- defaultVectorProperties: import("@vcmap/core", { with: { "resolution-mode": "import" } }).VectorPropertiesOptions;
64
+ defaultVectorProperties: {
65
+ altitudeMode?: import("@vcmap/core/dist/src/layer/vectorProperties.js", { with: { "resolution-mode": "import" } }).AltitudeModeType | undefined;
66
+ allowPicking?: boolean | undefined;
67
+ classificationType?: import("@vcmap/core/dist/src/layer/vectorProperties.js", { with: { "resolution-mode": "import" } }).ClassificationTypeType | undefined;
68
+ scaleByDistance?: number[] | undefined;
69
+ eyeOffset?: number[] | undefined;
70
+ heightAboveGround?: number | undefined;
71
+ skirt?: number | undefined;
72
+ groundLevel?: number | undefined;
73
+ extrudedHeight?: number | undefined;
74
+ storeysAboveGround?: number | undefined;
75
+ storeysBelowGround?: number | undefined;
76
+ storeyHeightsAboveGround?: number | number[] | undefined;
77
+ storeyHeightsBelowGround?: number | number[] | undefined;
78
+ modelUrl?: string | undefined;
79
+ modelScaleX?: number | undefined;
80
+ modelScaleY?: number | undefined;
81
+ modelScaleZ?: number | undefined;
82
+ modelHeading?: number | undefined;
83
+ modelPitch?: number | undefined;
84
+ modelRoll?: number | undefined;
85
+ modelAutoScale?: boolean | undefined;
86
+ modelOptions?: Record<string, unknown> | undefined;
87
+ primitiveOptions?: {
88
+ type: import("@vcmap/core", { with: { "resolution-mode": "import" } }).PrimitiveOptionsType;
89
+ geometryOptions: {
90
+ length: number;
91
+ topRadius: number;
92
+ bottomRadius: number;
93
+ slices?: number | undefined;
94
+ vertexFormat?: {
95
+ position: boolean;
96
+ normal: boolean;
97
+ st: boolean;
98
+ bitangent: boolean;
99
+ tangent: boolean;
100
+ color: boolean;
101
+ } | undefined;
102
+ } | {
103
+ radius?: number | undefined;
104
+ stackPartitions?: number | undefined;
105
+ slicePartitions?: number | undefined;
106
+ vertexFormat?: {
107
+ position: boolean;
108
+ normal: boolean;
109
+ st: boolean;
110
+ bitangent: boolean;
111
+ tangent: boolean;
112
+ color: boolean;
113
+ } | undefined;
114
+ } | {
115
+ radii?: {
116
+ x: number;
117
+ y: number;
118
+ z: number;
119
+ clone: (result?: import("@vcmap-cesium/engine", { with: { "resolution-mode": "import" } }).Cartesian3 | undefined) => import("@vcmap-cesium/engine", { with: { "resolution-mode": "import" } }).Cartesian3;
120
+ equals: (right?: import("@vcmap-cesium/engine", { with: { "resolution-mode": "import" } }).Cartesian3 | undefined) => boolean;
121
+ equalsEpsilon: (right?: import("@vcmap-cesium/engine", { with: { "resolution-mode": "import" } }).Cartesian3 | undefined, relativeEpsilon?: number | undefined, absoluteEpsilon?: number | undefined) => boolean;
122
+ toString: () => string;
123
+ } | undefined;
124
+ innerRadii?: {
125
+ x: number;
126
+ y: number;
127
+ z: number;
128
+ clone: (result?: import("@vcmap-cesium/engine", { with: { "resolution-mode": "import" } }).Cartesian3 | undefined) => import("@vcmap-cesium/engine", { with: { "resolution-mode": "import" } }).Cartesian3;
129
+ equals: (right?: import("@vcmap-cesium/engine", { with: { "resolution-mode": "import" } }).Cartesian3 | undefined) => boolean;
130
+ equalsEpsilon: (right?: import("@vcmap-cesium/engine", { with: { "resolution-mode": "import" } }).Cartesian3 | undefined, relativeEpsilon?: number | undefined, absoluteEpsilon?: number | undefined) => boolean;
131
+ toString: () => string;
132
+ } | undefined;
133
+ minimumClock?: number | undefined;
134
+ maximumClock?: number | undefined;
135
+ minimumCone?: number | undefined;
136
+ maximumCone?: number | undefined;
137
+ stackPartitions?: number | undefined;
138
+ slicePartitions?: number | undefined;
139
+ vertexFormat?: {
140
+ position: boolean;
141
+ normal: boolean;
142
+ st: boolean;
143
+ bitangent: boolean;
144
+ tangent: boolean;
145
+ color: boolean;
146
+ } | undefined;
147
+ } | {
148
+ minimum: {
149
+ x: number;
150
+ y: number;
151
+ z: number;
152
+ clone: (result?: import("@vcmap-cesium/engine", { with: { "resolution-mode": "import" } }).Cartesian3 | undefined) => import("@vcmap-cesium/engine", { with: { "resolution-mode": "import" } }).Cartesian3;
153
+ equals: (right?: import("@vcmap-cesium/engine", { with: { "resolution-mode": "import" } }).Cartesian3 | undefined) => boolean;
154
+ equalsEpsilon: (right?: import("@vcmap-cesium/engine", { with: { "resolution-mode": "import" } }).Cartesian3 | undefined, relativeEpsilon?: number | undefined, absoluteEpsilon?: number | undefined) => boolean;
155
+ toString: () => string;
156
+ };
157
+ maximum: {
158
+ x: number;
159
+ y: number;
160
+ z: number;
161
+ clone: (result?: import("@vcmap-cesium/engine", { with: { "resolution-mode": "import" } }).Cartesian3 | undefined) => import("@vcmap-cesium/engine", { with: { "resolution-mode": "import" } }).Cartesian3;
162
+ equals: (right?: import("@vcmap-cesium/engine", { with: { "resolution-mode": "import" } }).Cartesian3 | undefined) => boolean;
163
+ equalsEpsilon: (right?: import("@vcmap-cesium/engine", { with: { "resolution-mode": "import" } }).Cartesian3 | undefined, relativeEpsilon?: number | undefined, absoluteEpsilon?: number | undefined) => boolean;
164
+ toString: () => string;
165
+ };
166
+ vertexFormat?: {
167
+ position: boolean;
168
+ normal: boolean;
169
+ st: boolean;
170
+ bitangent: boolean;
171
+ tangent: boolean;
172
+ color: boolean;
173
+ } | undefined;
174
+ } | undefined;
175
+ depthFailColor?: string | number[] | {
176
+ setTransform: (transform?: DOMMatrix2DInit | undefined) => void;
177
+ } | {
178
+ addColorStop: (offset: number, color: string) => void;
179
+ } | undefined;
180
+ offset?: number[] | undefined;
181
+ additionalOptions?: Record<string, unknown> | undefined;
182
+ } | undefined;
183
+ baseUrl?: string | undefined;
184
+ };
63
185
  showInputs: import("vue").ComputedRef<boolean>;
64
186
  }, any, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
65
187
  allowedVectorProperties: {
@@ -74,6 +74,10 @@ declare class LayerContentTreeItem extends VcsObjectContentTreeItem<LayerContent
74
74
  * @private
75
75
  */
76
76
  private _clearListeners;
77
+ /**
78
+ * @private
79
+ */
80
+ private _determineSupport;
77
81
  /**
78
82
  * @private
79
83
  */
@@ -205,6 +205,17 @@ class LayerContentTreeItem extends VcsObjectContentTreeItem {
205
205
  this._listeners.splice(0);
206
206
  }
207
207
 
208
+ /**
209
+ * @private
210
+ */
211
+ _determineSupport() {
212
+ const isSupported = this._layer.isSupported(this._app.maps.activeMap);
213
+ this.visible = isSupported || this._showWhenNotSupported;
214
+ if (this._showWhenNotSupported) {
215
+ this.disabled = !isSupported;
216
+ }
217
+ }
218
+
208
219
  /**
209
220
  * @private
210
221
  */
@@ -220,42 +231,37 @@ class LayerContentTreeItem extends VcsObjectContentTreeItem {
220
231
  }
221
232
  };
222
233
 
234
+ let supportedLayersListener = () => {};
235
+ const setActiveMap = (map) => {
236
+ supportedLayersListener();
237
+ this._determineSupport();
238
+ supportedLayersListener = map
239
+ ? map.layerTypesChanged.addEventListener(() => {
240
+ this._determineSupport();
241
+ })
242
+ : () => {};
243
+ };
223
244
  if (!this._layer) {
224
245
  this.visible = false;
225
246
  this._listeners.push(
226
247
  this._app.layers.added.addEventListener(resetHandler),
227
248
  );
228
249
  } else {
229
- let isSupported = this._layer.isSupported(this._app.maps.activeMap);
230
- this.visible = isSupported || this._showWhenNotSupported;
231
- if (this._showWhenNotSupported) {
232
- this.disabled = !isSupported;
233
- }
250
+ setActiveMap(this._app.maps.activeMap);
234
251
  this.state = getStateFromLayer(this._layer);
235
252
  this._setLayerExtentAction();
236
253
  this.setPropertiesFromObject(this._layer);
237
254
 
238
255
  this._listeners.push(
239
256
  this._app.layers.removed.addEventListener(resetHandler),
240
- );
241
- this._listeners.push(
242
257
  this._app.layers.added.addEventListener(resetHandler),
243
- );
244
-
245
- this._listeners.push(
246
258
  this._layer.stateChanged.addEventListener(() => {
247
259
  this.state = getStateFromLayer(this._layer);
248
260
  }),
249
- );
250
-
251
- this._listeners.push(
252
- this._app.maps.mapActivated.addEventListener(() => {
253
- isSupported = this._layer.isSupported(this._app.maps.activeMap);
254
- this.visible = isSupported || this._showWhenNotSupported;
255
- if (this._showWhenNotSupported) {
256
- this.disabled = !isSupported;
257
- }
258
- }),
261
+ this._app.maps.mapActivated.addEventListener(setActiveMap),
262
+ () => {
263
+ supportedLayersListener();
264
+ },
259
265
  );
260
266
  }
261
267
  }
@@ -50,6 +50,7 @@ declare class LayerGroupContentTreeItem extends ContentTreeItem {
50
50
  * @private
51
51
  */
52
52
  private _clearListeners;
53
+ _determineSupport(): void;
53
54
  /**
54
55
  * @private
55
56
  */
@@ -118,6 +118,17 @@ class LayerGroupContentTreeItem extends ContentTreeItem {
118
118
  this._listeners.splice(0);
119
119
  }
120
120
 
121
+ _determineSupport() {
122
+ const isSupported = this._layers.some((l) =>
123
+ l.isSupported(this._app.maps.activeMap),
124
+ );
125
+
126
+ this.visible = isSupported || this._showWhenNotSupported;
127
+ if (this._showWhenNotSupported) {
128
+ this.disabled = !isSupported;
129
+ }
130
+ }
131
+
121
132
  /**
122
133
  * @private
123
134
  */
@@ -132,15 +143,21 @@ class LayerGroupContentTreeItem extends ContentTreeItem {
132
143
  this._setup();
133
144
  }
134
145
  };
135
- const layers = this._layers;
136
- let isSupported = layers.some((l) =>
137
- l.isSupported(this._app.maps.activeMap),
138
- );
139
146
 
140
- this.visible = isSupported || this._showWhenNotSupported;
141
- if (this._showWhenNotSupported) {
142
- this.disabled = !isSupported;
143
- }
147
+ let supportedLayersListener = () => {};
148
+
149
+ const setActiveMap = (map) => {
150
+ supportedLayersListener();
151
+ this._determineSupport();
152
+ supportedLayersListener = map
153
+ ? map.layerTypesChanged.addEventListener(() => {
154
+ this._determineSupport();
155
+ })
156
+ : () => {};
157
+ };
158
+
159
+ const layers = this._layers;
160
+ setActiveMap(this._app.maps.activeMap);
144
161
  this.state = getStateFromLayers(layers);
145
162
  setViewpointAction(this, this._app, this._defaultViewpoint);
146
163
  setStyleAction(
@@ -153,27 +170,16 @@ class LayerGroupContentTreeItem extends ContentTreeItem {
153
170
 
154
171
  this._listeners.push(
155
172
  this._app.layers.removed.addEventListener(resetHandler),
156
- );
157
- this._listeners.push(this._app.layers.added.addEventListener(resetHandler));
158
-
159
- layers.forEach((layer) => {
160
- this._listeners.push(
173
+ this._app.layers.added.addEventListener(resetHandler),
174
+ ...layers.map((layer) =>
161
175
  layer.stateChanged.addEventListener(() => {
162
176
  this.state = getStateFromLayers(layers);
163
177
  }),
164
- );
165
- });
166
-
167
- this._listeners.push(
168
- this._app.maps.mapActivated.addEventListener(() => {
169
- isSupported = layers.some((l) =>
170
- l.isSupported(this._app.maps.activeMap),
171
- );
172
- this.visible = isSupported || this._showWhenNotSupported;
173
- if (this._showWhenNotSupported) {
174
- this.disabled = !isSupported;
175
- }
176
- }),
178
+ ),
179
+ this._app.maps.mapActivated.addEventListener(setActiveMap),
180
+ () => {
181
+ supportedLayersListener();
182
+ },
177
183
  );
178
184
  }
179
185
 
@@ -216,6 +216,7 @@ declare class WMSGroupContentTreeItem extends VcsObjectContentTreeItem<import(".
216
216
  * @private
217
217
  */
218
218
  private _setStateFromLayer;
219
+ _determineSupport(): void;
219
220
  /**
220
221
  * Loads WMS entries and creates child items
221
222
  * @returns {Promise<void>}
@@ -574,6 +574,14 @@ class WMSGroupContentTreeItem extends VcsObjectContentTreeItem {
574
574
  }
575
575
  }
576
576
 
577
+ _determineSupport() {
578
+ const isSupported = this._layer.isSupported(this._app.maps.activeMap);
579
+ this.visible = isSupported || this._showWhenNotSupported;
580
+ if (this._showWhenNotSupported) {
581
+ this.disabled = !isSupported;
582
+ }
583
+ }
584
+
577
585
  /**
578
586
  * Loads WMS entries and creates child items
579
587
  * @returns {Promise<void>}
@@ -673,26 +681,31 @@ class WMSGroupContentTreeItem extends VcsObjectContentTreeItem {
673
681
  this._setup();
674
682
  }
675
683
  };
684
+
685
+ let supportedLayersListener = () => {};
686
+
687
+ const setActiveMap = (map) => {
688
+ supportedLayersListener();
689
+ this._determineSupport();
690
+ supportedLayersListener = map
691
+ ? map.layerTypesChanged.addEventListener(() => {
692
+ this._determineSupport();
693
+ })
694
+ : () => {};
695
+ };
696
+
676
697
  if (!this._layer) {
677
698
  this.visible = false;
678
699
  this._listeners.push(
679
700
  this._app.layers.added.addEventListener(resetHandler),
680
701
  );
681
702
  } else {
682
- let isSupported = this._layer.isSupported(this._app.maps.activeMap);
683
- this.visible = isSupported || this._showWhenNotSupported;
684
- if (this._showWhenNotSupported) {
685
- this.disabled = !isSupported;
686
- }
687
703
  this.setPropertiesFromObject(this._layer);
704
+ setActiveMap(this._app.maps.activeMap);
688
705
 
689
706
  this._listeners.push(
690
707
  this._app.layers.removed.addEventListener(resetHandler),
691
- );
692
- this._listeners.push(
693
708
  this._app.layers.added.addEventListener(resetHandler),
694
- );
695
- this._listeners.push(
696
709
  this._layer.stateChanged.addEventListener(() => {
697
710
  if (!this._pauseStateChangedListener) {
698
711
  this._setStateFromLayer();
@@ -700,16 +713,10 @@ class WMSGroupContentTreeItem extends VcsObjectContentTreeItem {
700
713
  this._setLegend();
701
714
  }
702
715
  }),
703
- );
704
- this._listeners.push(
705
- this._app.maps.mapActivated.addEventListener(() => {
706
- isSupported = this._layer.isSupported(this._app.maps.activeMap);
707
- this.visible =
708
- (isSupported || this._showWhenNotSupported) && !this._invalid;
709
- if (this._showWhenNotSupported) {
710
- this.disabled = !isSupported;
711
- }
712
- }),
716
+ this._app.maps.mapActivated.addEventListener(setActiveMap),
717
+ () => {
718
+ supportedLayersListener();
719
+ },
713
720
  );
714
721
 
715
722
  if (this._loadOnStartup) {
@@ -91,10 +91,16 @@ export function setBalloonPosition(windowManager, id, windowPosition, target) {
91
91
  }
92
92
 
93
93
  const { width, height, maxWidth, maxHeight } = windowManager.get(id).position;
94
+
95
+ // Get the actual map target bounding rect to account for panel offsets
96
+ const targetRect = target?.getBoundingClientRect();
97
+ const offsetX = targetRect ? targetRect.left : 0;
98
+ const offsetY = targetRect ? targetRect.top : 0;
99
+
94
100
  const mapWindowPosition = getWindowPositionOptionsFromMapEvent(
95
101
  new Cartesian2(
96
- windowPosition.x - balloonOffset.x,
97
- windowPosition.y - balloonOffset.y,
102
+ windowPosition.x - balloonOffset.x + offsetX,
103
+ windowPosition.y - balloonOffset.y + offsetY,
98
104
  ),
99
105
  target,
100
106
  WindowAlignment.BOTTOM_LEFT,
@@ -10,10 +10,20 @@
10
10
  'theme--dark': appIsDark,
11
11
  resizable: panelState.resizable,
12
12
  }"
13
- @mousedown="startResize"
14
- @mouseup="stopResize"
15
13
  >
16
- <slot />
14
+ <div class="panel-content">
15
+ <slot />
16
+ </div>
17
+ <div
18
+ class="resize-handle"
19
+ :class="{
20
+ 'resize-handle-left': isLeft,
21
+ 'resize-handle-right': isRight,
22
+ 'resize-handle-bottom': isBottom,
23
+ 'resize-handle-resizable': panelState.resizable,
24
+ }"
25
+ @pointerdown="startResize"
26
+ ></div>
17
27
  </div>
18
28
  </template>
19
29
 
@@ -53,19 +63,12 @@
53
63
  () => props.panelState.location === PanelLocation.BOTTOM,
54
64
  ),
55
65
  startResize(e) {
56
- const { resizable, location } = props.panelState;
57
- if (
58
- resizable &&
59
- ((location === PanelLocation.LEFT &&
60
- e.currentTarget.clientWidth - e.offsetX < 4) ||
61
- (location === PanelLocation.RIGHT && e.offsetX < 4) ||
62
- (location === PanelLocation.BOTTOM && e.offsetY < 4))
63
- ) {
64
- emit('resize', props.panelState.id);
66
+ if (!props.panelState.resizable) {
67
+ return;
65
68
  }
66
- },
67
- stopResize() {
68
- emit('resize', undefined);
69
+ e.preventDefault();
70
+ e.stopPropagation();
71
+ emit('resize', props.panelState.id);
69
72
  },
70
73
  };
71
74
  },
@@ -74,39 +77,57 @@
74
77
 
75
78
  <style scoped lang="scss">
76
79
  .panel-component {
80
+ display: flex;
81
+ flex-direction: column;
82
+ }
83
+
84
+ .theme--light {
85
+ background: rgb(var(--v-theme-surface));
86
+ }
87
+
88
+ .theme--dark {
89
+ background: rgb(var(--v-theme-surface));
90
+ }
91
+
92
+ .panel-content {
93
+ flex: 1;
94
+ overflow: auto;
77
95
  padding: 0 4px;
96
+ min-height: 0; /* Important for flex children to be scrollable */
78
97
  }
79
- .panel-component::after {
80
- content: '';
98
+
99
+ .resize-handle {
81
100
  position: absolute;
82
101
  background: rgb(var(--v-theme-surface-light));
83
102
  }
84
103
 
85
- .panel-component-left::after {
104
+ .resize-handle-left {
86
105
  width: 4px;
87
106
  top: 0;
88
107
  bottom: 0;
89
108
  right: 0;
90
109
  }
91
- .panel-component-left.resizable::after {
92
- cursor: ew-resize;
93
- }
94
- .panel-component-right::after {
110
+
111
+ .resize-handle-right {
95
112
  width: 4px;
96
113
  top: 0;
97
114
  bottom: 0;
98
115
  left: 0;
99
116
  }
100
- .panel-component-right.resizable::after {
101
- cursor: ew-resize;
102
- }
103
- .panel-component-bottom::after {
117
+
118
+ .resize-handle-bottom {
104
119
  left: 0;
105
120
  right: 0;
106
121
  top: 0;
107
122
  height: 4px;
108
123
  }
109
- .panel-component-bottom.resizable::after {
124
+
125
+ .resize-handle-resizable.resize-handle-left,
126
+ .resize-handle-resizable.resize-handle-right {
127
+ cursor: ew-resize;
128
+ }
129
+
130
+ .resize-handle-resizable.resize-handle-bottom {
110
131
  cursor: n-resize;
111
132
  }
112
133
  </style>