@vcmap/ui 5.0.0-rc.15 → 5.0.0-rc.16

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 (75) hide show
  1. package/config/base.config.json +4 -0
  2. package/config/dev.config.json +5 -1
  3. package/config/www.config.json +5 -3
  4. package/dist/assets/{cesium.2e288a.js → cesium.430460.js} +0 -0
  5. package/dist/assets/cesium.js +1 -1
  6. package/dist/assets/{core.8014d3.js → core.5089ba.js} +5925 -4374
  7. package/dist/assets/core.js +1 -1
  8. package/dist/assets/{index.3f74fa92.js → index.854f8e2b.js} +1 -1
  9. package/dist/assets/{ol.31c3a5.js → ol.9be53a.js} +0 -0
  10. package/dist/assets/ol.js +1 -1
  11. package/dist/assets/ui.49010a.css +1 -0
  12. package/dist/assets/{ui.36f84f.js → ui.49010a.js} +3907 -3232
  13. package/dist/assets/ui.js +1 -1
  14. package/dist/assets/{vue.a39c10.js → vue.247c1c.js} +0 -0
  15. package/dist/assets/vue.js +2 -2
  16. package/dist/assets/{vuetify.378637.css → vuetify.735e58.css} +1 -1
  17. package/dist/assets/{vuetify.378637.js → vuetify.735e58.js} +1 -1
  18. package/dist/assets/vuetify.js +2 -2
  19. package/dist/index.html +1 -1
  20. package/index.html +77 -0
  21. package/index.js +4 -0
  22. package/package.json +4 -2
  23. package/plugins/@vcmap/create-link/fallbackCreateLink.vue +4 -1
  24. package/plugins/@vcmap/create-link/index.js +4 -1
  25. package/plugins/@vcmap/pluginExample/exampleActions.js +45 -0
  26. package/plugins/@vcmap/pluginExample/index.js +24 -1
  27. package/plugins/@vcmap/pluginExample/pluginExampleComponent.vue +70 -42
  28. package/plugins/@vcmap/search-nominatim/nominatim.js +1 -1
  29. package/plugins/@vcmap/theme-changer/ThemeChangerComponent.vue +4 -2
  30. package/plugins/notifier/index.js +31 -0
  31. package/plugins/notifier/notifierTester.vue +88 -0
  32. package/plugins/package.json +1 -1
  33. package/plugins/test/allIconsComponent.vue +2 -2
  34. package/plugins/test/emptyComponent.vue +1 -1
  35. package/plugins/test/index.js +22 -0
  36. package/plugins/test/myCustomHeader.vue +9 -1
  37. package/plugins/test/testList.vue +287 -0
  38. package/plugins/test/windowManagerExample.vue +3 -0
  39. package/plugins/wizardExample/index.js +41 -0
  40. package/plugins/wizardExample/wizardExample.vue +77 -0
  41. package/src/application/VcsApp.vue +18 -8
  42. package/src/components/form-inputs-controls/VcsFormSection.vue +10 -10
  43. package/src/components/form-inputs-controls/VcsSelect.vue +33 -1
  44. package/src/components/form-inputs-controls/VcsTextField.vue +11 -3
  45. package/src/components/form-inputs-controls/VcsWizard.vue +133 -0
  46. package/src/components/imageElementInjector.vue +22 -0
  47. package/src/components/lists/VcsList.vue +466 -0
  48. package/src/components/lists/VcsTreeview.vue +1 -2
  49. package/src/components/lists/VcsTreeviewLeaf.vue +18 -50
  50. package/src/components/lists/VcsTreeviewSearchbar.vue +1 -23
  51. package/src/components/tables/VcsTable.vue +13 -1
  52. package/src/contentTree/LayerTree.vue +1 -1
  53. package/src/contentTree/contentTreeItem.js +13 -13
  54. package/src/contentTree/subContentTreeItem.js +1 -1
  55. package/src/contentTree/vcsObjectContentTreeItem.js +1 -1
  56. package/src/featureInfo/BalloonComponent.vue +10 -8
  57. package/src/featureInfo/balloonFeatureInfoView.js +14 -14
  58. package/src/featureInfo/balloonHelper.js +4 -0
  59. package/src/featureInfo/featureInfo.js +13 -0
  60. package/src/featureInfo/featureInfoInteraction.js +1 -1
  61. package/src/i18n/de.js +7 -0
  62. package/src/i18n/en.js +7 -0
  63. package/src/icons/+all.js +4 -0
  64. package/src/icons/WandIcon.vue +63 -0
  65. package/src/manager/window/WindowComponent.vue +9 -2
  66. package/src/manager/window/WindowComponentHeader.vue +33 -7
  67. package/src/manager/window/WindowManager.vue +1 -0
  68. package/src/manager/window/windowManager.js +11 -1
  69. package/src/navigation/overviewMap.js +10 -9
  70. package/src/notifier/notifier.js +121 -0
  71. package/src/notifier/notifierComponent.vue +84 -0
  72. package/src/styles/variables.scss +19 -3
  73. package/src/vcsUiApp.js +19 -1
  74. package/src/vuePlugins/vuetify.js +2 -0
  75. package/dist/assets/ui.36f84f.css +0 -1
