@vcmap/ui 5.0.0-rc.15 → 5.0.0-rc.17
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/buildHelpers.js +7 -1
- package/config/base.config.json +7 -45
- package/config/dev.config.json +5 -1
- package/config/www.config.json +14 -13
- package/dist/assets/{cesium.2e288a.js → cesium.41de56.js} +0 -0
- package/dist/assets/cesium.js +1 -1
- package/dist/assets/{core.8014d3.js → core.af84e3.js} +6077 -4544
- package/dist/assets/core.js +1 -1
- package/dist/assets/{index.3f74fa92.js → index.5b773cad.js} +1 -1
- package/dist/assets/{ol.31c3a5.js → ol.5c7490.js} +0 -0
- package/dist/assets/ol.js +1 -1
- package/dist/assets/ui.dffe32.css +1 -0
- package/dist/assets/{ui.36f84f.js → ui.dffe32.js} +7243 -6234
- package/dist/assets/ui.js +1 -1
- package/dist/assets/{vue.a39c10.js → vue.25da17.js} +0 -0
- package/dist/assets/vue.js +2 -2
- package/dist/assets/{vuetify.378637.css → vuetify.e4ece7.css} +1 -1
- package/dist/assets/{vuetify.378637.js → vuetify.e4ece7.js} +5 -2
- package/dist/assets/vuetify.js +2 -2
- package/dist/index.html +1 -1
- package/index.html +77 -0
- package/index.js +18 -3
- package/package.json +4 -2
- package/plugins/@vcmap/create-link/fallbackCreateLink.vue +4 -1
- package/plugins/@vcmap/create-link/index.js +4 -1
- package/plugins/@vcmap/pluginExample/exampleActions.js +45 -0
- package/plugins/@vcmap/pluginExample/index.js +26 -2
- package/plugins/@vcmap/pluginExample/pluginExampleComponent.vue +77 -42
- package/plugins/@vcmap/search-nominatim/nominatim.js +1 -1
- package/plugins/@vcmap/theme-changer/ThemeChangerComponent.vue +4 -2
- package/plugins/categoryTest/Categories.vue +27 -13
- package/plugins/categoryTest/Category.vue +7 -1
- package/plugins/categoryTest/index.js +1 -1
- package/plugins/notifier/index.js +31 -0
- package/plugins/notifier/notifierTester.vue +88 -0
- package/plugins/package.json +1 -1
- package/plugins/test/allIconsComponent.vue +5 -5
- package/plugins/test/emptyComponent.vue +1 -1
- package/plugins/test/index.js +27 -3
- package/plugins/test/myCustomHeader.vue +9 -1
- package/plugins/test/testList.vue +290 -0
- package/plugins/test/vcsContent.vue +1 -1
- package/plugins/test/windowManagerExample.vue +12 -7
- package/plugins/wizardExample/index.js +41 -0
- package/plugins/wizardExample/wizardExample.vue +77 -0
- package/src/actions/actionHelper.js +10 -9
- package/src/application/VcsApp.vue +43 -34
- package/src/components/form-inputs-controls/VcsCheckbox.vue +1 -0
- package/src/components/form-inputs-controls/VcsFormSection.vue +23 -15
- package/src/components/form-inputs-controls/VcsSelect.vue +33 -1
- package/src/components/form-inputs-controls/VcsTextField.vue +11 -3
- package/src/components/form-inputs-controls/VcsWizard.vue +133 -0
- package/src/components/imageElementInjector.vue +22 -0
- package/src/components/lists/VcsList.vue +468 -0
- package/src/components/lists/VcsTreeview.vue +1 -2
- package/src/components/lists/VcsTreeviewLeaf.vue +18 -50
- package/src/components/lists/VcsTreeviewSearchbar.vue +1 -23
- package/src/components/tables/VcsTable.vue +13 -1
- package/src/contentTree/LayerTree.vue +1 -1
- package/src/contentTree/contentTreeCollection.js +9 -0
- package/src/contentTree/contentTreeItem.js +13 -13
- package/src/contentTree/layerContentTreeItem.js +1 -1
- package/src/contentTree/subContentTreeItem.js +1 -1
- package/src/contentTree/vcsObjectContentTreeItem.js +1 -1
- package/src/featureInfo/BalloonComponent.vue +13 -8
- package/src/featureInfo/balloonFeatureInfoView.js +16 -22
- package/src/featureInfo/balloonHelper.js +26 -5
- package/src/featureInfo/featureInfo.js +14 -2
- package/src/featureInfo/featureInfoInteraction.js +1 -1
- package/src/i18n/de.js +13 -1
- package/src/i18n/en.js +13 -1
- package/src/icons/+all.js +4 -0
- package/src/icons/WandIcon.vue +63 -0
- package/src/manager/categoryManager/CategoryComponent.vue +115 -0
- package/src/manager/categoryManager/CategoryComponentList.vue +57 -0
- package/src/manager/categoryManager/CategoryManager.vue +35 -0
- package/src/manager/categoryManager/categoryManager.js +251 -165
- package/src/manager/contextMenu/contextMenuManager.js +8 -2
- package/src/manager/window/WindowComponent.vue +51 -70
- package/src/manager/window/WindowComponentHeader.vue +81 -13
- package/src/manager/window/WindowManager.vue +54 -30
- package/src/manager/window/windowHelper.js +341 -0
- package/src/manager/window/windowManager.js +173 -151
- package/src/navigation/overviewMap.js +10 -9
- package/src/notifier/notifier.js +120 -0
- package/src/notifier/notifierComponent.vue +84 -0
- package/src/styles/variables.scss +19 -3
- package/src/vcsUiApp.js +26 -2
- package/src/vuePlugins/vuetify.js +2 -0
- package/dist/assets/ui.36f84f.css +0 -1
- package/src/manager/categoryManager/ComponentsManager.vue +0 -30
@@ -3,21 +3,22 @@
|
|
3
3
|
class="d-flex flex-row align-center"
|
4
4
|
v-if="item"
|
5
5
|
>
|
6
|
-
<span v-if="item.icon" class="d-flex align-center">
|
7
|
-
<v-icon
|
8
|
-
v-if="iconType === iconTypes.string"
|
9
|
-
v-text="item.icon"
|
10
|
-
:size="16"
|
11
|
-
class="mr-1"
|
12
|
-
/>
|
13
|
-
<span ref="imgContainer" />
|
14
|
-
</span>
|
15
|
-
|
16
6
|
<div
|
17
|
-
class="position-relative col-8 pa-0 d-flex align-center treeview-
|
7
|
+
class="position-relative col-8 pa-0 d-flex align-center vcs-treeview-leaf"
|
18
8
|
:title="$t(item.tooltip || item.title)"
|
19
9
|
>
|
20
|
-
<span
|
10
|
+
<span
|
11
|
+
v-if="item.icon"
|
12
|
+
>
|
13
|
+
<v-icon
|
14
|
+
v-if="isStringIcon"
|
15
|
+
v-text="item.icon"
|
16
|
+
:size="16"
|
17
|
+
class="mr-1"
|
18
|
+
/>
|
19
|
+
<ImageElementInjector :element="item.icon" v-else />
|
20
|
+
</span>
|
21
|
+
<span class="vcs-treeview-item-title">{{ $t(item.title) }}</span>
|
21
22
|
</div>
|
22
23
|
<VcsActionButtonList
|
23
24
|
v-if="item.actions.length > 0"
|
@@ -31,7 +32,7 @@
|
|
31
32
|
</div>
|
32
33
|
</template>
|
33
34
|
<style lang="css" scoped>
|
34
|
-
.treeview-
|
35
|
+
.vcs-treeview-leaf .vcs-treeview-item-title{
|
35
36
|
white-space: nowrap;
|
36
37
|
overflow: hidden;
|
37
38
|
text-overflow: ellipsis;
|
@@ -39,22 +40,10 @@
|
|
39
40
|
</style>
|
40
41
|
|
41
42
|
<script>
|
42
|
-
import
|
43
|
-
{
|
44
|
-
computed,
|
45
|
-
onMounted,
|
46
|
-
ref,
|
47
|
-
} from 'vue';
|
48
|
-
|
43
|
+
import { computed } from 'vue';
|
49
44
|
import { VIcon } from 'vuetify/lib';
|
50
45
|
import VcsActionButtonList from '../buttons/VcsActionButtonList.vue';
|
51
|
-
|
52
|
-
|
53
|
-
const iconTypes = {
|
54
|
-
image: 'HTMLImageElement',
|
55
|
-
canvas: 'HTMLCanvasElement',
|
56
|
-
string: 'StringIcon',
|
57
|
-
};
|
46
|
+
import ImageElementInjector from '../imageElementInjector.vue';
|
58
47
|
|
59
48
|
/**
|
60
49
|
* @description
|
@@ -66,6 +55,7 @@
|
|
66
55
|
components: {
|
67
56
|
VcsActionButtonList,
|
68
57
|
VIcon,
|
58
|
+
ImageElementInjector,
|
69
59
|
},
|
70
60
|
props: {
|
71
61
|
item: {
|
@@ -74,32 +64,10 @@
|
|
74
64
|
},
|
75
65
|
},
|
76
66
|
setup(props) {
|
77
|
-
const iconType = ref();
|
78
|
-
const imgContainer = ref();
|
79
|
-
|
80
67
|
const leaf = computed(() => props.item?.children?.length === 0);
|
81
68
|
|
82
|
-
onMounted(() => { // TODO make icon reactive
|
83
|
-
const { icon } = props.item;
|
84
|
-
if (icon) {
|
85
|
-
if (icon instanceof HTMLImageElement) {
|
86
|
-
imgContainer.value.appendChild(icon);
|
87
|
-
iconType.value = iconTypes.image;
|
88
|
-
}
|
89
|
-
if (icon instanceof HTMLCanvasElement) {
|
90
|
-
imgContainer.value.appendChild(icon);
|
91
|
-
iconType.value = iconTypes.canvas;
|
92
|
-
}
|
93
|
-
if (typeof icon === 'string') {
|
94
|
-
iconType.value = iconTypes.string;
|
95
|
-
}
|
96
|
-
}
|
97
|
-
});
|
98
|
-
|
99
69
|
return {
|
100
|
-
|
101
|
-
iconType,
|
102
|
-
imgContainer,
|
70
|
+
isStringIcon: computed(() => typeof props.item.icon === 'string'),
|
103
71
|
leaf,
|
104
72
|
};
|
105
73
|
},
|
@@ -17,7 +17,7 @@
|
|
17
17
|
class="searchbar outlined rounded-xl align-center d-flex justify-center white pa-1 pl-6"
|
18
18
|
:placeholder="$t(placeholder)"
|
19
19
|
:value="value"
|
20
|
-
|
20
|
+
v-on="$listeners"
|
21
21
|
clearable
|
22
22
|
/>
|
23
23
|
</slot>
|
@@ -104,13 +104,8 @@
|
|
104
104
|
|
105
105
|
|
106
106
|
<script>
|
107
|
-
import { onMounted, onUnmounted } from 'vue';
|
108
|
-
|
109
|
-
import { Subject } from 'rxjs';
|
110
|
-
import { debounceTime } from 'rxjs/operators';
|
111
107
|
import { VIcon, VTextField } from 'vuetify/lib';
|
112
108
|
|
113
|
-
|
114
109
|
/**
|
115
110
|
* @description Stylized wrapper around vuetify divider
|
116
111
|
* @vue-prop {number} height - Height of the component.
|
@@ -140,22 +135,5 @@
|
|
140
135
|
default: false,
|
141
136
|
},
|
142
137
|
},
|
143
|
-
setup(props, context) {
|
144
|
-
const sub = new Subject();
|
145
|
-
onMounted(() => {
|
146
|
-
sub.pipe(debounceTime(330)).subscribe(
|
147
|
-
(value) => {
|
148
|
-
context.emit('input', value);
|
149
|
-
},
|
150
|
-
);
|
151
|
-
});
|
152
|
-
onUnmounted(() => sub.unsubscribe());
|
153
|
-
|
154
|
-
return {
|
155
|
-
handleInput: (val) => {
|
156
|
-
sub.next(val);
|
157
|
-
},
|
158
|
-
};
|
159
|
-
},
|
160
138
|
};
|
161
139
|
</script>
|
@@ -90,7 +90,16 @@
|
|
90
90
|
<script>
|
91
91
|
import { getCurrentInstance, ref, computed } from 'vue';
|
92
92
|
import {
|
93
|
-
|
93
|
+
VCard,
|
94
|
+
VDivider,
|
95
|
+
VContainer,
|
96
|
+
VDataTable,
|
97
|
+
VList,
|
98
|
+
VListItem,
|
99
|
+
VListItemTitle,
|
100
|
+
VMenu,
|
101
|
+
VIcon,
|
102
|
+
VRow,
|
94
103
|
} from 'vuetify/lib';
|
95
104
|
import VcsTreeviewSearchbar from '../lists/VcsTreeviewSearchbar.vue';
|
96
105
|
import VcsButton from '../buttons/VcsButton.vue';
|
@@ -140,10 +149,13 @@
|
|
140
149
|
components: {
|
141
150
|
VcsButton,
|
142
151
|
VcsTreeviewSearchbar,
|
152
|
+
VCard,
|
143
153
|
VDataTable,
|
144
154
|
VContainer,
|
155
|
+
VDivider,
|
145
156
|
VRow,
|
146
157
|
VMenu,
|
158
|
+
VIcon,
|
147
159
|
VList,
|
148
160
|
VListItem,
|
149
161
|
VListItemTitle,
|
@@ -198,6 +198,15 @@ class ContentTreeCollection extends IndexedCollection {
|
|
198
198
|
this._subTreeListeners = subTrees.map(subTree => this._createSubtreeActionButton(subTree));
|
199
199
|
}
|
200
200
|
|
201
|
+
/**
|
202
|
+
* Returns all managed subtrees. Entries are not persisted and will change, if the trees get recalculated.
|
203
|
+
* @type {import("vue").Ref<Map<string, TreeViewItem>>}
|
204
|
+
* @readonly
|
205
|
+
*/
|
206
|
+
get subTreeViewItems() {
|
207
|
+
return this._subTreeViewItems;
|
208
|
+
}
|
209
|
+
|
201
210
|
/**
|
202
211
|
* All ids of the currently managed subtrees. Ids are not persisted and will change if
|
203
212
|
* the trees get recalculated. The first ID is always the default tree. Other ids are subtree ids.
|
@@ -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=
|
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
|
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
|
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(
|
20
|
+
{{ $t(balloonTitle) }}
|
21
21
|
</v-list-item-title>
|
22
|
-
<v-list-item-subtitle v-if="
|
23
|
-
{{ $t(
|
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,
|
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}
|
72
|
-
* @vue-prop {string}
|
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
|
-
|
99
|
+
balloonTitle: {
|
98
100
|
type: String,
|
99
101
|
required: true,
|
100
102
|
},
|
101
|
-
|
103
|
+
balloonSubtitle: {
|
102
104
|
type: String,
|
103
105
|
required: true,
|
104
106
|
},
|
@@ -148,6 +150,9 @@
|
|
148
150
|
</script>
|
149
151
|
|
150
152
|
<style lang="scss">
|
153
|
+
.balloon {
|
154
|
+
z-index: 0 !important;
|
155
|
+
}
|
151
156
|
.balloon hr:first-child {
|
152
157
|
display: none;
|
153
158
|
}
|
@@ -4,9 +4,8 @@ import { Cartographic, Entity, Math as CesiumMath } from '@vcmap/cesium';
|
|
4
4
|
import { Projection } from '@vcmap/core';
|
5
5
|
import { check } from '@vcsuite/check';
|
6
6
|
import AbstractFeatureInfoView from './abstractFeatureInfoView.js';
|
7
|
-
import {
|
7
|
+
import { WindowSlot } from '../manager/window/windowManager.js';
|
8
8
|
import BalloonComponent from './BalloonComponent.vue';
|
9
|
-
import { balloonOffset } from './balloonHelper.js';
|
10
9
|
|
11
10
|
/**
|
12
11
|
* derive value from attributes
|
@@ -26,14 +25,14 @@ export function extractNestedKey(key, attrs, defaultValue = null) {
|
|
26
25
|
|
27
26
|
/**
|
28
27
|
* @typedef {FeatureInfoViewOptions} BalloonFeatureInfoViewOptions
|
29
|
-
* @property {string} [
|
30
|
-
* @property {string} [
|
28
|
+
* @property {string} [balloonTitle] - optional title to overwrite default (layerName). Can be attribute key (nested key using '.'), i18n key or text
|
29
|
+
* @property {string} [balloonSubtitle] - optional window title to overwrite default (featureId). Can be attribute key (nested key using '.'), i18n key or text
|
31
30
|
*/
|
32
31
|
|
33
32
|
/**
|
34
33
|
* @typedef {FeatureInfoProps} BalloonFeatureInfoViewProps
|
35
|
-
* @property {string}
|
36
|
-
* @property {string}
|
34
|
+
* @property {string} balloonTitle
|
35
|
+
* @property {string} balloonSubtitle
|
37
36
|
* @property {import("ol/coordinate").Coordinate} position
|
38
37
|
*/
|
39
38
|
|
@@ -87,12 +86,12 @@ class BalloonFeatureInfoView extends AbstractFeatureInfoView {
|
|
87
86
|
/**
|
88
87
|
* @type {string}
|
89
88
|
*/
|
90
|
-
this.
|
89
|
+
this.balloonTitle = options.balloonTitle;
|
91
90
|
|
92
91
|
/**
|
93
92
|
* @type {string}
|
94
93
|
*/
|
95
|
-
this.
|
94
|
+
this.balloonSubtitle = options.balloonSubtitle;
|
96
95
|
}
|
97
96
|
|
98
97
|
/**
|
@@ -105,11 +104,11 @@ class BalloonFeatureInfoView extends AbstractFeatureInfoView {
|
|
105
104
|
return {
|
106
105
|
...properties,
|
107
106
|
position: featureInfo.position ?? getPositionFromFeature(featureInfo.feature),
|
108
|
-
|
109
|
-
extractNestedKey(this.
|
107
|
+
balloonTitle: this.balloonTitle != null ?
|
108
|
+
extractNestedKey(this.balloonTitle, properties.attributes, this.balloonTitle) :
|
110
109
|
properties.layerProperties.title,
|
111
|
-
|
112
|
-
extractNestedKey(this.
|
110
|
+
balloonSubtitle: this.balloonSubtitle != null ?
|
111
|
+
extractNestedKey(this.balloonSubtitle, properties.attributes, this.balloonSubtitle) :
|
113
112
|
properties.featureId,
|
114
113
|
};
|
115
114
|
}
|
@@ -124,12 +123,7 @@ class BalloonFeatureInfoView extends AbstractFeatureInfoView {
|
|
124
123
|
options.state.hideHeader = true;
|
125
124
|
options.state.classes = ['balloon'];
|
126
125
|
options.slot = WindowSlot.DETACHED;
|
127
|
-
|
128
|
-
(featureInfo.windowPosition?.[0] ?? 0) - balloonOffset.x, // if we do not have a windowPosition, let the next render handle it
|
129
|
-
(featureInfo.windowPosition?.[1] ?? 0) - balloonOffset.y,
|
130
|
-
null,
|
131
|
-
WindowAlignment.BOTTOM_LEFT,
|
132
|
-
);
|
126
|
+
// windowPosition is handled by next render
|
133
127
|
return options;
|
134
128
|
}
|
135
129
|
|
@@ -138,11 +132,11 @@ class BalloonFeatureInfoView extends AbstractFeatureInfoView {
|
|
138
132
|
*/
|
139
133
|
toJSON() {
|
140
134
|
const config = super.toJSON();
|
141
|
-
if (this.
|
142
|
-
config.
|
135
|
+
if (this.balloonTitle) {
|
136
|
+
config.balloonTitle = this.balloonTitle;
|
143
137
|
}
|
144
|
-
if (this.
|
145
|
-
config.
|
138
|
+
if (this.balloonSubtitle) {
|
139
|
+
config.balloonSubtitle = this.balloonSubtitle;
|
146
140
|
}
|
147
141
|
return config;
|
148
142
|
}
|
@@ -4,7 +4,7 @@ import { unByKey } from 'ol/Observable.js';
|
|
4
4
|
import {
|
5
5
|
getWindowPositionOptionsFromMapEvent,
|
6
6
|
WindowAlignment,
|
7
|
-
} from '../manager/window/
|
7
|
+
} from '../manager/window/windowHelper.js';
|
8
8
|
|
9
9
|
/**
|
10
10
|
* balloon offset from location or click position in pixel
|
@@ -63,8 +63,9 @@ export async function getBalloonPosition(app, position) {
|
|
63
63
|
* @param {WindowManager} windowManager
|
64
64
|
* @param {string} id - windowId of balloon
|
65
65
|
* @param {import("@vcmap/cesium").Cartesian2|undefined} windowPosition
|
66
|
+
* @param {HTMLElement} target - the map's target { @link @import("@vcmap/core").MapCollection }
|
66
67
|
*/
|
67
|
-
export function setBalloonPosition(windowManager, id, windowPosition) {
|
68
|
+
export function setBalloonPosition(windowManager, id, windowPosition, target) {
|
68
69
|
if (!windowPosition) {
|
69
70
|
return;
|
70
71
|
}
|
@@ -72,6 +73,7 @@ export function setBalloonPosition(windowManager, id, windowPosition) {
|
|
72
73
|
id,
|
73
74
|
getWindowPositionOptionsFromMapEvent(
|
74
75
|
new Cartesian2(windowPosition.x - balloonOffset.x, windowPosition.y - balloonOffset.y),
|
76
|
+
target,
|
75
77
|
WindowAlignment.BOTTOM_LEFT,
|
76
78
|
),
|
77
79
|
);
|
@@ -99,13 +101,27 @@ export async function setupBalloonPositionListener(vcsApp, windowId, clickedPosi
|
|
99
101
|
|
100
102
|
const map = app.maps.activeMap;
|
101
103
|
if (map instanceof CesiumMap) {
|
104
|
+
if (!position[2]) {
|
105
|
+
const [position3D] = await map.getHeightFromTerrain([position]);
|
106
|
+
position[2] = position3D[2];
|
107
|
+
}
|
102
108
|
const wgs84Position = Projection.mercatorToWgs84(position);
|
103
109
|
const cartesian = Cartographic.toCartesian(Cartographic.fromDegrees(...wgs84Position));
|
104
110
|
listeners.push(map.getScene().postRender.addEventListener((scene) => {
|
105
|
-
setBalloonPosition(
|
111
|
+
setBalloonPosition(
|
112
|
+
app.windowManager,
|
113
|
+
windowId,
|
114
|
+
getBalloonPositionCesium(scene, cartesian),
|
115
|
+
app.maps.target,
|
116
|
+
);
|
106
117
|
}));
|
107
118
|
} else if (map instanceof OpenlayersMap) {
|
108
|
-
const handler = () => setBalloonPosition(
|
119
|
+
const handler = () => setBalloonPosition(
|
120
|
+
app.windowManager,
|
121
|
+
windowId,
|
122
|
+
getBalloonPositionOL(map.olMap, position),
|
123
|
+
app.maps.target,
|
124
|
+
);
|
109
125
|
const key = map.olMap.on(
|
110
126
|
'postrender',
|
111
127
|
handler,
|
@@ -117,7 +133,12 @@ export async function setupBalloonPositionListener(vcsApp, windowId, clickedPosi
|
|
117
133
|
position,
|
118
134
|
);
|
119
135
|
listeners.push(map.imageChanged.addEventListener(setup.bind(null, app, windowId, position)));
|
120
|
-
const handler = () => setBalloonPosition(
|
136
|
+
const handler = () => setBalloonPosition(
|
137
|
+
app.windowManager,
|
138
|
+
windowId,
|
139
|
+
getBalloonPositionOL(map.olMap, coords),
|
140
|
+
app.maps.target,
|
141
|
+
);
|
121
142
|
const key = map.olMap.on(
|
122
143
|
'postrender',
|
123
144
|
handler,
|
@@ -25,7 +25,6 @@ import {
|
|
25
25
|
} from '@vcmap/cesium';
|
26
26
|
import { Feature } from 'ol';
|
27
27
|
import { check, checkMaybe } from '@vcsuite/check';
|
28
|
-
import { v4 as uuidv4 } from 'uuid';
|
29
28
|
|
30
29
|
import { vcsAppSymbol } from '../pluginHelper.js';
|
31
30
|
import FeatureInfoInteraction from './featureInfoInteraction.js';
|
@@ -231,6 +230,11 @@ class FeatureInfo {
|
|
231
230
|
* @private
|
232
231
|
*/
|
233
232
|
this._selectedFeature = null;
|
233
|
+
/**
|
234
|
+
* @type {string|null}
|
235
|
+
* @private
|
236
|
+
*/
|
237
|
+
this._selectedFeatureId = null;
|
234
238
|
/**
|
235
239
|
* @type {Array<function():void>}
|
236
240
|
* @private
|
@@ -299,6 +303,12 @@ class FeatureInfo {
|
|
299
303
|
*/
|
300
304
|
get selectedFeature() { return this._selectedFeature; }
|
301
305
|
|
306
|
+
/**
|
307
|
+
* @type {null|string}
|
308
|
+
* @readonly
|
309
|
+
*/
|
310
|
+
get selectedFeatureId() { return this._selectedFeatureId; }
|
311
|
+
|
302
312
|
/**
|
303
313
|
* The window id of the current features FeatureInfoView window
|
304
314
|
* @type {string|null}
|
@@ -391,7 +401,7 @@ class FeatureInfo {
|
|
391
401
|
});
|
392
402
|
this._clearHighlightingCb = () => layer.featureVisibility.unHighlight([featureId]);
|
393
403
|
}
|
394
|
-
this._windowId =
|
404
|
+
this._windowId = usedFeatureInfoView.className; // use className for a type based position caching
|
395
405
|
this._app.windowManager.add(
|
396
406
|
{
|
397
407
|
id: this._windowId,
|
@@ -404,6 +414,7 @@ class FeatureInfo {
|
|
404
414
|
);
|
405
415
|
|
406
416
|
this._selectedFeature = feature;
|
417
|
+
this._selectedFeatureId = feature.getId();
|
407
418
|
this._featureChanged.raiseEvent(this._selectedFeature);
|
408
419
|
} else {
|
409
420
|
this.clear();
|
@@ -436,6 +447,7 @@ class FeatureInfo {
|
|
436
447
|
this._clearInternal();
|
437
448
|
if (this._selectedFeature) {
|
438
449
|
this._selectedFeature = null;
|
450
|
+
this._selectedFeatureId = null;
|
439
451
|
this._featureChanged.raiseEvent(this._selectedFeature);
|
440
452
|
}
|
441
453
|
}
|
@@ -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.
|
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
@@ -41,9 +41,15 @@ const messages = {
|
|
41
41
|
pitchTooltip: 'Kamera pitch: {0}°',
|
42
42
|
overviewMapTooltip: 'Übersichtskarte',
|
43
43
|
},
|
44
|
-
|
44
|
+
categoryManager: {
|
45
45
|
title: 'Komponenten',
|
46
46
|
tooltip: 'Komponenten',
|
47
|
+
more: 'Weitere anzeigen...',
|
48
|
+
empty: 'Es gibt noch keine Einträge.',
|
49
|
+
},
|
50
|
+
components: {
|
51
|
+
pin: 'Fenster andocken.',
|
52
|
+
close: 'Fenster schließen.',
|
47
53
|
vcsFormSection: {
|
48
54
|
help: 'Hilfe anzeigen.',
|
49
55
|
},
|
@@ -91,6 +97,12 @@ const messages = {
|
|
91
97
|
tooltip: 'Öffne Attribution Fenster',
|
92
98
|
},
|
93
99
|
},
|
100
|
+
notification: {
|
101
|
+
error: 'Fehler',
|
102
|
+
warning: 'Warnung',
|
103
|
+
information: 'Information',
|
104
|
+
success: 'Erfolg',
|
105
|
+
},
|
94
106
|
};
|
95
107
|
|
96
108
|
export default messages;
|
package/src/i18n/en.js
CHANGED
@@ -41,9 +41,15 @@ const messages = {
|
|
41
41
|
pitchTooltip: 'Camera pitch: {0}°',
|
42
42
|
overviewMapTooltip: 'Overview Map',
|
43
43
|
},
|
44
|
-
|
44
|
+
categoryManager: {
|
45
45
|
title: 'Components',
|
46
46
|
tooltip: 'Components',
|
47
|
+
more: 'Show more...',
|
48
|
+
empty: 'There are no entries yet.',
|
49
|
+
},
|
50
|
+
components: {
|
51
|
+
pin: 'Pin window.',
|
52
|
+
close: 'Close window.',
|
47
53
|
vcsFormSection: {
|
48
54
|
help: 'Show help.',
|
49
55
|
},
|
@@ -91,6 +97,12 @@ const messages = {
|
|
91
97
|
tooltip: 'Open Attributions Window',
|
92
98
|
},
|
93
99
|
},
|
100
|
+
notification: {
|
101
|
+
error: 'Error',
|
102
|
+
warning: 'Warning',
|
103
|
+
information: 'Information',
|
104
|
+
success: 'Success',
|
105
|
+
},
|
94
106
|
};
|
95
107
|
|
96
108
|
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); };
|