@vcmap/ui 5.0.0-rc.10 → 5.0.0-rc.11
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/README.md +11 -4
- package/build/build.js +0 -3
- package/build/buildHelpers.js +0 -1
- package/build/buildPreview.js +7 -0
- package/config/aerowest.config.json +13 -3
- package/config/base.config.json +89 -64
- package/config/codes.config.json +397 -0
- package/config/dev.config.json +169 -0
- package/config/graphFeatureInfo.config.json +100 -0
- package/config/www.config.json +1232 -0
- package/dist/assets/{cesium.eb5667.js → cesium.e67536.js} +0 -0
- package/dist/assets/cesium.js +1 -1
- package/dist/assets/core.ebf665.js +4 -0
- package/dist/assets/core.js +1 -1
- package/dist/assets/{index.4ccd4433.js → index.9b213929.js} +1 -1
- package/dist/assets/{ol.ef03b1.js → ol.8bbd50.js} +0 -0
- package/dist/assets/ol.js +1 -1
- package/dist/assets/ui.fdfe0d.css +1 -0
- package/dist/assets/ui.fdfe0d.js +68 -0
- package/dist/assets/ui.js +1 -1
- package/dist/assets/vue.0bb7c6.js +9 -0
- package/dist/assets/vue.js +2 -1
- package/dist/assets/{vuetify.401a29.css → vuetify.53300f.css} +1 -1
- package/dist/assets/{vuetify.401a29.js → vuetify.53300f.js} +71 -71
- package/dist/assets/vuetify.js +2 -2
- package/dist/index.html +1 -1
- package/index.js +36 -5
- package/lib/vue.js +1 -0
- package/map.config.json +15 -6
- package/package.json +6 -7
- package/plugins/@vcmap/create-link/fallbackCreateLink.vue +71 -0
- package/plugins/@vcmap/create-link/index.js +83 -0
- package/plugins/@vcmap/create-link/package.json +6 -0
- package/plugins/@vcmap/pluginExample/index.js +1 -1
- package/plugins/@vcmap/pluginExample/pluginExampleComponent.vue +20 -3
- package/plugins/@vcmap/project-selector/ProjectSelectorComponent.vue +1 -1
- package/plugins/@vcmap/project-selector/index.js +1 -1
- package/plugins/@vcmap/project-selector/package.json +1 -2
- package/plugins/@vcmap/theme-changer/ThemeChangerComponent.vue +1 -1
- package/plugins/@vcmap/theme-changer/index.js +1 -1
- package/plugins/@vcmap/theme-changer/package.json +1 -2
- package/plugins/categoryTest/Categories.vue +89 -1
- package/plugins/categoryTest/Category.vue +1 -1
- package/plugins/simple-graph/README.md +51 -0
- package/plugins/simple-graph/SimpleGraphComponent.vue +70 -0
- package/plugins/simple-graph/index.js +17 -0
- package/plugins/simple-graph/package.json +11 -0
- package/plugins/simple-graph/simpleGraphView.js +76 -0
- package/plugins/test/editor.vue +1 -1
- package/plugins/test/index.js +63 -2
- package/plugins/test/windowManagerExample.vue +1 -1
- package/src/actions/stateRefAction.js +2 -2
- package/src/actions/styleSelector.vue +1 -1
- package/src/application/Navbar.vue +13 -2
- package/src/application/VcsApp.vue +201 -92
- package/src/application/VcsMap.vue +1 -1
- package/src/application/VcsSettings.vue +1 -1
- package/src/application/vcsAppWrapper.vue +1 -0
- package/src/components/form-inputs-controls/VcsCheckbox.vue +13 -0
- package/src/components/form-inputs-controls/VcsColorPicker.vue +1 -1
- package/src/components/form-inputs-controls/VcsRadio.vue +123 -0
- package/src/components/form-output/VcsFormattedNumber.vue +1 -1
- package/src/components/lists/VcsActionList.vue +13 -4
- package/src/components/lists/VcsTreeview.vue +4 -4
- package/src/components/lists/VcsTreeviewLeaf.vue +9 -2
- package/src/components/lists/VcsTreeviewSearchbar.vue +1 -2
- package/src/components/tables/VcsTable.vue +245 -0
- package/src/contentTree/LayerTree.vue +1 -1
- package/src/contentTree/contentTreeCollection.js +4 -4
- package/src/contentTree/contentTreeItem.js +9 -9
- package/src/contentTree/groupContentTreeItem.js +1 -1
- package/src/contentTree/layerContentTreeItem.js +15 -1
- package/src/contentTree/layerGroupContentTreeItem.js +21 -1
- package/src/contentTree/nodeContentTreeItem.js +1 -1
- package/src/featureInfo/AddressBalloonComponent.vue +47 -0
- package/src/featureInfo/BalloonComponent.vue +138 -0
- package/src/featureInfo/abstractFeatureInfoView.js +313 -0
- package/src/featureInfo/addressBalloonFeatureInfoView.js +118 -0
- package/src/featureInfo/balloonFeatureInfoView.js +151 -0
- package/src/featureInfo/balloonHelper.js +132 -0
- package/src/featureInfo/featureInfo.js +455 -0
- package/src/featureInfo/featureInfoInteraction.js +42 -0
- package/src/featureInfo/iframeFeatureInfoView.js +95 -0
- package/src/featureInfo/tableFeatureInfoView.js +106 -0
- package/src/i18n/de.js +16 -0
- package/src/i18n/en.js +16 -0
- package/src/i18n/i18nCollection.js +17 -0
- package/src/manager/buttonManager.js +5 -5
- package/src/manager/categoryManager/ComponentsManager.vue +30 -0
- package/src/manager/categoryManager/categoryManager.js +500 -0
- package/src/manager/contextMenu/contextMenuComponent.vue +43 -0
- package/src/manager/contextMenu/contextMenuInteraction.js +42 -0
- package/src/manager/contextMenu/contextMenuManager.js +197 -0
- package/src/manager/navbarManager.js +8 -8
- package/src/manager/toolbox/ToolboxManager.vue +2 -2
- package/src/manager/toolbox/toolboxManager.js +7 -3
- package/src/manager/window/WindowComponent.vue +1 -1
- package/src/manager/window/WindowManager.vue +5 -3
- package/src/manager/window/windowManager.js +118 -14
- package/src/navigation/mapNavigation.vue +3 -5
- package/src/navigation/overviewMap.js +28 -5
- package/src/navigation/vcsCompass.vue +1 -1
- package/src/setup.js +0 -2
- package/src/state.js +256 -0
- package/src/styles/_theming.scss +0 -5
- package/src/uiConfig.js +79 -0
- package/src/vcsUiApp.js +210 -20
- package/src/vuePlugins/vuetify.js +14 -4
- package/config/berlin.config.json +0 -510
- package/dist/assets/core.216494.js +0 -4
- package/dist/assets/ui.99a1a7.css +0 -1
- package/dist/assets/ui.99a1a7.js +0 -70
- package/dist/assets/vue-composition-api.c5aca1.js +0 -14
- package/dist/assets/vue-composition-api.js +0 -2
- package/dist/assets/vue.762edd.js +0 -9
- package/lib/vue-composition-api.js +0 -2
@@ -0,0 +1,197 @@
|
|
1
|
+
import { CesiumMap, BaseOLMap } from '@vcmap/core';
|
2
|
+
import { unByKey } from 'ol/Observable.js';
|
3
|
+
import { check } from '@vcsuite/check';
|
4
|
+
import ContextMenuInteraction from './contextMenuInteraction.js';
|
5
|
+
import { vcsAppSymbol } from '../../pluginHelper.js';
|
6
|
+
import { validateAction } from '../../components/lists/VcsActionList.vue';
|
7
|
+
import { getFittedWindowPositionOptionsFromMapEvent, WindowSlot } from '../window/windowManager.js';
|
8
|
+
import ContextMenuComponent, { contextMenuWindowId } from './contextMenuComponent.vue';
|
9
|
+
import { sortByOwner } from '../navbarManager.js';
|
10
|
+
|
11
|
+
/**
|
12
|
+
* @typedef {Object} ContextMenuEventHandler
|
13
|
+
* @property {string|symbol} owner
|
14
|
+
* @property {function(import("@vcmap/core").InteractionEvent):Promise<Array<VcsAction>>|Array<VcsAction>} handler
|
15
|
+
*/
|
16
|
+
|
17
|
+
/**
|
18
|
+
* @param {import("@vcmap/core").VcsMap} map
|
19
|
+
* @param {function():void} clear
|
20
|
+
* @returns {function():void} - returns stop listener function.
|
21
|
+
*/
|
22
|
+
function setupViewPointChanged(map, clear) {
|
23
|
+
const currentViewpoint = map.getViewPointSync();
|
24
|
+
const postRenderHandler = () => {
|
25
|
+
if (!currentViewpoint.equals(map.getViewPointSync(), 0.001)) {
|
26
|
+
clear();
|
27
|
+
}
|
28
|
+
};
|
29
|
+
|
30
|
+
if (map instanceof CesiumMap) {
|
31
|
+
return map.getScene().postRender.addEventListener(postRenderHandler);
|
32
|
+
} else if (map instanceof BaseOLMap) {
|
33
|
+
const key = map.olMap.on('postrender', postRenderHandler);
|
34
|
+
return () => {
|
35
|
+
unByKey(key);
|
36
|
+
};
|
37
|
+
}
|
38
|
+
return () => {};
|
39
|
+
}
|
40
|
+
|
41
|
+
/**
|
42
|
+
* The context menu manager handles right click events in the current map and displays a
|
43
|
+
* context menu based on registered action providers.
|
44
|
+
* @class
|
45
|
+
*/
|
46
|
+
class ContextMenuManager {
|
47
|
+
/**
|
48
|
+
* @param {VcsUiApp} app
|
49
|
+
*/
|
50
|
+
constructor(app) {
|
51
|
+
/**
|
52
|
+
* @type {VcsUiApp}
|
53
|
+
* @private
|
54
|
+
*/
|
55
|
+
this._app = app;
|
56
|
+
/**
|
57
|
+
* @type {ContextMenuInteraction}
|
58
|
+
* @private
|
59
|
+
*/
|
60
|
+
this._interaction = new ContextMenuInteraction(
|
61
|
+
this._handleRightClick.bind(this),
|
62
|
+
async () => {
|
63
|
+
this.clear();
|
64
|
+
},
|
65
|
+
);
|
66
|
+
/**
|
67
|
+
* @type {Array<ContextMenuEventHandler>}
|
68
|
+
* @private
|
69
|
+
*/
|
70
|
+
this._eventHandlers = [];
|
71
|
+
/**
|
72
|
+
* @type {function():void|null}
|
73
|
+
* @private
|
74
|
+
*/
|
75
|
+
this._interactionListener = null;
|
76
|
+
/**
|
77
|
+
* @type {Array<function():void>}
|
78
|
+
* @private
|
79
|
+
*/
|
80
|
+
this._listeners = [];
|
81
|
+
}
|
82
|
+
|
83
|
+
_ensureInteraction() {
|
84
|
+
if (!this._interactionListener) {
|
85
|
+
this._interactionListener = this._app.maps.eventHandler.addPersistentInteraction(this._interaction);
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
_setupListeners() {
|
90
|
+
const clear = this.clear.bind(this);
|
91
|
+
this._listeners = [
|
92
|
+
this._app.layers.stateChanged.addEventListener(clear),
|
93
|
+
this._app.maps.mapActivated.addEventListener(clear),
|
94
|
+
setupViewPointChanged(this._app.maps.activeMap, clear),
|
95
|
+
];
|
96
|
+
}
|
97
|
+
|
98
|
+
/**
|
99
|
+
* @param {import("@vcmap/core").InteractionEvent} event
|
100
|
+
* @private
|
101
|
+
*/
|
102
|
+
async _handleRightClick(event) {
|
103
|
+
this.clear();
|
104
|
+
const actionArrays = await Promise.all(this._eventHandlers.map(({ handler }) => handler(event)));
|
105
|
+
const actions = actionArrays
|
106
|
+
.filter(i => Array.isArray(i))
|
107
|
+
.flatMap(i => i)
|
108
|
+
.filter(validateAction);
|
109
|
+
|
110
|
+
if (actions.length > 0) {
|
111
|
+
const position = getFittedWindowPositionOptionsFromMapEvent(event.windowPosition, 320, actions.length * 32);
|
112
|
+
if (position.left) { // ensure we nudge the window, so it does not trigger the default right click.
|
113
|
+
position.left += 1;
|
114
|
+
} else {
|
115
|
+
position.right += 1;
|
116
|
+
}
|
117
|
+
|
118
|
+
this._app.windowManager.add({
|
119
|
+
id: contextMenuWindowId,
|
120
|
+
component: ContextMenuComponent,
|
121
|
+
state: {
|
122
|
+
hideHeader: true,
|
123
|
+
},
|
124
|
+
props: {
|
125
|
+
actions,
|
126
|
+
showIcon: true,
|
127
|
+
},
|
128
|
+
position,
|
129
|
+
slow: WindowSlot.DETACHED,
|
130
|
+
}, vcsAppSymbol);
|
131
|
+
|
132
|
+
this._setupListeners();
|
133
|
+
}
|
134
|
+
}
|
135
|
+
|
136
|
+
/**
|
137
|
+
* Adds a handler to the context menu. A handler is called with the interaction event on each right click.
|
138
|
+
* If the handler returns an array of valid actions, said actions will be displayed in the context menu
|
139
|
+
* @param {function(import("@vcmap/core").InteractionEvent):Promise<Array<VcsAction>>|Array<VcsAction>} handler
|
140
|
+
* @param {string|symbol} owner
|
141
|
+
*/
|
142
|
+
addEventHandler(handler, owner) {
|
143
|
+
check(handler, Function);
|
144
|
+
check(owner, [String, vcsAppSymbol]);
|
145
|
+
|
146
|
+
this._ensureInteraction();
|
147
|
+
this._eventHandlers.push({ owner, handler });
|
148
|
+
const order = [...this._app.plugins].map(p => p.name);
|
149
|
+
this._eventHandlers.sort((a, b) => {
|
150
|
+
return sortByOwner(a.owner, b.owner, order);
|
151
|
+
});
|
152
|
+
}
|
153
|
+
|
154
|
+
/**
|
155
|
+
* Remove a single handler
|
156
|
+
* @param {function(import("@vcmap/core").InteractionEvent):Promise<Array<VcsAction>>|Array<VcsAction>} handler
|
157
|
+
*/
|
158
|
+
removeHandler(handler) {
|
159
|
+
this._eventHandlers = this._eventHandlers.filter(({ handler: itemHandler }) => itemHandler !== handler);
|
160
|
+
if (this._eventHandlers.length === 0 && this._interactionListener) {
|
161
|
+
this._interactionListener();
|
162
|
+
this._interactionListener = null;
|
163
|
+
}
|
164
|
+
}
|
165
|
+
|
166
|
+
/**
|
167
|
+
* Remove all handlers associated with this owner
|
168
|
+
* @param {string|symbol} owner
|
169
|
+
*/
|
170
|
+
removeOwner(owner) {
|
171
|
+
this._eventHandlers = this._eventHandlers.filter(({ owner: handlerOwner }) => handlerOwner !== owner);
|
172
|
+
if (this._eventHandlers.length === 0 && this._interactionListener) {
|
173
|
+
this._interactionListener();
|
174
|
+
this._interactionListener = null;
|
175
|
+
}
|
176
|
+
}
|
177
|
+
|
178
|
+
/**
|
179
|
+
* Clear any currently opened context menus
|
180
|
+
*/
|
181
|
+
clear() {
|
182
|
+
this._listeners.forEach((cb) => { cb(); });
|
183
|
+
this._listeners = [];
|
184
|
+
this._app.windowManager.remove(contextMenuWindowId);
|
185
|
+
}
|
186
|
+
|
187
|
+
destroy() {
|
188
|
+
this._interaction.destroy();
|
189
|
+
if (this._interactionListener) {
|
190
|
+
this._interactionListener();
|
191
|
+
this._interactionListener = null;
|
192
|
+
}
|
193
|
+
this._eventHandlers = [];
|
194
|
+
}
|
195
|
+
}
|
196
|
+
|
197
|
+
export default ContextMenuManager;
|
@@ -1,20 +1,20 @@
|
|
1
1
|
import { check } from '@vcsuite/check';
|
2
|
-
import
|
2
|
+
import ButtonManager from './buttonManager.js';
|
3
3
|
import { vcsAppSymbol } from '../pluginHelper.js';
|
4
4
|
|
5
5
|
export const locationSymbol = Symbol('location');
|
6
6
|
|
7
7
|
/**
|
8
8
|
* sorts by owner and optionally plugin order
|
9
|
-
* @param {
|
10
|
-
* @param {
|
9
|
+
* @param {string | symbol} ownerA
|
10
|
+
* @param {string | symbol} ownerB
|
11
11
|
* @param {string[]} [order] order of owners to sort by
|
12
12
|
* @returns {number}
|
13
13
|
*/
|
14
|
-
function sortByOwner(
|
14
|
+
export function sortByOwner(ownerA, ownerB, order = []) {
|
15
15
|
const sorted = [vcsAppSymbol, ...order];
|
16
|
-
const indexA = sorted.indexOf(
|
17
|
-
const indexB = sorted.indexOf(
|
16
|
+
const indexA = sorted.indexOf(ownerA);
|
17
|
+
const indexB = sorted.indexOf(ownerB);
|
18
18
|
|
19
19
|
if (indexA === indexB) {
|
20
20
|
return 0;
|
@@ -35,13 +35,13 @@ function sortByOwner(a, b, order = []) {
|
|
35
35
|
* @param {Array<ButtonComponent>} buttonComponents
|
36
36
|
* @param {ButtonLocation} location Button render position
|
37
37
|
* @param {string[]} [order] optional order to sort by (plugin names)
|
38
|
-
* @param {function(
|
38
|
+
* @param {function(ownerA:string, ownerB:string, order: string[]):number} [compareFn=sortByOwner] Per default components are sorted by owner: app first, then plugins
|
39
39
|
* @returns {Array<VcsAction>}
|
40
40
|
*/
|
41
41
|
export function getActionsByLocation(buttonComponents, location, order = [], compareFn = sortByOwner) {
|
42
42
|
return [...buttonComponents]
|
43
43
|
.filter(b => b[locationSymbol] === location)
|
44
|
-
.sort((a, b) => compareFn(a, b, order))
|
44
|
+
.sort((a, b) => compareFn(a.owner, b.owner, order))
|
45
45
|
.map(b => b.action);
|
46
46
|
}
|
47
47
|
|
@@ -49,7 +49,7 @@
|
|
49
49
|
|
50
50
|
<script>
|
51
51
|
|
52
|
-
import { inject, ref, computed, watch, onUnmounted } from '
|
52
|
+
import { inject, ref, computed, watch, onUnmounted } from 'vue';
|
53
53
|
import ToolboxGroupComponent from './ToolboxGroupComponent.vue';
|
54
54
|
import {ButtonLocation, vcsAppSymbol} from '@vcmap/ui';
|
55
55
|
|
@@ -143,7 +143,7 @@ export default {
|
|
143
143
|
actionGroups,
|
144
144
|
width,
|
145
145
|
getPosition,
|
146
|
-
groupId: null,
|
146
|
+
groupId: ref(null),
|
147
147
|
toggleGroup(groupId) {
|
148
148
|
if (this.groupId === groupId) {
|
149
149
|
this.groupId = null;
|
@@ -1,9 +1,8 @@
|
|
1
1
|
/* eslint-disable import/prefer-default-export */
|
2
2
|
import { VcsEvent } from '@vcmap/core';
|
3
|
-
import { reactive } from '@vue/composition-api';
|
4
3
|
import { check, checkMaybe } from '@vcsuite/check';
|
5
4
|
import { v4 as uuidv4 } from 'uuid';
|
6
|
-
import
|
5
|
+
import ButtonManager from '../buttonManager.js';
|
7
6
|
|
8
7
|
/**
|
9
8
|
* @typedef ToolboxGroupComponentOptions
|
@@ -24,6 +23,11 @@ import { ButtonManager } from '../buttonManager.js';
|
|
24
23
|
* @type {Array<ToolboxGroupComponentOptions>}
|
25
24
|
*/
|
26
25
|
const defaultGroups = [
|
26
|
+
{
|
27
|
+
id: 'featureInfo',
|
28
|
+
icon: '$vcsInfo',
|
29
|
+
title: 'Feature Info',
|
30
|
+
},
|
27
31
|
{
|
28
32
|
id: 'select',
|
29
33
|
icon: '$vcsPen',
|
@@ -70,7 +74,7 @@ export class ToolboxManager {
|
|
70
74
|
* reactive ordered array of ids,
|
71
75
|
* @type {Array<string>}
|
72
76
|
*/
|
73
|
-
this.componentIds =
|
77
|
+
this.componentIds = [];
|
74
78
|
|
75
79
|
/**
|
76
80
|
* @type {Map<string, ToolboxGroupComponent>}
|
@@ -41,7 +41,7 @@
|
|
41
41
|
<script>
|
42
42
|
import {
|
43
43
|
onMounted, onUnmounted, computed, ref, nextTick,
|
44
|
-
} from '
|
44
|
+
} from 'vue';
|
45
45
|
import { fromEvent } from 'rxjs';
|
46
46
|
import { switchMap, take, map, tap } from 'rxjs/operators';
|
47
47
|
import { WindowSlot } from './windowManager.js';
|
@@ -1,5 +1,7 @@
|
|
1
1
|
<template>
|
2
|
-
<div
|
2
|
+
<div
|
3
|
+
:class="$vuetify.breakpoint.xs ? 'win-container-mobile' : 'unset'"
|
4
|
+
>
|
3
5
|
<WindowComponent
|
4
6
|
v-for="(id, zIndex) in componentIds"
|
5
7
|
:key="id"
|
@@ -46,7 +48,7 @@
|
|
46
48
|
</style>
|
47
49
|
|
48
50
|
<script>
|
49
|
-
import { inject } from '
|
51
|
+
import { inject, ref } from 'vue';
|
50
52
|
|
51
53
|
import WindowComponent from './WindowComponent.vue';
|
52
54
|
import WindowComponentHeader from './WindowComponentHeader.vue';
|
@@ -109,7 +111,7 @@
|
|
109
111
|
};
|
110
112
|
|
111
113
|
return {
|
112
|
-
componentIds,
|
114
|
+
componentIds: ref(componentIds),
|
113
115
|
getComponent: id => windowManager.get(id).component,
|
114
116
|
getHeaderComponent: id => windowManager.get(id).headerComponent || WindowComponentHeader,
|
115
117
|
getStyles,
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { reactive, ref } from '
|
1
|
+
import { reactive, ref } from 'vue';
|
2
2
|
import { VcsEvent } from '@vcmap/core';
|
3
3
|
import { v4 as uuidv4 } from 'uuid';
|
4
4
|
import { parseEnumValue } from '@vcsuite/parsers';
|
@@ -72,8 +72,8 @@ export const WindowPositions = {
|
|
72
72
|
/**
|
73
73
|
* @typedef WindowComponentOptions
|
74
74
|
* @property {string} [id] Optional ID, If not provided an uuid will be generated.
|
75
|
-
* @property {
|
76
|
-
* @property {
|
75
|
+
* @property {import("vue").Component} component Main Component which is shown below the header.
|
76
|
+
* @property {import("vue").Component} [headerComponent] Replaces the Header Component.
|
77
77
|
* @property {WindowPositionOptions} [position] Will be ignored if WindowSlot !== DETACHED, can be given otherwise or default will be used
|
78
78
|
* @property {WindowState} [state]
|
79
79
|
* @property {WindowSlot} [slot] If WindowSlot is not detached the position will be ignored
|
@@ -94,8 +94,8 @@ export const WindowPositions = {
|
|
94
94
|
/**
|
95
95
|
* @typedef WindowComponent
|
96
96
|
* @property {string} id
|
97
|
-
* @property {
|
98
|
-
* @property {
|
97
|
+
* @property {import("vue").Component} component
|
98
|
+
* @property {import("vue").Component} [headerComponent]
|
99
99
|
* @property {WindowPosition} position
|
100
100
|
* @property {WindowState} state
|
101
101
|
* @property {Ref<UnwrapRef<WindowSlot>>} slot
|
@@ -150,20 +150,124 @@ export function windowPositionFromOptions(windowPositionOptions, windowPosition
|
|
150
150
|
return Object.assign(windowPosition, result);
|
151
151
|
}
|
152
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
|
+
}
|
177
|
+
}
|
178
|
+
return null;
|
179
|
+
}
|
180
|
+
|
153
181
|
/**
|
154
182
|
* WindowPositionOptions from client position relative to a HTMLElement
|
155
|
-
* @param {number} x
|
156
|
-
* @param {number} y
|
157
|
-
* @param {
|
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]
|
158
187
|
* @returns {WindowPositionOptions}
|
159
188
|
*/
|
160
|
-
export function getWindowPositionOptions(x, y, element =
|
161
|
-
|
162
|
-
if (
|
163
|
-
|
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 };
|
164
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 };
|
202
|
+
}
|
203
|
+
return { right: (left + width) - x, bottom: (height + top) - y };
|
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 };
|
216
|
+
}
|
217
|
+
|
218
|
+
const { left, top } = mapElement.getBoundingClientRect();
|
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 };
|
237
|
+
}
|
238
|
+
|
239
|
+
const { width: parentWidth, height: parentHeight } = mapElement.getBoundingClientRect();
|
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);
|
253
|
+
}
|
254
|
+
|
255
|
+
/**
|
256
|
+
* Fits a window aligned top left so it fits into currently active map. this will change the alignment to be bottom or right depending
|
257
|
+
* on if the window would not fit into active map element.
|
258
|
+
* @param {import("@vcmap/cesium").Cartesian2} windowPosition - the window position, as retrieved from an InteractionEvent
|
259
|
+
* @param {number} width
|
260
|
+
* @param {number} height
|
261
|
+
* @returns {WindowPositionOptions}
|
262
|
+
*/
|
263
|
+
export function getFittedWindowPositionOptionsFromMapEvent(windowPosition, width, height) {
|
264
|
+
const mapElement = getActiveMapElement();
|
265
|
+
if (!mapElement) {
|
266
|
+
return { left: windowPosition.x, top: windowPosition.y };
|
267
|
+
}
|
268
|
+
|
165
269
|
const { left, top } = mapElement.getBoundingClientRect();
|
166
|
-
return
|
270
|
+
return getFittedWindowPositionOptions(windowPosition.x + left, windowPosition.y + top, width, height, mapElement);
|
167
271
|
}
|
168
272
|
|
169
273
|
/**
|
@@ -185,7 +289,7 @@ export class WindowManager {
|
|
185
289
|
* reactive ordered array of ids,
|
186
290
|
* @type {Array<string>}
|
187
291
|
*/
|
188
|
-
this.componentIds =
|
292
|
+
this.componentIds = [];
|
189
293
|
|
190
294
|
/**
|
191
295
|
* @type {Map<string, WindowComponent>}
|
@@ -36,7 +36,7 @@
|
|
36
36
|
</template>
|
37
37
|
|
38
38
|
<script>
|
39
|
-
import { computed, inject, ref, onUnmounted } from '
|
39
|
+
import { computed, inject, ref, reactive, onUnmounted } from 'vue';
|
40
40
|
import { ObliqueMap, CesiumMap, OpenlayersMap } from '@vcmap/core';
|
41
41
|
import { unByKey } from 'ol/Observable.js';
|
42
42
|
import { createOverviewMapAction } from '../actions/actionHelper.js';
|
@@ -119,7 +119,7 @@
|
|
119
119
|
VcsCompass,
|
120
120
|
},
|
121
121
|
setup() {
|
122
|
-
/** @type {
|
122
|
+
/** @type {VcsUiApp} */
|
123
123
|
const app = inject('vcsApp');
|
124
124
|
const viewMode = ref(OrientationToolsViewMode.TWO_D);
|
125
125
|
const headingRef = ref(0);
|
@@ -179,9 +179,7 @@
|
|
179
179
|
isOblique: computed(() => viewMode.value === OrientationToolsViewMode.OBLIQUE),
|
180
180
|
zoomIn() { zoom(app.maps.activeMap); }, // debounce?
|
181
181
|
zoomOut() { zoom(app.maps.activeMap, true); },
|
182
|
-
|
183
|
-
right: () => {},
|
184
|
-
overviewAction: ref(action),
|
182
|
+
overviewAction: reactive(action),
|
185
183
|
};
|
186
184
|
},
|
187
185
|
};
|
@@ -20,7 +20,7 @@ import { unByKey } from 'ol/Observable.js';
|
|
20
20
|
import VectorSource from 'ol/source/Vector.js';
|
21
21
|
import { WindowSlot } from '../manager/window/windowManager.js';
|
22
22
|
import OverviewMapClickedInteraction from './overviewMapClickedInteraction.js';
|
23
|
-
import {
|
23
|
+
import { defaultPrimaryColor } from '../vuePlugins/vuetify.js';
|
24
24
|
import { vcsAppSymbol } from '../pluginHelper.js';
|
25
25
|
import VcsMap from '../application/VcsMap.vue';
|
26
26
|
|
@@ -99,8 +99,8 @@ class OverviewMap {
|
|
99
99
|
*/
|
100
100
|
this._obliqueSelectedImageLayer = null;
|
101
101
|
|
102
|
-
const
|
103
|
-
const fillColor = Color.fromCssColorString(
|
102
|
+
const primary = app.uiConfig.config.value.primaryColor ?? defaultPrimaryColor;
|
103
|
+
const fillColor = Color.fromCssColorString('#EDEDED');
|
104
104
|
|
105
105
|
/**
|
106
106
|
* @type {VectorStyleItem}
|
@@ -199,7 +199,7 @@ class OverviewMap {
|
|
199
199
|
* @type {Array<function():void>}
|
200
200
|
* @private
|
201
201
|
*/
|
202
|
-
this.
|
202
|
+
this._collectionListeners = [
|
203
203
|
this._app.maps.layerCollection.added.addEventListener((layer) => {
|
204
204
|
if (layer.properties.showInOverviewMap) {
|
205
205
|
const clone = deserializeLayer(this._app, layer.toJSON());
|
@@ -219,6 +219,16 @@ class OverviewMap {
|
|
219
219
|
this._map.layerCollection.remove(clone);
|
220
220
|
}
|
221
221
|
}),
|
222
|
+
this._app.uiConfig.added.addEventListener((item) => {
|
223
|
+
if (item?.name === 'primaryColor') {
|
224
|
+
this._setObliqueColor(item.value);
|
225
|
+
}
|
226
|
+
}),
|
227
|
+
this._app.uiConfig.removed.addEventListener((item) => {
|
228
|
+
if (item?.name === 'primaryColor') {
|
229
|
+
this._setObliqueColor(defaultPrimaryColor);
|
230
|
+
}
|
231
|
+
}),
|
222
232
|
];
|
223
233
|
}
|
224
234
|
|
@@ -254,6 +264,18 @@ class OverviewMap {
|
|
254
264
|
return this._mapClicked;
|
255
265
|
}
|
256
266
|
|
267
|
+
/**
|
268
|
+
* @param {string} color
|
269
|
+
* @private
|
270
|
+
*/
|
271
|
+
_setObliqueColor(color) {
|
272
|
+
this.obliqueUnselectedStyle?.stroke?.setColor(color);
|
273
|
+
this.obliqueSelectedStyle?.stroke?.setColor(color);
|
274
|
+
this._obliqueTileLayer?.forceRedraw?.();
|
275
|
+
this._obliqueImageLayer?.forceRedraw?.();
|
276
|
+
this._obliqueSelectedImageLayer?.forceRedraw?.();
|
277
|
+
}
|
278
|
+
|
257
279
|
/**
|
258
280
|
* @private
|
259
281
|
*/
|
@@ -574,7 +596,8 @@ class OverviewMap {
|
|
574
596
|
|
575
597
|
destroy() {
|
576
598
|
this._clearListeners();
|
577
|
-
this.
|
599
|
+
this._collectionListeners.forEach(cb => cb());
|
600
|
+
this._collectionListeners = [];
|
578
601
|
if (this._mapPointerListener) {
|
579
602
|
this._mapPointerListener();
|
580
603
|
this._mapPointerListener = null;
|
package/src/setup.js
CHANGED
@@ -1,11 +1,9 @@
|
|
1
1
|
import Vue from 'vue';
|
2
|
-
import VueCompositionAPI from '@vue/composition-api';
|
3
2
|
|
4
3
|
// eslint-disable-next-line no-unused-vars
|
5
4
|
import * as core from '@vcmap/core';
|
6
5
|
// pull in entire core for vcsClassRegistry
|
7
6
|
|
8
7
|
Vue.config.productionTip = false;
|
9
|
-
Vue.use(VueCompositionAPI);
|
10
8
|
|
11
9
|
window.CESIUM_BASE_URL = '/node_modules/@vcmap/cesium/Source/';
|