@@ -7,30 +7,30 @@ import { createStateRefAction, StateActionState } from '../actions/stateRefActio
7
7
 
8
8
  /**
9
9
  * @typedef {Object} ContentTreeItemOptions
10
- * @property {string} name
10
+ * @property {string} name - name of the item defining the structure within the tree using dot notation.
11
11
  * @property {string} [title] - may be unset, if set from object properties later on. required otherwise
12
12
  * @property {string} [tooltip] - may be unset or set from object properties later on.
13
- * @property {string|HTMLCanvasElement|HTMLImageElement|undefined} icon - an icon URL or element to display
14
- * @property {number} [weight]
15
- * @property {string} [infoUrl]
16
- * @property {boolean} [initOpen=false]
13
+ * @property {string|HTMLCanvasElement|HTMLImageElement|undefined} icon - an icon URL or element to display.
14
+ * @property {number} [weight] - optional weighting of the item. higher weights come first.
15
+ * @property {string} [infoUrl] - optional info url providing link with additional information.
16
+ * @property {boolean} [initOpen=false] - groups being initially open or not.
17
17
  */
18
18
 
19
19
  /**
20
20
  * A readonly rendering interface of a ContentTreeItem.
21
21
  * @typedef {Object} TreeViewItem
22
22
  * @property {string} name
23
- * @property {boolean} visible
24
- * @property {boolean} clickable
25
- * @property {boolean} disabled
26
- * @property {StateActionState} state
27
- * @property {string} title
23
+ * @property {boolean} visible - Whether to display this item or not.
24
+ * @property {boolean} clickable - Whether this item reacts to click events, e.g. with visual feedback
25
+ * @property {boolean} disabled - Whether this item should be displayed as disabled.
26
+ * @property {StateActionState} state - The state of this item. NONE if this item cannot have a state.
27
+ * @property {string} title - The title to be displayed
28
28
  * @property {string} [tooltip]
29
- * @property {string|HTMLCanvasElement|HTMLImageElement|undefined} icon
29
+ * @property {string|HTMLCanvasElement|HTMLImageElement|undefined} [icon] - An optional icon to display with this item. Can be an URL or HTMLElement.
30
30
  * @property {Array<VcsAction>} actions
31
31
  * @property {Array<TreeViewItem>} children
32
32
  * @property {Array<TreeViewItem>} visibleChildren - computed property
33
- * @property {function():Promise<void>} clicked
33
+ * @property {function(PointerEvent):Promise<void>} clicked - A callback called once the item is clicked.
34
34
  */
35
35
 
36
36
  /**
@@ -376,7 +376,7 @@ class ContentTreeItem {
376
376
  * GoToExtent: 8
377
377
  * The default weight is set to always push new actions past these.
378
378
  * @param {VcsAction} action
379
- * @param {number} [weight=0]
379
+ * @param {number} [weight=11]
380
380
  */
