@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
@@ -8,10 +8,10 @@ import { vcsAppSymbol } from '../../pluginHelper.js';
|
|
8
8
|
/**
|
9
9
|
* @readonly
|
10
10
|
* @enum {string}
|
11
|
-
* @property {string} STATIC
|
12
|
-
* @property {string} DYNAMIC_LEFT
|
13
|
-
* @property {string} DYNAMIC_RIGHT
|
14
|
-
* @property {string} DETACHED
|
11
|
+
* @property {string} STATIC - Static windows cannot be moved and will be positioned top-left.
|
12
|
+
* @property {string} DYNAMIC_LEFT - Positioned top-left, if no static window is present. Can be moved by user interaction.
|
13
|
+
* @property {string} DYNAMIC_RIGHT - Positioned top-right. Can be moved by user interaction.
|
14
|
+
* @property {string} DETACHED - Positioned at initial provided position. Can be moved by user interaction.
|
15
15
|
*/
|
16
16
|
export const WindowSlot = {
|
17
17
|
STATIC: 'static',
|
@@ -22,38 +22,47 @@ export const WindowSlot = {
|
|
22
22
|
|
23
23
|
|
24
24
|
/**
|
25
|
-
* @typedef WindowPositionOptions
|
25
|
+
* @typedef {Object} WindowPositionOptions
|
26
26
|
* @property {string|number|undefined} left Can be a css position string (e.g. '320px' or '50%') number values are treated as `px` values
|
27
27
|
* @property {string|number|undefined} top Can be a css position string (e.g. '320px' or '50%') number values are treated as `px` values
|
28
28
|
* @property {string|number|undefined} right Can be a css position string (e.g. '320px' or '50%') number values are treated as `px` values
|
29
29
|
* @property {string|number|undefined} bottom Can be a css position string (e.g. '320px' or '50%') number values are treated as `px` values
|
30
|
-
* @property {string|number|undefined} width Can be a css position string (e.g. '320px') number values are treated as `px` values
|
31
|
-
* @property {string|number|undefined} height Can be
|
30
|
+
* @property {string|number|undefined} width Can be a css position string (e.g. '320px' or '50%') number values are treated as `px` values
|
31
|
+
* @property {string|number|undefined} height Can be a css position string (e.g. '320px' or '50%') number values are treated as `px` values
|
32
|
+
* @property {string|number|undefined} maxHeight Can be a css position string (e.g. '320px' or '50%') number values are treated as `px` values
|
33
|
+
* @property {string|number|undefined} maxWidth Can be a css position string (e.g. '320px' or '50%') number values are treated as `px` values
|
34
|
+
* @property {string|number|undefined} minHeight Can be a css position string (e.g. '320px' or '50%') number values are treated as `px` values
|
35
|
+
* @property {string|number|undefined} minWidth Can be a css position string (e.g. '320px' or '50%') number values are treated as `px` values
|
32
36
|
*/
|
33
37
|
|
34
38
|
/**
|
35
|
-
* @typedef WindowPosition
|
36
|
-
* @property {string} left -
|
37
|
-
* @property {string} top -
|
38
|
-
* @property {string} right -
|
39
|
-
* @property {string} bottom -
|
40
|
-
* @property {string} width
|
41
|
-
* @property {string} height
|
39
|
+
* @typedef {Object} WindowPosition
|
40
|
+
* @property {string} left - The left CSS property participates in specifying the horizontal position of a window.
|
41
|
+
* @property {string} top - The top CSS property participates in specifying the vertical position of a window.
|
42
|
+
* @property {string} right - The right CSS property participates in specifying the horizontal position of a window.
|
43
|
+
* @property {string} bottom - The bottom CSS property participates in specifying the vertical position of a window.
|
44
|
+
* @property {string} width - The width CSS property sets an element's width.
|
45
|
+
* @property {string} height - The height CSS property sets an element's height.
|
46
|
+
* @property {string} [maxHeight] - It prevents the used value of the height property from becoming larger than the value specified for max-height. (max is target height, will be automatically updated)
|
47
|
+
* @property {string} [maxWidth] - It prevents the used value of the width property from becoming larger than the value specified by max-width. (max is target width, will be automatically updated)
|
48
|
+
* @property {string} [minHeight] - It prevents the used value of the height property from becoming smaller than the value specified for min-height.
|
49
|
+
* @property {string} [minWidth] - It prevents the used value of the width property from becoming smaller than the value specified for min-width.
|
42
50
|
*/
|
43
51
|
|
44
52
|
/**
|
45
53
|
* @readonly
|
46
|
-
* @enum {
|
47
|
-
* @property {
|
48
|
-
* @property {
|
49
|
-
* @property {
|
50
|
-
* @property {
|
54
|
+
* @enum {WindowPosition}
|
55
|
+
* @property {WindowPosition} TOP_LEFT position of the DYNAMIC_LEFT or STATIC Slot
|
56
|
+
* @property {WindowPosition} TOP_LEFT2 position of the DYNAMIC_LEFT Slot if a STATIC is present
|
57
|
+
* @property {WindowPosition} TOP_RIGHT position of the DYNAMIC_RIGHT Slot
|
58
|
+
* @property {WindowPosition} DETACHED default position of DETACHED Windows if no position is given
|
51
59
|
* @private
|
52
60
|
*/
|
53
61
|
export const WindowPositions = {
|
54
62
|
TOP_LEFT: {
|
55
63
|
left: '0px',
|
56
64
|
top: '0px',
|
65
|
+
maxWidth: '320px',
|
57
66
|
},
|
58
67
|
TOP_LEFT2: {
|
59
68
|
left: '320px',
|
@@ -62,6 +71,7 @@ export const WindowPositions = {
|
|
62
71
|
TOP_RIGHT: {
|
63
72
|
right: '0px',
|
64
73
|
top: '0px',
|
74
|
+
maxHeight: '70%',
|
65
75
|
},
|
66
76
|
DETACHED: {
|
67
77
|
left: '200px',
|
@@ -69,15 +79,36 @@ export const WindowPositions = {
|
|
69
79
|
},
|
70
80
|
};
|
71
81
|
|
82
|
+
/**
|
83
|
+
* Return true, if all values of pos1 match with the corresponding values of pos2
|
84
|
+
* @param {WindowPosition} pos1
|
85
|
+
* @param {WindowPosition} pos2
|
86
|
+
* @returns {boolean}
|
87
|
+
*/
|
88
|
+
export function compareWindowPositions(pos1, pos2) {
|
89
|
+
return !(Object.keys(pos1).some(key => pos1[key] !== pos2[key]));
|
90
|
+
}
|
91
|
+
|
92
|
+
/**
|
93
|
+
* Returns true, if the provided position is a slot position
|
94
|
+
* @param {WindowPosition} windowPosition
|
95
|
+
* @returns {boolean}
|
96
|
+
*/
|
97
|
+
export function isSlotPosition(windowPosition) {
|
98
|
+
return [WindowPositions.TOP_LEFT, WindowPositions.TOP_LEFT2, WindowPositions.TOP_RIGHT]
|
99
|
+
.some(s => compareWindowPositions(s, windowPosition));
|
100
|
+
}
|
101
|
+
|
72
102
|
/**
|
73
103
|
* @typedef WindowComponentOptions
|
74
104
|
* @property {string} [id] Optional ID, If not provided an uuid will be generated.
|
75
105
|
* @property {import("vue").Component} component Main Component which is shown below the header.
|
76
106
|
* @property {import("vue").Component} [headerComponent] Replaces the Header Component.
|
77
|
-
* @property {WindowPositionOptions} [position] Will be ignored if WindowSlot !== DETACHED, can be given otherwise or default will be used
|
78
107
|
* @property {WindowState} [state]
|
108
|
+
* @property {WindowPositionOptions} [position] Will be ignored if WindowSlot !== DETACHED, can be given otherwise or default will be used
|
79
109
|
* @property {WindowSlot} [slot] If WindowSlot is not detached the position will be ignored
|
80
110
|
* @property {Object} [props]
|
111
|
+
* @property {Object} [provides]
|
81
112
|
*/
|
82
113
|
|
83
114
|
/**
|
@@ -85,9 +116,14 @@ export const WindowPositions = {
|
|
85
116
|
* @property {string} id
|
86
117
|
* @property {string|vcsAppSymbol} owner Owner of the window, set by windowManager on add
|
87
118
|
* @property {boolean} [hideHeader] be used to not show the header.
|
119
|
+
* @property {boolean} [hidePin] be used to not show the pin button.
|
88
120
|
* @property {string} [headerTitle]
|
89
121
|
* @property {string} [headerIcon]
|
90
|
-
* @property {
|
122
|
+
* @property {Array<VcsAction>} [headerActions]
|
123
|
+
* @property {number} [headerActionsOverflowCount]
|
124
|
+
* @property {string} [infoUrl] An optional url referencing help or further information on the window's content.
|
125
|
+
* @property {boolean} [dockable] Auto derived from hidePin, current slot, current position and initial position.
|
126
|
+
* @property {Object<string, string>} [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
127
|
* @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
128
|
*/
|
93
129
|
|
@@ -96,17 +132,20 @@ export const WindowPositions = {
|
|
96
132
|
* @property {string} id
|
97
133
|
* @property {import("vue").Component} component
|
98
134
|
* @property {import("vue").Component} [headerComponent]
|
99
|
-
* @property {WindowPosition} position
|
100
135
|
* @property {WindowState} state
|
101
|
-
* @property {
|
136
|
+
* @property {WindowPosition} position
|
137
|
+
* @property {WindowPositionOptions} initialPositionOptions
|
138
|
+
* @property {import("vue").Ref<WindowSlot>} slot
|
139
|
+
* @property {WindowSlot} initialSlot
|
102
140
|
* @property {Object} props
|
141
|
+
* @property {Object} provides
|
103
142
|
*/
|
104
143
|
|
105
144
|
/**
|
106
145
|
* @param {string|number|undefined} pos
|
107
146
|
* @returns {string|undefined}
|
108
147
|
*/
|
109
|
-
function
|
148
|
+
export function posToPixel(pos) {
|
110
149
|
if (typeof pos === 'number') {
|
111
150
|
return `${pos}px`;
|
112
151
|
}
|
@@ -114,17 +153,18 @@ function parsePosition(pos) {
|
|
114
153
|
}
|
115
154
|
|
116
155
|
/**
|
156
|
+
* Returns CSS position string properties
|
117
157
|
* @param {WindowPositionOptions} windowPositionOptions
|
118
158
|
* @param {WindowPosition=} windowPosition
|
119
159
|
* @returns {WindowPosition}
|
120
160
|
*/
|
121
161
|
export function windowPositionFromOptions(windowPositionOptions, windowPosition = {}) {
|
122
|
-
let left =
|
123
|
-
const right =
|
124
|
-
let top =
|
125
|
-
const bottom =
|
126
|
-
let width =
|
127
|
-
let height =
|
162
|
+
let left = posToPixel(windowPositionOptions.left) || 'unset';
|
163
|
+
const right = posToPixel(windowPositionOptions.right) || 'unset';
|
164
|
+
let top = posToPixel(windowPositionOptions.top) || 'unset';
|
165
|
+
const bottom = posToPixel(windowPositionOptions.bottom) || 'unset';
|
166
|
+
let width = posToPixel(windowPositionOptions.width) || 'auto';
|
167
|
+
let height = posToPixel(windowPositionOptions.height) || 'auto';
|
128
168
|
if (left !== 'unset' && right !== 'unset') {
|
129
169
|
width = 'auto'; // left + right takes precedence over configured width
|
130
170
|
} else if (width === 'auto') {
|
@@ -147,127 +187,37 @@ export function windowPositionFromOptions(windowPositionOptions, windowPosition
|
|
147
187
|
width,
|
148
188
|
height,
|
149
189
|
};
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
/**
|
154
|
-
* @enum {number}
|
155
|
-
* @property {number} TOP_LEFT
|
156
|
-
* @property {number} TOP_RIGHT
|
157
|
-
* @property {number} BOTTOM_LEFT
|
158
|
-
* @property {number} BOTTOM_RIGHT
|
159
|
-
*/
|
160
|
-
export const WindowAlignment = {
|
161
|
-
TOP_LEFT: 1,
|
162
|
-
TOP_RIGHT: 2,
|
163
|
-
BOTTOM_LEFT: 3,
|
164
|
-
BOTTOM_RIGHT: 4,
|
165
|
-
};
|
166
|
-
|
167
|
-
/**
|
168
|
-
* @returns {HTMLElement|null}
|
169
|
-
*/
|
170
|
-
function getActiveMapElement() {
|
171
|
-
const mapElements = document.getElementsByClassName('mapElement');
|
172
|
-
for (let i = 0; i < mapElements.length; i++) {
|
173
|
-
const element = mapElements.item(i);
|
174
|
-
if (element.style.display !== 'none') {
|
175
|
-
return element;
|
176
|
-
}
|
190
|
+
if (windowPositionOptions.maxWidth) {
|
191
|
+
result.maxWidth = posToPixel(windowPositionOptions.maxWidth);
|
177
192
|
}
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
/**
|
182
|
-
* WindowPositionOptions from client position relative to a HTMLElement
|
183
|
-
* @param {number} x - client pixel position
|
184
|
-
* @param {number} y - client pixel position
|
185
|
-
* @param {HTMLElement} [element='mapElement'] - the element. if none is provided, the currently active mapElement will be taken
|
186
|
-
* @param {WindowAlignment} [alignment=WindowAlignment.TOP_LEFT]
|
187
|
-
* @returns {WindowPositionOptions}
|
188
|
-
*/
|
189
|
-
export function getWindowPositionOptions(x, y, element, alignment = WindowAlignment.TOP_LEFT) {
|
190
|
-
const mapElement = element ?? getActiveMapElement();
|
191
|
-
if (!mapElement) {
|
192
|
-
return { left: x, top: y };
|
193
|
-
}
|
194
|
-
|
195
|
-
const { left, top, width, height } = mapElement.getBoundingClientRect();
|
196
|
-
if (alignment === WindowAlignment.TOP_LEFT) {
|
197
|
-
return { left: x - left, top: y - top };
|
198
|
-
} else if (alignment === WindowAlignment.TOP_RIGHT) {
|
199
|
-
return { right: (left + width) - x, top: y - top };
|
200
|
-
} else if (alignment === WindowAlignment.BOTTOM_LEFT) {
|
201
|
-
return { left: x - left, bottom: (height + top) - y };
|
193
|
+
if (windowPositionOptions.maxHeight) {
|
194
|
+
result.maxHeight = posToPixel(windowPositionOptions.maxHeight);
|
202
195
|
}
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
/**
|
207
|
-
* Get window position options based on a pixel in the map
|
208
|
-
* @param {import("@vcmap/cesium").Cartesian2} windowPosition - the window position, as retrieved from an InteractionEvent
|
209
|
-
* @param {WindowAlignment} [alignment]
|
210
|
-
* @returns {WindowPositionOptions}
|
211
|
-
*/
|
212
|
-
export function getWindowPositionOptionsFromMapEvent(windowPosition, alignment) {
|
213
|
-
const mapElement = getActiveMapElement();
|
214
|
-
if (!mapElement) {
|
215
|
-
return { left: windowPosition.x, top: windowPosition.y };
|
196
|
+
if (windowPositionOptions.minHeight) {
|
197
|
+
result.minHeight = posToPixel(windowPositionOptions.minHeight);
|
216
198
|
}
|
217
|
-
|
218
|
-
|
219
|
-
return getWindowPositionOptions(windowPosition.x + left, windowPosition.y + top, mapElement, alignment);
|
220
|
-
}
|
221
|
-
|
222
|
-
|
223
|
-
/**
|
224
|
-
* Fits a window aligned top left so it fits into the parent. this will change the alignment to be bottom or right depending
|
225
|
-
* on if the window would not fit into the parent.
|
226
|
-
* @param {number} x - client pixel position
|
227
|
-
* @param {number} y - client pixel position
|
228
|
-
* @param {number} width - window width to fit
|
229
|
-
* @param {number} height - window height to fit
|
230
|
-
* @param {HTMLElement} [element='mapElement'] - the element. if none is provided, the currently active mapElement will be taken
|
231
|
-
* @returns {WindowPositionOptions}
|
232
|
-
*/
|
233
|
-
export function getFittedWindowPositionOptions(x, y, width, height, element) {
|
234
|
-
const mapElement = element ?? getActiveMapElement();
|
235
|
-
if (!mapElement) {
|
236
|
-
return { left: x, top: y };
|
199
|
+
if (windowPositionOptions.minWidth) {
|
200
|
+
result.minWidth = posToPixel(windowPositionOptions.minWidth);
|
237
201
|
}
|
238
202
|
|
239
|
-
|
240
|
-
const bottom = y + height > parentHeight;
|
241
|
-
const right = x + width > parentWidth;
|
242
|
-
let alignment = WindowAlignment.TOP_LEFT;
|
243
|
-
if (bottom) {
|
244
|
-
if (right) {
|
245
|
-
alignment = WindowAlignment.BOTTOM_RIGHT;
|
246
|
-
} else {
|
247
|
-
alignment = WindowAlignment.BOTTOM_LEFT;
|
248
|
-
}
|
249
|
-
} else if (right) {
|
250
|
-
alignment = WindowAlignment.TOP_RIGHT;
|
251
|
-
}
|
252
|
-
return getWindowPositionOptions(x, y, mapElement, alignment);
|
203
|
+
return Object.assign(windowPosition, result);
|
253
204
|
}
|
254
205
|
|
255
206
|
/**
|
256
|
-
*
|
257
|
-
*
|
258
|
-
* @param {
|
259
|
-
* @param {number} width
|
260
|
-
* @param {number} height
|
261
|
-
* @returns {WindowPositionOptions}
|
207
|
+
* Sets a position on a component. Updates dockable state.
|
208
|
+
* @param {WindowComponent} windowComponent
|
209
|
+
* @param {WindowComponentOptions} windowPositionOptions
|
262
210
|
*/
|
263
|
-
|
264
|
-
const
|
265
|
-
|
266
|
-
|
211
|
+
function setWindowPosition(windowComponent, windowPositionOptions) {
|
212
|
+
const windowPosition = windowPositionFromOptions(windowPositionOptions, windowComponent.position);
|
213
|
+
// not one of the default Positions, so we also have to DETACH the windowState.
|
214
|
+
if (!isSlotPosition(windowPosition)) {
|
215
|
+
windowComponent.slot.value = WindowSlot.DETACHED;
|
267
216
|
}
|
268
|
-
|
269
|
-
const
|
270
|
-
|
217
|
+
// check dockable state
|
218
|
+
const initialWindowPosition = windowPositionFromOptions(windowComponent.initialPositionOptions);
|
219
|
+
windowComponent.state.dockable = windowComponent.slot.value === WindowSlot.DETACHED &&
|
220
|
+
!compareWindowPositions(windowPosition, initialWindowPosition);
|
271
221
|
}
|
272
222
|
|
273
223
|
/**
|
@@ -296,6 +246,11 @@ class WindowManager {
|
|
296
246
|
* @private
|
297
247
|
*/
|
298
248
|
this._windowComponents = new Map();
|
249
|
+
/**
|
250
|
+
* @type {Map<string, WindowPosition>}
|
251
|
+
* @private
|
252
|
+
*/
|
253
|
+
this._windowPositionsCache = new Map();
|
299
254
|
}
|
300
255
|
|
301
256
|
/**
|
@@ -323,6 +278,7 @@ class WindowManager {
|
|
323
278
|
check(id, String);
|
324
279
|
const windowComponent = this._windowComponents.get(id);
|
325
280
|
if (windowComponent) {
|
281
|
+
this._cachePosition(windowComponent);
|
326
282
|
const index = this.componentIds.indexOf(id);
|
327
283
|
this.componentIds.splice(index, 1);
|
328
284
|
this._windowComponents.delete(id);
|
@@ -338,14 +294,7 @@ class WindowManager {
|
|
338
294
|
setWindowPositionOptions(id, windowPositionOptions) {
|
339
295
|
const windowComponent = this._windowComponents.get(id);
|
340
296
|
if (windowComponent) {
|
341
|
-
|
342
|
-
windowPositionOptions === WindowPositions.TOP_LEFT2 ||
|
343
|
-
windowPositionOptions === WindowPositions.TOP_RIGHT;
|
344
|
-
// not one of the default Positions, so we also have to DETACH the windowState.
|
345
|
-
if (!isSlotPosition) {
|
346
|
-
windowComponent.slot.value = WindowSlot.DETACHED;
|
347
|
-
}
|
348
|
-
windowPositionFromOptions(windowPositionOptions, windowComponent.position);
|
297
|
+
setWindowPosition(windowComponent, windowPositionOptions);
|
349
298
|
}
|
350
299
|
}
|
351
300
|
|
@@ -414,10 +363,46 @@ class WindowManager {
|
|
414
363
|
}
|
415
364
|
}
|
416
365
|
|
366
|
+
/**
|
367
|
+
* @param {string} id
|
368
|
+
* @returns {WindowPosition|undefined}
|
369
|
+
*/
|
370
|
+
getCachedPosition(id) {
|
371
|
+
return this._windowPositionsCache.get(id);
|
372
|
+
}
|
373
|
+
|
374
|
+
/**
|
375
|
+
* Caches the position, if it differs from the initial position
|
376
|
+
* @param {WindowComponent} windowComponent
|
377
|
+
* @private
|
378
|
+
*/
|
379
|
+
_cachePosition(windowComponent) {
|
380
|
+
const initialWindowPosition = windowPositionFromOptions(windowComponent.initialPositionOptions);
|
381
|
+
if (!compareWindowPositions(initialWindowPosition, windowComponent.position)) {
|
382
|
+
this._windowPositionsCache.set(windowComponent.id, { ...windowComponent.position });
|
383
|
+
}
|
384
|
+
}
|
385
|
+
|
386
|
+
/**
|
387
|
+
* Returns true, if cached position was assigned.
|
388
|
+
* @param {WindowComponent} windowComponent
|
389
|
+
* @returns {boolean}
|
390
|
+
* @private
|
391
|
+
*/
|
392
|
+
_assignCachedPosition(windowComponent) {
|
393
|
+
if (this._windowPositionsCache.has(windowComponent.id)) {
|
394
|
+
const windowPosition = this.getCachedPosition(windowComponent.id);
|
395
|
+
setWindowPosition(windowComponent, windowPosition);
|
396
|
+
this._windowPositionsCache.delete(windowComponent.id);
|
397
|
+
return true;
|
398
|
+
}
|
399
|
+
return false;
|
400
|
+
}
|
401
|
+
|
417
402
|
/**
|
418
403
|
* adds a windowComponent to the WindowManager and renders the Window at the provided position/slot.
|
419
404
|
* 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
|
405
|
+
* The WindowState Object can also be used to change hideHeader, headerTitle, headerIcon, headerActions, styles and classes
|
421
406
|
* @param {WindowComponentOptions|WindowComponent} windowComponentOptions
|
422
407
|
* @param {string|symbol} owner pluginName or vcsAppSymbol
|
423
408
|
* @throws {Error} if a windowComponent with the same ID has already been added
|
@@ -448,15 +433,22 @@ class WindowManager {
|
|
448
433
|
id,
|
449
434
|
owner,
|
450
435
|
hideHeader: !!windowComponentOptions?.state?.hideHeader,
|
436
|
+
hidePin: !!windowComponentOptions?.state?.hidePin,
|
451
437
|
headerTitle: windowComponentOptions?.state?.headerTitle,
|
452
438
|
headerIcon: windowComponentOptions?.state?.headerIcon,
|
439
|
+
headerActions: windowComponentOptions?.state?.headerActions,
|
440
|
+
headerActionsOverflow: windowComponentOptions?.state?.headerActionsOverflow,
|
441
|
+
dockable: false,
|
442
|
+
infoUrl: windowComponentOptions?.state?.infoUrl,
|
453
443
|
classes,
|
454
444
|
styles,
|
455
445
|
});
|
456
446
|
|
457
447
|
const props = windowComponentOptions.props || {};
|
448
|
+
const provides = windowComponentOptions.provides || {};
|
458
449
|
|
459
450
|
const position = reactive(windowPosition);
|
451
|
+
const initialPosition = { ...windowPositionOptions };
|
460
452
|
/**
|
461
453
|
* @type {WindowComponent}
|
462
454
|
*/
|
@@ -476,14 +468,26 @@ class WindowManager {
|
|
476
468
|
get slot() {
|
477
469
|
return slotRef;
|
478
470
|
},
|
471
|
+
get initialSlot() {
|
472
|
+
return slot;
|
473
|
+
},
|
479
474
|
get position() {
|
480
475
|
return position;
|
481
476
|
},
|
477
|
+
get initialPositionOptions() {
|
478
|
+
return initialPosition;
|
479
|
+
},
|
482
480
|
get props() {
|
483
481
|
return props;
|
484
482
|
},
|
483
|
+
get provides() {
|
484
|
+
return provides;
|
485
|
+
},
|
485
486
|
};
|
486
|
-
this.
|
487
|
+
const cached = this._assignCachedPosition(windowComponent);
|
488
|
+
if (!cached) {
|
489
|
+
this._removeWindowAtSlot(slot);
|
490
|
+
}
|
487
491
|
this._windowComponents.set(id, windowComponent);
|
488
492
|
this.componentIds.push(id);
|
489
493
|
this._handleSlotsChanged(slot);
|
@@ -505,6 +509,24 @@ class WindowManager {
|
|
505
509
|
}
|
506
510
|
}
|
507
511
|
|
512
|
+
/**
|
513
|
+
* Docks a window by resetting detached to its initial slot.
|
514
|
+
* Updates position according to its initial slot or initial position.
|
515
|
+
* Clears any cached position for this window.
|
516
|
+
* @param {string} id
|
517
|
+
*/
|
518
|
+
pinWindow(id) {
|
519
|
+
const component = this.get(id);
|
520
|
+
if (!component?.state?.dockable) {
|
521
|
+
return;
|
522
|
+
}
|
523
|
+
this._removeWindowAtSlot(component.initialSlot);
|
524
|
+
component.slot.value = component.initialSlot;
|
525
|
+
const dockedPosition = this._getPositionOptionsForSlot(component.initialSlot, component.initialPositionOptions);
|
526
|
+
this.setWindowPositionOptions(id, dockedPosition);
|
527
|
+
this._windowPositionsCache.delete(id);
|
528
|
+
}
|
529
|
+
|
508
530
|
/**
|
509
531
|
* removes all windowComponents of a specific owner (plugin) and fires removed Events
|
510
532
|
* @param {string|vcsAppSymbol} owner
|
@@ -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.
|
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
|
-
|
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
|
555
|
-
|
556
|
-
|
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
|
|
@@ -0,0 +1,120 @@
|
|
1
|
+
import { ref, shallowRef } from 'vue';
|
2
|
+
import { v4 as uuidv4 } from 'uuid';
|
3
|
+
|
4
|
+
/**
|
5
|
+
* @typedef {Object} NotificationOptions
|
6
|
+
* @property {string} message
|
7
|
+
* @property {NotificationType} type
|
8
|
+
* @property {string} [title]
|
9
|
+
* @property {number} [timeout=5000]
|
10
|
+
*/
|
11
|
+
|
12
|
+
/**
|
13
|
+
* @typedef {Object} Notification
|
14
|
+
* @property {string} id
|
15
|
+
* @property {string} message
|
16
|
+
* @property {NotificationType} type
|
17
|
+
* @property {string} [title]
|
18
|
+
* @property {number} timeout
|
19
|
+
* @property {import("vue").Ref<boolean>} open
|
20
|
+
* @property {function():void} close
|
21
|
+
*/
|
22
|
+
|
23
|
+
/**
|
24
|
+
* @enum {string}
|
25
|
+
*/
|
26
|
+
export const NotificationType = {
|
27
|
+
ERROR: 'error',
|
28
|
+
WARNING: 'warning',
|
29
|
+
INFO: 'info',
|
30
|
+
SUCCESS: 'success',
|
31
|
+
};
|
32
|
+
|
33
|
+
/**
|
34
|
+
* @param {NotificationOptions} options
|
35
|
+
* @param {Notifier} notifier
|
36
|
+
* @returns {Notification}
|
37
|
+
*/
|
38
|
+
function createNotification(options, notifier) {
|
39
|
+
const {
|
40
|
+
type,
|
41
|
+
title,
|
42
|
+
message,
|
43
|
+
timeout,
|
44
|
+
} = options;
|
45
|
+
const id = uuidv4();
|
46
|
+
const open = ref(true);
|
47
|
+
|
48
|
+
return {
|
49
|
+
get id() { return id; },
|
50
|
+
get type() { return type; },
|
51
|
+
get title() { return title; },
|
52
|
+
get message() { return message; },
|
53
|
+
get timeout() { return timeout ?? 5000; },
|
54
|
+
get open() { return open; },
|
55
|
+
set open(value) {
|
56
|
+
open.value = value?.value ?? value; // when used as a v-model, this is set as a boolean
|
57
|
+
if (!open.value) {
|
58
|
+
this.close();
|
59
|
+
}
|
60
|
+
},
|
61
|
+
close() {
|
62
|
+
open.value = false;
|
63
|
+
setTimeout(() => {
|
64
|
+
notifier.remove(this);
|
65
|
+
}, 100);
|
66
|
+
},
|
67
|
+
};
|
68
|
+
}
|
69
|
+
|
70
|
+
/**
|
71
|
+
* API for adding snackbar notification to the VcsUiApp. This is simply a container and on its own will not render anything.
|
72
|
+
* Typically, you do not need to instantiate this yourself, but use the notifier on the {@see VcsUiApp}.
|
73
|
+
* @class
|
74
|
+
*/
|
75
|
+
class Notifier {
|
76
|
+
constructor() {
|
77
|
+
/**
|
78
|
+
* @type {import("vue").Ref<Array<Notification>>}
|
79
|
+
* @private
|
80
|
+
*/
|
81
|
+
this._notifications = shallowRef([]);
|
82
|
+
}
|
83
|
+
|
84
|
+
/**
|
85
|
+
* @type {import("vue").Ref<Array<Notification>>}
|
86
|
+
* @readonly
|
87
|
+
*/
|
88
|
+
get notifications() {
|
89
|
+
return this._notifications;
|
90
|
+
}
|
91
|
+
|
92
|
+
/**
|
93
|
+
* @param {NotificationOptions} notification
|
94
|
+
* @returns {Notification}
|
95
|
+
*/
|
96
|
+
add(notification) {
|
97
|
+
const note = createNotification(notification, this);
|
98
|
+
// use spread since push won't trigger updates
|
99
|
+
this._notifications.value = [...this._notifications.value, note];
|
100
|
+
return note;
|
101
|
+
}
|
102
|
+
|
103
|
+
/**
|
104
|
+
* @param {Notification} notification
|
105
|
+
*/
|
106
|
+
remove(notification) {
|
107
|
+
// reassign to trigger update
|
108
|
+
this._notifications.value = this._notifications.value.filter(n => n !== notification);
|
109
|
+
}
|
110
|
+
|
111
|
+
/**
|
112
|
+
* @param {Notification} notification
|
113
|
+
* @returns {boolean}
|
114
|
+
*/
|
115
|
+
has(notification) {
|
116
|
+
return this._notifications.value.includes(notification);
|
117
|
+
}
|
118
|
+
}
|
119
|
+
|
120
|
+
export default Notifier;
|