381
381
  addAction(action, weight = 11) {
382
382
  check(action.name, String);
@@ -6,7 +6,7 @@ import ContentTreeItem, { contentTreeClassRegistry } from './contentTreeItem.js'
6
6
  export const subTreeSymbol = Symbol('SubTree');
7
7
 
8
8
  /**
9
- * A sub tree item. Subtrees are rendered in their own (not the main content tree).
9
+ * A subtree item. Subtrees are rendered in their own (not the main content tree).
10
10
  * They will receive their own toggle button in the nav bar.
11
11
  * Only toplevel items can be content tree items (with a name which does not have a .)
12
12
  * @class
@@ -9,7 +9,7 @@ import ContentTreeItem, { contentTreeClassRegistry } from './contentTreeItem.js'
9
9
 
10
10
  /**
11
11
  * An abstract class for VcsObject based items.
12
- * It handle the overriding/setting of its own values based on
12
+ * It handles the overriding/setting of its own values based on
13
13
  * the VcsObjects properties bag.
14
14
  * @class
15
15
  * @template {VcsObjectContentTreeItemProperties} T
@@ -17,16 +17,17 @@
17
17
  </v-list-item-avatar>
18
18
  <v-list-item-content class="py-2 pr-1 align-self-start">
19
19
  <v-list-item-title class="text-h6">
20
- {{ $t(title) }}
20
+ {{ $t(balloonTitle) }}
21
21
  </v-list-item-title>
22
- <v-list-item-subtitle v-if="subtitle">
23
- {{ $t(subtitle) }}
22
+ <v-list-item-subtitle v-if="balloonSubtitle">
23
+ {{ $t(balloonSubtitle) }}
24
24
  </v-list-item-subtitle>
25
25
  </v-list-item-content>
26
26
  <VcsButton
27
27
  @click.stop="close"
28
28
  small
29
29
  icon="mdi-close-thick"
30
+ tooltip="components.close"
30
31
  />
31
32
  </v-list-item>
32
33
  </slot>
@@ -58,7 +59,8 @@
58
59
  VList,
59
60
  VListItem,
60
61
  VListItemAvatar,
61
- VListItemContent, VListItemSubtitle,
62
+ VListItemContent,
63
+ VListItemSubtitle,
62
64
  VListItemTitle,
63
65
  } from 'vuetify/lib';
64
66
  import { setupBalloonPositionListener } from './balloonHelper.js';
@@ -68,8 +70,8 @@
68
70
  * @description A balloon viewing feature attributes. Size dynamic dependent on number of attributes.
69
71
  * Scrollable, if more than 6 attributes are provided.
70
72
  * @vue-prop {string} featureId - feature's id
71
- * @vue-prop {string} title - balloon title
72
- * @vue-prop {string} subtitle - balloon subtitle
73
+ * @vue-prop {string} balloonTitle - balloon title
74
+ * @vue-prop {string} balloonSubtitle - balloon subtitle
73
75
  * @vue-prop {Object} attributes - feature's attributes
74
76
  * @vue-prop {Array<import("ol/coordinate").Coordinate>} position - clicked position balloon is rendered at
75
77
  * @vue-data {slot} [#balloon-header] - slot to override balloon header, $props and $attrs are passed to `attrs`
@@ -94,11 +96,11 @@
94
96
  type: String,
95
97
  required: true,
96
98
  },
97
- title: {
99
+ balloonTitle: {
98
100
  type: String,
99
101
  required: true,
100
102
  },
101
- subtitle: {
103
+ balloonSubtitle: {
102
104
  type: String,
103
105
  required: true,
104
106
  },
@@ -26,14 +26,14 @@ export function extractNestedKey(key, attrs, defaultValue = null) {
26
26
 
27
27
  /**
28
28
  * @typedef {FeatureInfoViewOptions} BalloonFeatureInfoViewOptions
29
- * @property {string} [title] - optional title to overwrite default (layerName). Can be attribute key (nested key using '.'), i18n key or text
30
- * @property {string} [subtitle] - optional window title to overwrite default (featureId). Can be attribute key (nested key using '.'), i18n key or text
29
+ * @property {string} [balloonTitle] - optional title to overwrite default (layerName). Can be attribute key (nested key using '.'), i18n key or text
30
+ * @property {string} [balloonSubtitle] - optional window title to overwrite default (featureId). Can be attribute key (nested key using '.'), i18n key or text
31
31
  */
32
32
 
33
33
  /**
34
34
  * @typedef {FeatureInfoProps} BalloonFeatureInfoViewProps
35
- * @property {string} title
36
- * @property {string} subtitle
35
+ * @property {string} balloonTitle
36
+ * @property {string} balloonSubtitle
37
37
  * @property {import("ol/coordinate").Coordinate} position
38
38
  */
39
39
 
@@ -87,12 +87,12 @@ class BalloonFeatureInfoView extends AbstractFeatureInfoView {
87
87
  /**
88
88
  * @type {string}
89
89
  */
90
- this.title = options.title;
90
+ this.balloonTitle = options.balloonTitle;
91
91
 
92
92
  /**
93
93
  * @type {string}
94
94
  */
95
- this.subtitle = options.subtitle;
95
+ this.balloonSubtitle = options.balloonSubtitle;
96
96
  }
97
97
 
98
98
  /**
@@ -105,11 +105,11 @@ class BalloonFeatureInfoView extends AbstractFeatureInfoView {
105
105
  return {
106
106
  ...properties,
107
107
  position: featureInfo.position ?? getPositionFromFeature(featureInfo.feature),
108
- title: this.title != null ?
109
- extractNestedKey(this.title, properties.attributes, this.title) :
108
+ balloonTitle: this.balloonTitle != null ?
109
+ extractNestedKey(this.balloonTitle, properties.attributes, this.balloonTitle) :
110
110
  properties.layerProperties.title,
111
- subtitle: this.subtitle != null ?
112
- extractNestedKey(this.subtitle, properties.attributes, this.subtitle) :
111
+ balloonSubtitle: this.balloonSubtitle != null ?
112
+ extractNestedKey(this.balloonSubtitle, properties.attributes, this.balloonSubtitle) :
113
113
  properties.featureId,
114
114
  };
115
115
  }
@@ -138,11 +138,11 @@ class BalloonFeatureInfoView extends AbstractFeatureInfoView {
138
138
  */
139
139
  toJSON() {
140
140
  const config = super.toJSON();
141
- if (this.title) {
142
- config.title = this.title;
141
+ if (this.balloonTitle) {
142
+ config.balloonTitle = this.balloonTitle;
143
143
  }
144
- if (this.subtitle) {
145
- config.subtitle = this.subtitle;
144
+ if (this.balloonSubtitle) {
145
+ config.balloonSubtitle = this.balloonSubtitle;
146
146
  }
147
147
  return config;
148
148
  }
@@ -99,6 +99,10 @@ export async function setupBalloonPositionListener(vcsApp, windowId, clickedPosi
99
99
 
100
100
  const map = app.maps.activeMap;
101
101
  if (map instanceof CesiumMap) {
102
+ if (!position[2]) {
103
+ const [position3D] = await map.getHeightFromTerrain([position]);
104
+ position[2] = position3D[2];
105
+ }
102
106
  const wgs84Position = Projection.mercatorToWgs84(position);
103
107
  const cartesian = Cartographic.toCartesian(Cartographic.fromDegrees(...wgs84Position));
104
108
  listeners.push(map.getScene().postRender.addEventListener((scene) => {
@@ -231,6 +231,11 @@ class FeatureInfo {
231
231
  * @private
232
232
  */
233
233
  this._selectedFeature = null;
234
+ /**
235
+ * @type {string|null}
236
+ * @private
237
+ */
238
+ this._selectedFeatureId = null;
234
239
  /**
235
240
  * @type {Array<function():void>}
236
241
  * @private
@@ -299,6 +304,12 @@ class FeatureInfo {
299
304
  */
300
305
  get selectedFeature() { return this._selectedFeature; }
301
306
 
307
+ /**
308
+ * @type {null|string}
309
+ * @readonly
310
+ */
311
+ get selectedFeatureId() { return this._selectedFeatureId; }
312
+
302
313
  /**
303
314
  * The window id of the current features FeatureInfoView window
304
315
  * @type {string|null}
@@ -404,6 +415,7 @@ class FeatureInfo {
404
415
  );
405
416
 
406
417
  this._selectedFeature = feature;
418
+ this._selectedFeatureId = feature.getId();
407
419
  this._featureChanged.raiseEvent(this._selectedFeature);
408
420
  } else {
409
421
  this.clear();
@@ -436,6 +448,7 @@ class FeatureInfo {
436
448
  this._clearInternal();
437
449
  if (this._selectedFeature) {
438
450
  this._selectedFeature = null;
451
+ this._selectedFeatureId = null;
439
452
  this._featureChanged.raiseEvent(this._selectedFeature);
440
453
  }
441
454
  }
@@ -24,7 +24,7 @@ class FeatureInfoInteraction extends AbstractInteraction {
24
24
  */
25
25
  async pipe(event) {
26
26
  if (event.feature) {
27
- if (!this._featureInfo.selectedFeature || event.feature.getId() !== this._featureInfo.selectedFeature.getId()) {
27
+ if (!this._featureInfo.selectedFeature || event.feature.getId() !== this._featureInfo.selectedFeatureId) {
28
28
  event.stopPropagation = true;
29
29
  await this._featureInfo.selectFeature(
30
30
  event.feature,
package/src/i18n/de.js CHANGED
@@ -44,6 +44,7 @@ const messages = {
44
44
  components: {
45
45
  title: 'Komponenten',
46
46
  tooltip: 'Komponenten',
47
+ close: 'Fenster schließen.',
47
48
  vcsFormSection: {
48
49
  help: 'Hilfe anzeigen.',
49
50
  },
@@ -91,6 +92,12 @@ const messages = {
91
92
  tooltip: 'Öffne Attribution Fenster',
92
93
  },
93
94
  },
95
+ notification: {
96
+ error: 'Fehler',
97
+ warning: 'Warnung',
98
+ information: 'Information',
99
+ success: 'Erfolg',
100
+ },
94
101
  };
95
102
 
96
103
  export default messages;
package/src/i18n/en.js CHANGED
@@ -44,6 +44,7 @@ const messages = {
44
44
  components: {
45
45
  title: 'Components',
46
46
  tooltip: 'Components',
47
+ close: 'Close window.',
47
48
  vcsFormSection: {
48
49
  help: 'Show help.',
49
50
  },
@@ -91,6 +92,12 @@ const messages = {
91
92
  tooltip: 'Open Attributions Window',
92
93
  },
93
94
  },
95
+ notification: {
96
+ error: 'Error',
97
+ warning: 'Warning',
98
+ information: 'Information',
99
+ success: 'Success',
100
+ },
94
101
  };
95
102
 
96
103
  export default messages;
package/src/icons/+all.js CHANGED
@@ -100,6 +100,7 @@ import Viewshed360Icon from './Viewshed360Icon.vue';
100
100
  import ViewshedConeIcon from './ViewshedConeIcon.vue';
101
101
  import WalkingIcon from './WalkingIcon.vue';
102
102
  import WallIcon from './WallIcon.vue';
103
+ import WandIcon from './WandIcon.vue';
103
104
 
104
105
  // * // IconMap.boundingBox
105
106
  // * <v-icon size="16" v-text="'$vcsBoundingBox'" />
@@ -431,6 +432,9 @@ const IconMap = {
431
432
  walking: {
432
433
  component: WalkingIcon,
433
434
  },
435
+ wand: {
436
+ component: WandIcon,
437
+ },
434
438
  };
435
439
 
436
440
  const nameCapitalized = (name) => { return name.charAt(0).toUpperCase() + name.slice(1); };
@@ -0,0 +1,63 @@
1
+ <!-- eslint-disable max-len -->
2
+
3
+ <template>
4
+ <svg id="icon_wizard" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
5
+ <g id="wand" transform="translate(1.706 1.705)">
6
+ <g id="Gruppe_1465" data-name="Gruppe 1465" transform="translate(0 10.491)">
7
+ <g id="Gruppe_1464" data-name="Gruppe 1464">
8
+ <path id="Pfad_540" data-name="Pfad 540" d="M1.574,22.1a.476.476,0,0,1-.367-.157L.157,20.892a.507.507,0,0,1,0-.734.507.507,0,0,1,.734,0l1.049,1.049a.507.507,0,0,1,0,.734A.476.476,0,0,1,1.574,22.1Z" transform="translate(0 -20)" fill="currentColor" />
9
+ </g>
10
+ </g>
11
+ <g id="Gruppe_1467" data-name="Gruppe 1467" transform="translate(1.049 1.049)">
12
+ <g id="Gruppe_1466" data-name="Gruppe 1466">
13
+ <path id="Pfad_541" data-name="Pfad 541" d="M2.525,13.54a.476.476,0,0,1-.367-.157.507.507,0,0,1,0-.734L12.648,2.157a.519.519,0,1,1,.734.734L2.892,13.382A.476.476,0,0,1,2.525,13.54Z" transform="translate(-2 -2)" fill="currentColor" />
14
+ </g>
15
+ </g>
16
+ <g id="Gruppe_1469" data-name="Gruppe 1469" transform="translate(10.491 0)">
17
+ <g id="Gruppe_1468" data-name="Gruppe 1468">
18
+ <path id="Pfad_542" data-name="Pfad 542" d="M21.574,2.1a.476.476,0,0,1-.367-.157L20.157.892a.507.507,0,0,1,0-.734.507.507,0,0,1,.734,0l1.049,1.049a.507.507,0,0,1,0,.734A.476.476,0,0,1,21.574,2.1Z" transform="translate(-20 0)" fill="currentColor" />
19
+ </g>
20
+ </g>
21
+ <g id="Gruppe_1471" data-name="Gruppe 1471" transform="translate(0 0)">
22
+ <g id="Gruppe_1470" data-name="Gruppe 1470">
23
+ <path id="Pfad_543" data-name="Pfad 543" d="M.525,11.54a.476.476,0,0,1-.367-.157.507.507,0,0,1,0-.734L10.648.157a.507.507,0,0,1,.734,0,.507.507,0,0,1,0,.734L.892,11.382A.476.476,0,0,1,.525,11.54Z" transform="translate(0 0)" fill="currentColor" />
24
+ </g>
25
+ </g>
26
+ <g id="Gruppe_1473" data-name="Gruppe 1473" transform="translate(8.393 2.098)">
27
+ <g id="Gruppe_1472" data-name="Gruppe 1472">
28
+ <path id="Pfad_544" data-name="Pfad 544" d="M17.574,6.1a.476.476,0,0,1-.367-.157L16.157,4.892a.519.519,0,0,1,.734-.734l1.049,1.049a.507.507,0,0,1,0,.734A.476.476,0,0,1,17.574,6.1Z" transform="translate(-16 -4)" fill="currentColor" />
29
+ </g>
30
+ </g>
31
+ <g id="Gruppe_1475" data-name="Gruppe 1475" transform="translate(7.344 7.344)">
32
+ <g id="Gruppe_1474" data-name="Gruppe 1474">
33
+ <path id="Pfad_545" data-name="Pfad 545" d="M14.525,16.1A.5.5,0,0,1,14,15.574V14.525a.525.525,0,1,1,1.049,0v1.049A.5.5,0,0,1,14.525,16.1Z" transform="translate(-14 -14)" fill="currentColor" />
34
+ </g>
35
+ </g>
36
+ <g id="Gruppe_1477" data-name="Gruppe 1477" transform="translate(7.344)">
37
+ <g id="Gruppe_1476" data-name="Gruppe 1476">
38
+ <path id="Pfad_546" data-name="Pfad 546" d="M14.525,2.1A.5.5,0,0,1,14,1.574V.525a.525.525,0,0,1,1.049,0V1.574A.5.5,0,0,1,14.525,2.1Z" transform="translate(-14)" fill="currentColor" />
39
+ </g>
40
+ </g>
41
+ <g id="Gruppe_1479" data-name="Gruppe 1479" transform="translate(3.147 4.196)">
42
+ <g id="Gruppe_1478" data-name="Gruppe 1478">
43
+ <path id="Pfad_547" data-name="Pfad 547" d="M7.574,9.049H6.525A.525.525,0,0,1,6.525,8H7.574a.525.525,0,0,1,0,1.049Z" transform="translate(-6 -8)" fill="currentColor" />
44
+ </g>
45
+ </g>
46
+ <g id="Gruppe_1481" data-name="Gruppe 1481" transform="translate(10.491 4.196)">
47
+ <g id="Gruppe_1480" data-name="Gruppe 1480">
48
+ <path id="Pfad_548" data-name="Pfad 548" d="M21.574,9.049H20.525a.525.525,0,0,1,0-1.049h1.049a.525.525,0,1,1,0,1.049Z" transform="translate(-20 -8)" fill="currentColor" />
49
+ </g>
50
+ </g>
51
+ <g id="Gruppe_1483" data-name="Gruppe 1483" transform="translate(3.986 0.839)">
52
+ <g id="Gruppe_1482" data-name="Gruppe 1482">
53
+ <path id="Pfad_549" data-name="Pfad 549" d="M9.279,3.8a.476.476,0,0,1-.367-.157L7.757,2.492a.519.519,0,0,1,.734-.734l1.1,1.1a.507.507,0,0,1,0,.734A.326.326,0,0,1,9.279,3.8Z" transform="translate(-7.6 -1.6)" fill="currentColor" />
54
+ </g>
55
+ </g>
56
+ <g id="Gruppe_1485" data-name="Gruppe 1485" transform="translate(9.599 6.452)">
57
+ <g id="Gruppe_1484" data-name="Gruppe 1484">
58
+ <path id="Pfad_550" data-name="Pfad 550" d="M19.926,14.451a.476.476,0,0,1-.367-.157l-1.1-1.1a.519.519,0,1,1,.734-.734l1.1,1.1a.507.507,0,0,1,0,.734A.567.567,0,0,1,19.926,14.451Z" transform="translate(-18.3 -12.3)" fill="currentColor" />
59
+ </g>
60
+ </g>
61
+ </g>
62
+ </svg>
63
+ </template>
@@ -19,7 +19,7 @@
19
19
  }"
20
20
  :draggable="isDynamic"
21
21
  >
22
- <slot name="headerComponent" />
22
+ <slot name="headerComponent" :props="$attrs" />
23
23
  </div>
24
24
  <v-divider />
25
25
  <div
@@ -40,7 +40,7 @@
40
40
 
41
41
  <script>
42
42
  import {
43
- onMounted, onUnmounted, computed, ref, nextTick,
43
+ onMounted, onUnmounted, computed, ref, nextTick, inject, provide,
44
44
  } from 'vue';
45
45
  import { fromEvent } from 'rxjs';
46
46
  import { switchMap, take, map, tap } from 'rxjs/operators';
@@ -133,6 +133,13 @@
133
133
  dropSub.unsubscribe();
134
134
  }
135
135
  });
136
+
137
+ const app = inject('vcsApp');
138
+ const { provides } = app.windowManager.get(windowState.id);
139
+ Object.entries(provides)
140
+ .forEach(([key, value]) => {
141
+ provide(key, value);
142
+ });
136
143
  return {
137
144
  isDynamic,
138
145
  isDocked,
@@ -10,29 +10,55 @@
10
10
  {{ $t(windowState.headerTitle) }}
11
11
  </h3>
12
12
  </span>
13
- <VcsButton
14
- @click.stop="close"
15
- small
16
- icon="mdi-close-thick"
17
- />
13
+ <div class="d-flex justify-space-between align-center">
14
+ <template v-if="windowState.headerActions?.length > 0">
15
+ <VcsActionButtonList
16
+ :actions="windowState.headerActions"
17
+ :overflow-count="windowState.headerActionsOverflowCount ?? 3"
18
+ small
19
+ />
20
+ <v-divider
21
+ vertical
22
+ inset
23
+ class="mx-2"
24
+ />
25
+ </template>
26
+ <VcsButton
27
+ @click.stop="close"
28
+ small
29
+ icon="mdi-close-thick"
30
+ tooltip="components.close"
31
+ />
32
+ </div>
18
33
  </span>
19
34
  </template>
20
35
 
21
- <style>
36
+ <style lang="scss" scoped>
22
37
  .window-component-header{
23
38
  max-height: 16px;
39
+
40
+ .v-divider--vertical.v-divider--inset {
41
+ margin-top: 2px;
42
+ }
24
43
  }
25
44
  </style>
26
45
 
27
46
  <script>
28
- import { VIcon } from 'vuetify/lib';
47
+ import { VIcon, VDivider } from 'vuetify/lib';
29
48
  import VcsButton from '../../components/buttons/VcsButton.vue';
49
+ import VcsActionButtonList from '../../components/buttons/VcsActionButtonList.vue';
30
50
 
51
+ /**
52
+ * Default window component header with drag functionality close action and further optional window actions.
53
+ * @vue-prop {WindowState} windowState - state of the window component.
54
+ */
31
55
  export default {
32
56
  name: 'WindowComponentHeader',
33
57
  components: {
58
+ VcsActionButtonList,
34
59
  VcsButton,
35
60
  VIcon,
61
+ VDivider,
36
62
  },
37
63
  props: {
38
64
  windowState: {
@@ -23,6 +23,7 @@
23
23
  <component
24
24
  :is="getHeaderComponent(id)"
25
25
  :window-state="getState(id)"
26
+ v-bind="getProps(id)"
26
27
  @close="close(id)"
27
28
  />
28
29
  </template>
@@ -78,6 +78,7 @@ export const WindowPositions = {
78
78
  * @property {WindowState} [state]
79
79
  * @property {WindowSlot} [slot] If WindowSlot is not detached the position will be ignored
80
80
  * @property {Object} [props]
81
+ * @property {Object} [provides]
81
82
  */
82
83
 
83
84
  /**
@@ -87,6 +88,8 @@ export const WindowPositions = {
87
88
  * @property {boolean} [hideHeader] be used to not show the header.
88
89
  * @property {string} [headerTitle]
89
90
  * @property {string} [headerIcon]
91
+ * @property {Array<VcsAction>} [headerActions]
92
+ * @property {number} [headerActionsOverflowCount]
90
93
  * @property {Object<string, string>} styles[styles] Can be used to add additional styles to the root WindowComponent. Use Vue Style Bindings Object Syntax https://vuejs.org/v2/guide/class-and-style.html
91
94
  * @property {Array<string>|Object<string,string>} [classes] Can be used to add additional classes to the root WindowComponent. Use Vue Class Bindings Syntax https://vuejs.org/v2/guide/class-and-style.html
92
95
  */
@@ -100,6 +103,7 @@ export const WindowPositions = {
100
103
  * @property {WindowState} state
101
104
  * @property {Ref<UnwrapRef<WindowSlot>>} slot
102
105
  * @property {Object} props
106
+ * @property {Object} provides
103
107
  */
104
108
 
105
109
  /**
@@ -417,7 +421,7 @@ class WindowManager {
417
421
  /**
418
422
  * adds a windowComponent to the WindowManager and renders the Window at the provided position/slot.
419
423
  * The reactive WindowState Object can be used to watch Changes on position/WindowSlot.
420
- * The WindowState Object can also be used to change hideHeader, headerTitle, headerIcon, styles and classes
424
+ * The WindowState Object can also be used to change hideHeader, headerTitle, headerIcon, headerActions, styles and classes
421
425
  * @param {WindowComponentOptions|WindowComponent} windowComponentOptions
422
426
  * @param {string|symbol} owner pluginName or vcsAppSymbol
423
427
  * @throws {Error} if a windowComponent with the same ID has already been added
@@ -450,11 +454,14 @@ class WindowManager {
450
454
  hideHeader: !!windowComponentOptions?.state?.hideHeader,
451
455
  headerTitle: windowComponentOptions?.state?.headerTitle,
452
456
  headerIcon: windowComponentOptions?.state?.headerIcon,
457
+ headerActions: windowComponentOptions?.state?.headerActions,
458
+ headerActionsOverflow: windowComponentOptions?.state?.headerActionsOverflow,
453
459
  classes,
454
460
  styles,
455
461
  });
456
462
 
457
463
  const props = windowComponentOptions.props || {};
464
+ const provides = windowComponentOptions.provides || {};
458
465
 
459
466
  const position = reactive(windowPosition);
460
467
  /**
@@ -482,6 +489,9 @@ class WindowManager {
482
489
  get props() {
483
490
  return props;
484
491
  },
492
+ get provides() {
493
+ return provides;
494
+ },
485
495
  };
486
496
  this._removeWindowAtSlot(slot);
487
497
  this._windowComponents.set(id, windowComponent);
@@ -205,7 +205,7 @@ class OverviewMap {
205
205
  clone.activate();
206
206
  const idx = this._map.layerCollection.indexOf(clone);
207
207
  if (idx < 0) {
208
- this._map.layerCollection.add(clone);
208
+ this._map.layerCollection.add(clone, 0);
209
209
  } else {
210
210
  this._map.layerCollection.remove(clone);
211
211
  this._map.layerCollection.add(clone, idx);
@@ -298,6 +298,7 @@ class OverviewMap {
298
298
  this._setupMapInteraction();
299
299
  }
300
300
  await this._map.activate();
301
+ this.map.setTarget('overview-map-container');
301
302
  if (!this._active) {
302
303
  this._mapActivatedListener = this._app.maps.mapActivated.addEventListener(() => {
303
304
  this._clearListeners();
@@ -323,7 +324,6 @@ class OverviewMap {
323
324
  this._app.windowManager.add(getWindowComponentOptions(), vcsAppSymbol);
324
325
  }
325
326
  await this._activate();
326
- this.map.setTarget('overview-map-container');
327
327
  }
328
328
 
329
329
  /**
@@ -347,9 +347,10 @@ class OverviewMap {
347
347
  async _initializePostRenderHandler(map) {
348
348
  if (!this._cameraIconLayer) {
349
349
  this._setupCameraIconLayer();
350
+ this._syncCameraViewAndFeature();
350
351
  }
351
352
  const navRemover = this._addNavigationListener(map);
352
- const prRemover = map.postRender.addEventListener(this._addCameraFeature.bind(this));
353
+ const prRemover = map.postRender.addEventListener(this._syncCameraViewAndFeature.bind(this));
353
354
  const cleanupTasks = () => {
354
355
  prRemover();
355
356
  navRemover();
@@ -513,7 +514,7 @@ class OverviewMap {
513
514
  * Adds and maintains the view and camera feature
514
515
  * @private
515
516
  */
516
- _addCameraFeature() {
517
+ _syncCameraViewAndFeature() {
517
518
  const viewpoint = this._app.maps.activeMap?.getViewpointSync();
518
519
  if (!viewpoint || !viewpoint.isValid() || viewpoint.equals(this._cachedViewpoint)) {
519
520
  return;
@@ -525,8 +526,6 @@ class OverviewMap {
525
526
  let { distance } = viewpoint;
526
527
  if (position[2] && !(distance && distance < position[2] * 4)) {
527
528
  distance = position[2] * 4;
528
- } else if (position[2] == null) {
529
- position[2] = distance;
530
529
  }
531
530
 
532
531
  distance = distance > this.minimumHeight ? distance : this.minimumHeight;
@@ -551,9 +550,11 @@ class OverviewMap {
551
550
  this.cameraIconStyle.image.setRotation(rotationRadians);
552
551
 
553
552
  viewpoint.heading = 0;
554
- viewpoint.cameraPosition = position;
555
- viewpoint.groundPosition = null;
556
- viewpoint.distance = distance * 4;
553
+ if (viewpoint.cameraPosition) {
554
+ viewpoint.cameraPosition = position;
555
+ viewpoint.groundPosition = null;
556
+ viewpoint.distance = distance * 4;
557
+ }
557
558
  this._map.gotoViewpoint(viewpoint);
558
559
  }
559
560