@vcmap/core 5.0.0-rc.4 → 5.0.0-rc.7
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/index.d.ts +274 -72
- package/index.js +11 -2
- package/package.json +9 -16
- package/src/vcs/vcm/category/appBackedCategory.js +41 -0
- package/src/vcs/vcm/category/category.js +374 -0
- package/src/vcs/vcm/category/categoryCollection.js +145 -0
- package/src/vcs/vcm/context.js +73 -0
- package/src/vcs/vcm/event/vcsEvent.js +2 -2
- package/src/vcs/vcm/globalCollections.js +1 -5
- package/src/vcs/vcm/layer/featureStore.js +2 -2
- package/src/vcs/vcm/layer/featureStoreChanges.js +89 -73
- package/src/vcs/vcm/layer/featureVisibility.js +3 -2
- package/src/vcs/vcm/layer/geojson.js +3 -5
- package/src/vcs/vcm/layer/geojsonHelpers.js +3 -3
- package/src/vcs/vcm/layer/openlayers/rasterLayerOpenlayers.js +3 -2
- package/src/vcs/vcm/layer/tileProvider/mvtTileProvider.js +3 -3
- package/src/vcs/vcm/layer/tileProvider/staticGeojsonTileProvider.js +3 -3
- package/src/vcs/vcm/layer/tileProvider/urlTemplateTileProvider.js +3 -3
- package/src/vcs/vcm/layer/vectorHelpers.js +4 -4
- package/src/vcs/vcm/layer/wfs.js +5 -5
- package/src/vcs/vcm/maps/oblique.js +19 -23
- package/src/vcs/vcm/maps/openlayers.js +6 -3
- package/src/vcs/vcm/oblique/ObliqueCollection.js +33 -5
- package/src/vcs/vcm/oblique/ObliqueDataSet.js +7 -7
- package/src/vcs/vcm/oblique/ObliqueImageMeta.js +2 -2
- package/src/vcs/vcm/oblique/ObliqueProvider.js +6 -3
- package/src/vcs/vcm/oblique/ObliqueView.js +31 -1
- package/src/vcs/vcm/oblique/defaultObliqueCollection.js +62 -0
- package/src/vcs/vcm/util/clipping/clippingPlaneHelper.js +4 -4
- package/src/vcs/vcm/util/featureProvider/featureProviderHelpers.js +3 -4
- package/src/vcs/vcm/util/featureProvider/wmsFeatureProvider.js +13 -7
- package/src/vcs/vcm/util/featureconverter/extent3D.js +181 -0
- package/src/vcs/vcm/util/fetch.js +32 -0
- package/src/vcs/vcm/util/overrideCollection.js +224 -0
- package/src/vcs/vcm/util/projection.js +5 -2
- package/src/vcs/vcm/util/style/declarativeStyleItem.js +2 -0
- package/src/vcs/vcm/util/style/styleFactory.js +1 -1
- package/src/vcs/vcm/util/style/styleItem.js +2 -0
- package/src/vcs/vcm/util/style/vectorStyleItem.js +2 -0
- package/src/vcs/vcm/vcsApp.js +373 -0
- package/src/vcs/vcm/vcsAppContextHelpers.js +108 -0
- package/src/vcs/vcm/util/featureconverter/extent3d.js +0 -154
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/* eslint no-underscore-dangle: ["error", { "allow": ["_array"] }] */
|
|
2
|
+
// eslint-disable-next-line max-classes-per-file
|
|
3
|
+
import { check } from '@vcsuite/check';
|
|
4
|
+
import { getLogger as getLoggerByName } from '@vcsuite/logger';
|
|
5
|
+
import { contextIdSymbol } from '../vcsAppContextHelpers.js';
|
|
6
|
+
import Collection from './collection.js';
|
|
7
|
+
import VcsEvent from '../event/vcsEvent.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @returns {import("@vcsuite/logger").Logger}
|
|
11
|
+
*/
|
|
12
|
+
function getLogger() {
|
|
13
|
+
return getLoggerByName('OverrideCollection');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The override collection adds the ability to override a unique item and re-creating it, should the override
|
|
18
|
+
* be removed. This does change some flow of called events. 1) if you override an item, removed is not called for the
|
|
19
|
+
* removed current item. 2) added can be called more the once for the same unique id. 3) replaced is called for items
|
|
20
|
+
* which where replaced. replaced is called after added has been called for the item.
|
|
21
|
+
* @interface OverrideCollectionInterface
|
|
22
|
+
* @property {import("@vcmap/core").VcsEvent<T>} replaced - replaced is called after added
|
|
23
|
+
* @property {function(T):T|null} override - returns the overriden item or null if the item could not be inserted (this would be the result of a race condition)
|
|
24
|
+
* @property {Map<string, Array<Object>>} shadowMap
|
|
25
|
+
* @property {function(Array<Object>, string):Promise<void>} parseItems
|
|
26
|
+
* @property {function(string):Promise<void>} removeContext
|
|
27
|
+
* @property {function(string):Array<Object>} serializeContext
|
|
28
|
+
* @template {*} T
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* A symbol added to override collections.
|
|
33
|
+
* @type {symbol}
|
|
34
|
+
*/
|
|
35
|
+
export const isOverrideCollection = Symbol('OverrideCollection');
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @param {Collection<T>} collection
|
|
39
|
+
* @param {function():string} getDynamicContextId - function to get the current dynamic context id
|
|
40
|
+
* @param {(function(T):Object)=} serializeItem - optional function to serialize an item, defaults to returning item.toJSON or item: i => (i.toJSON || i)
|
|
41
|
+
* @param {(function(Object):(T|Promise<T>))=} deserializeItem - optional desirialization function. defaults to returning the passed object: i => i
|
|
42
|
+
* @param {*=} ctor - optional constructor to validate deserialized items against. if passed, deserializeItem must be an instance of ctor.
|
|
43
|
+
* @param {(function(T, (T|null|undefined), (number|undefined)):number|null)=} determineShadowIndex - return the index where a shadow should be inserted. only has relevance, if the collection is indexed. previous and current index may be null.
|
|
44
|
+
* @template {*} T
|
|
45
|
+
* @returns {OverrideCollection<T>}
|
|
46
|
+
*/
|
|
47
|
+
function makeOverrideCollection(
|
|
48
|
+
collection,
|
|
49
|
+
getDynamicContextId,
|
|
50
|
+
serializeItem,
|
|
51
|
+
deserializeItem,
|
|
52
|
+
ctor,
|
|
53
|
+
determineShadowIndex,
|
|
54
|
+
) {
|
|
55
|
+
check(collection, Collection);
|
|
56
|
+
|
|
57
|
+
const overrideCollection = /** @type {OverrideCollection<T>} */ (collection);
|
|
58
|
+
if (overrideCollection[isOverrideCollection]) {
|
|
59
|
+
throw new Error('Cannot transform collection, collection already is an OverrideCollection');
|
|
60
|
+
}
|
|
61
|
+
overrideCollection[isOverrideCollection] = true;
|
|
62
|
+
|
|
63
|
+
const deserialize = deserializeItem || (i => i);
|
|
64
|
+
// @ts-ignore
|
|
65
|
+
const serialize = serializeItem || (i => (i.toJSON ? i.toJSON() : i));
|
|
66
|
+
const getShadowIndex = determineShadowIndex || ((item, shadow, currentIndex) => currentIndex);
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @type {Map<string, Array<Object>>}
|
|
70
|
+
*/
|
|
71
|
+
overrideCollection.shadowMap = new Map();
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* @param {T} item
|
|
75
|
+
* @returns {T|null}
|
|
76
|
+
*/
|
|
77
|
+
overrideCollection.override = function override(item) {
|
|
78
|
+
let shadow;
|
|
79
|
+
let index;
|
|
80
|
+
const itemId = item[overrideCollection.uniqueKey];
|
|
81
|
+
|
|
82
|
+
if (overrideCollection.hasKey(itemId)) {
|
|
83
|
+
shadow = overrideCollection.getByKey(itemId);
|
|
84
|
+
// @ts-ignore
|
|
85
|
+
index = overrideCollection._array.indexOf(shadow); // faking remove to not call removed
|
|
86
|
+
if (index > -1) {
|
|
87
|
+
// @ts-ignore
|
|
88
|
+
overrideCollection._array.splice(index, 1);
|
|
89
|
+
}
|
|
90
|
+
if (!overrideCollection.shadowMap.has(itemId)) {
|
|
91
|
+
overrideCollection.shadowMap.set(itemId, []);
|
|
92
|
+
}
|
|
93
|
+
const shadowsArray = overrideCollection.shadowMap.get(itemId);
|
|
94
|
+
const serializedShadow = serialize(shadow);
|
|
95
|
+
// @ts-ignore
|
|
96
|
+
if (shadow.destroy) {
|
|
97
|
+
// @ts-ignore
|
|
98
|
+
shadow.destroy();
|
|
99
|
+
}
|
|
100
|
+
serializedShadow[contextIdSymbol] = shadow[contextIdSymbol];
|
|
101
|
+
shadowsArray.push(serializedShadow);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const usedIndex = shadow ? getShadowIndex(shadow, item, index) : null;
|
|
105
|
+
// @ts-ignore
|
|
106
|
+
if (overrideCollection.add(item, usedIndex) >= 0) {
|
|
107
|
+
if (shadow) {
|
|
108
|
+
overrideCollection.replaced.raiseEvent(item);
|
|
109
|
+
}
|
|
110
|
+
return item;
|
|
111
|
+
}
|
|
112
|
+
return null;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* @param {Array<Object>} configArray
|
|
117
|
+
* @param {string} contextId
|
|
118
|
+
* @returns {Promise<void>}
|
|
119
|
+
*/
|
|
120
|
+
overrideCollection.parseItems = async function parseItems(configArray, contextId) {
|
|
121
|
+
if (Array.isArray(configArray)) {
|
|
122
|
+
const instanceArray = await Promise.all(configArray.map(async (config) => {
|
|
123
|
+
const item = await deserialize(config);
|
|
124
|
+
if (!item || (ctor && !(item instanceof ctor))) {
|
|
125
|
+
getLogger().warning(`Could not load item ${config[overrideCollection.uniqueKey]} of type ${config.type}`);
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
item[contextIdSymbol] = contextId;
|
|
129
|
+
return item;
|
|
130
|
+
}));
|
|
131
|
+
instanceArray
|
|
132
|
+
.filter(i => i)
|
|
133
|
+
.forEach((i) => { overrideCollection.override(i); });
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
overrideCollection.removed.addEventListener(async (item) => {
|
|
138
|
+
const itemId = item[overrideCollection.uniqueKey];
|
|
139
|
+
|
|
140
|
+
if (overrideCollection.shadowMap.has(itemId)) {
|
|
141
|
+
const serializedShadow = overrideCollection.shadowMap.get(itemId).pop();
|
|
142
|
+
if (serializedShadow) {
|
|
143
|
+
const reincarnation = await deserialize(serializedShadow);
|
|
144
|
+
reincarnation[contextIdSymbol] = serializedShadow[contextIdSymbol];
|
|
145
|
+
// @ts-ignore
|
|
146
|
+
const index = getShadowIndex(reincarnation, item, item[overrideCollection.previousIndexSymbol]);
|
|
147
|
+
// @ts-ignore
|
|
148
|
+
overrideCollection.add(reincarnation, index);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (overrideCollection.shadowMap.get(itemId).length === 0) {
|
|
152
|
+
overrideCollection.shadowMap.delete(itemId);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
overrideCollection.added.addEventListener((item) => {
|
|
158
|
+
if (!item[contextIdSymbol]) {
|
|
159
|
+
item[contextIdSymbol] = getDynamicContextId();
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* @param {string} contextId
|
|
165
|
+
* @returns {Promise<void>}
|
|
166
|
+
*/
|
|
167
|
+
overrideCollection.removeContext = async function removeContext(contextId) {
|
|
168
|
+
overrideCollection.shadowMap.forEach((shadowsArray, name) => {
|
|
169
|
+
const newShadowsArray = shadowsArray.filter(c => c[contextIdSymbol] !== contextId);
|
|
170
|
+
if (newShadowsArray.length === 0) {
|
|
171
|
+
overrideCollection.shadowMap.delete(name);
|
|
172
|
+
} else if (newShadowsArray.length !== shadowsArray.length) {
|
|
173
|
+
overrideCollection.shadowMap.set(name, newShadowsArray);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
await Promise.all([...overrideCollection]
|
|
178
|
+
.filter(item => item[contextIdSymbol] === contextId)
|
|
179
|
+
.map(async (item) => {
|
|
180
|
+
overrideCollection.remove(item);
|
|
181
|
+
// @ts-ignore
|
|
182
|
+
if (item.destroy) {
|
|
183
|
+
// @ts-ignore
|
|
184
|
+
item.destroy();
|
|
185
|
+
}
|
|
186
|
+
}));
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* @type {VcsEvent<T>}
|
|
191
|
+
*/
|
|
192
|
+
overrideCollection.replaced = new VcsEvent();
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* @param {string} contextId
|
|
196
|
+
* @returns {Array<Object>}
|
|
197
|
+
*/
|
|
198
|
+
overrideCollection.serializeContext = function serializeContext(contextId) {
|
|
199
|
+
return [...overrideCollection]
|
|
200
|
+
.map((item) => {
|
|
201
|
+
if (item[contextIdSymbol] === contextId) {
|
|
202
|
+
return serialize(item);
|
|
203
|
+
}
|
|
204
|
+
if (overrideCollection.shadowMap.has(item[overrideCollection.uniqueKey])) {
|
|
205
|
+
return overrideCollection.shadowMap.get(item[overrideCollection.uniqueKey])
|
|
206
|
+
.find(i => i[contextIdSymbol] === contextId);
|
|
207
|
+
}
|
|
208
|
+
return null;
|
|
209
|
+
})
|
|
210
|
+
.filter(i => i);
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
const originalDestroy = overrideCollection.destroy.bind(overrideCollection);
|
|
214
|
+
|
|
215
|
+
overrideCollection.destroy = function destroy() {
|
|
216
|
+
originalDestroy();
|
|
217
|
+
overrideCollection.shadowMap.clear();
|
|
218
|
+
overrideCollection.replaced.destroy();
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
return overrideCollection;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export default makeOverrideCollection;
|
|
@@ -14,9 +14,12 @@ import { VcsClassRegistry } from '../classRegistry.js';
|
|
|
14
14
|
* @property {string|undefined} [prefix='EPSG:'] - an alternate prefix to use for custom projection
|
|
15
15
|
* @api stable
|
|
16
16
|
*/
|
|
17
|
+
/**
|
|
18
|
+
* @typedef {function(Array<number>, Array<number>=, number=): Array<number>} CorrectTransformFunction
|
|
19
|
+
*/
|
|
17
20
|
|
|
18
|
-
export const wgs84ToMercatorTransformer = getTransform('EPSG:4326', 'EPSG:3857');
|
|
19
|
-
export const mercatorToWgs84Transformer = getTransform('EPSG:3857', 'EPSG:4326');
|
|
21
|
+
export const wgs84ToMercatorTransformer = /** @type {CorrectTransformFunction} */ (getTransform('EPSG:4326', 'EPSG:3857'));
|
|
22
|
+
export const mercatorToWgs84Transformer = /** @type {CorrectTransformFunction} */ (getTransform('EPSG:3857', 'EPSG:4326'));
|
|
20
23
|
|
|
21
24
|
|
|
22
25
|
/**
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
whiteColor,
|
|
15
15
|
} from './styleHelpers.js';
|
|
16
16
|
import { originalFeatureSymbol } from '../../layer/vectorSymbols.js';
|
|
17
|
+
import { VcsClassRegistry } from '../../classRegistry.js';
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* @typedef {Object} DeclarativeStyleItemConditions
|
|
@@ -558,6 +559,7 @@ class DeclarativeStyleItem extends StyleItem {
|
|
|
558
559
|
}
|
|
559
560
|
|
|
560
561
|
export default DeclarativeStyleItem;
|
|
562
|
+
VcsClassRegistry.registerClass(DeclarativeStyleItem.className, DeclarativeStyleItem);
|
|
561
563
|
|
|
562
564
|
/**
|
|
563
565
|
* @type {DeclarativeStyleItem}
|
|
@@ -13,7 +13,7 @@ function getLogger() {
|
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* @param {(Reference|DeclarativeStyleItemOptions|VectorStyleItemOptions|StyleItem|string)=} styleOptions
|
|
16
|
-
* @param {
|
|
16
|
+
* @param {StyleItem=} defaultStyle
|
|
17
17
|
* @returns {StyleItem}
|
|
18
18
|
*/
|
|
19
19
|
// eslint-disable-next-line import/prefer-default-export
|
|
@@ -4,6 +4,7 @@ import deepEqual from 'fast-deep-equal';
|
|
|
4
4
|
import { parseEnumValue } from '@vcsuite/parsers';
|
|
5
5
|
import VcsObject from '../../object.js';
|
|
6
6
|
import VcsEvent from '../../event/vcsEvent.js';
|
|
7
|
+
import { VcsClassRegistry } from '../../classRegistry.js';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* @namespace style
|
|
@@ -241,3 +242,4 @@ class StyleItem extends VcsObject {
|
|
|
241
242
|
}
|
|
242
243
|
|
|
243
244
|
export default StyleItem;
|
|
245
|
+
VcsClassRegistry.registerClass(StyleItem.className, StyleItem);
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
getDefaultVectorStyleItemOptions,
|
|
25
25
|
} from './styleHelpers.js';
|
|
26
26
|
import { getShapeFromOptions } from './shapesCategory.js';
|
|
27
|
+
import { VcsClassRegistry } from '../../classRegistry.js';
|
|
27
28
|
|
|
28
29
|
/**
|
|
29
30
|
* @typedef {Object} VectorStyleItemPattern
|
|
@@ -907,6 +908,7 @@ export default VectorStyleItem;
|
|
|
907
908
|
* @export
|
|
908
909
|
*/
|
|
909
910
|
export const defaultVectorStyle = new VectorStyleItem(getDefaultVectorStyleItemOptions());
|
|
911
|
+
VcsClassRegistry.registerClass(VectorStyleItem.className, VectorStyleItem);
|
|
910
912
|
|
|
911
913
|
/**
|
|
912
914
|
* @param {import("@vcmap/cesium").Color} cesiumColor
|
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
import { getLogger as getLoggerByName } from '@vcsuite/logger';
|
|
2
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
3
|
+
import { check } from '@vcsuite/check';
|
|
4
|
+
import Context from './context.js';
|
|
5
|
+
import {
|
|
6
|
+
contextIdSymbol,
|
|
7
|
+
destroyCollection,
|
|
8
|
+
getObjectFromOptions,
|
|
9
|
+
deserializeViewPoint,
|
|
10
|
+
deserializeMap,
|
|
11
|
+
getLayerIndex,
|
|
12
|
+
serializeLayer,
|
|
13
|
+
} from './vcsAppContextHelpers.js';
|
|
14
|
+
import makeOverrideCollection from './util/overrideCollection.js';
|
|
15
|
+
import CategoryCollection from './category/categoryCollection.js';
|
|
16
|
+
import MapCollection from './util/mapCollection.js';
|
|
17
|
+
import VcsMap from './maps/map.js';
|
|
18
|
+
import Layer from './layer/layer.js';
|
|
19
|
+
import Collection from './util/collection.js';
|
|
20
|
+
import ObliqueCollection from './oblique/ObliqueCollection.js';
|
|
21
|
+
import ViewPoint from './util/viewpoint.js';
|
|
22
|
+
import StyleItem from './util/style/styleItem.js';
|
|
23
|
+
import IndexedCollection from './util/indexedCollection.js';
|
|
24
|
+
import VcsEvent from './event/vcsEvent.js';
|
|
25
|
+
import { setDefaultProjectionOptions } from './util/projection.js';
|
|
26
|
+
import Oblique from './maps/oblique.js';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @returns {import("@vcsuite/logger").Logger}
|
|
30
|
+
*/
|
|
31
|
+
function getLogger() {
|
|
32
|
+
return getLoggerByName('init');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @type {Map<string, VcsApp>}
|
|
37
|
+
*/
|
|
38
|
+
const vcsApps = new Map();
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @class
|
|
42
|
+
*/
|
|
43
|
+
class VcsApp {
|
|
44
|
+
constructor() {
|
|
45
|
+
/**
|
|
46
|
+
* @type {string}
|
|
47
|
+
* @private
|
|
48
|
+
*/
|
|
49
|
+
this._id = uuidv4();
|
|
50
|
+
/**
|
|
51
|
+
* @type {Context}
|
|
52
|
+
* @private
|
|
53
|
+
*/
|
|
54
|
+
this._defaultDynamicContext = new Context({ id: '_defaultDynamicContext' });
|
|
55
|
+
/**
|
|
56
|
+
* @type {Context}
|
|
57
|
+
* @private
|
|
58
|
+
*/
|
|
59
|
+
this._dynamicContext = this._defaultDynamicContext;
|
|
60
|
+
|
|
61
|
+
const getDynamicContextId = () => this._dynamicContext.id;
|
|
62
|
+
/**
|
|
63
|
+
* @type {OverrideMapCollection}
|
|
64
|
+
* @private
|
|
65
|
+
*/
|
|
66
|
+
// @ts-ignore
|
|
67
|
+
this._maps = makeOverrideCollection(
|
|
68
|
+
new MapCollection(),
|
|
69
|
+
getDynamicContextId,
|
|
70
|
+
null,
|
|
71
|
+
deserializeMap.bind(null, this),
|
|
72
|
+
VcsMap,
|
|
73
|
+
);
|
|
74
|
+
/**
|
|
75
|
+
* @type {OverrideLayerCollection}
|
|
76
|
+
* @private
|
|
77
|
+
*/
|
|
78
|
+
// @ts-ignore
|
|
79
|
+
this._layers = makeOverrideCollection(
|
|
80
|
+
this._maps.layerCollection,
|
|
81
|
+
getDynamicContextId,
|
|
82
|
+
serializeLayer.bind(null, this),
|
|
83
|
+
getObjectFromOptions,
|
|
84
|
+
Layer,
|
|
85
|
+
getLayerIndex,
|
|
86
|
+
);
|
|
87
|
+
/**
|
|
88
|
+
* @type {OverrideCollection<import("@vcmap/core").ObliqueCollection>}
|
|
89
|
+
* @private
|
|
90
|
+
*/
|
|
91
|
+
this._obliqueCollections = makeOverrideCollection(
|
|
92
|
+
new Collection(),
|
|
93
|
+
getDynamicContextId,
|
|
94
|
+
null,
|
|
95
|
+
config => new ObliqueCollection(config),
|
|
96
|
+
ObliqueCollection,
|
|
97
|
+
); // XXX there is a global for this collection in core.
|
|
98
|
+
/**
|
|
99
|
+
* @type {OverrideCollection<import("@vcmap/core").ViewPoint>}
|
|
100
|
+
* @private
|
|
101
|
+
*/
|
|
102
|
+
this._viewPoints = makeOverrideCollection(
|
|
103
|
+
new Collection(),
|
|
104
|
+
getDynamicContextId,
|
|
105
|
+
null,
|
|
106
|
+
deserializeViewPoint,
|
|
107
|
+
ViewPoint,
|
|
108
|
+
);
|
|
109
|
+
/**
|
|
110
|
+
* @type {OverrideCollection<import("@vcmap/core").StyleItem>}
|
|
111
|
+
* @private
|
|
112
|
+
*/
|
|
113
|
+
this._styles = makeOverrideCollection(
|
|
114
|
+
new Collection(),
|
|
115
|
+
getDynamicContextId,
|
|
116
|
+
null,
|
|
117
|
+
getObjectFromOptions,
|
|
118
|
+
StyleItem,
|
|
119
|
+
); // XXX there is a global for this collection in core.
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* @type {IndexedCollection<Context>}
|
|
123
|
+
* @private
|
|
124
|
+
*/
|
|
125
|
+
this._contexts = new IndexedCollection('id');
|
|
126
|
+
this._contexts.add(this._dynamicContext);
|
|
127
|
+
/**
|
|
128
|
+
* @type {CategoryCollection}
|
|
129
|
+
* @private
|
|
130
|
+
*/
|
|
131
|
+
this._categories = new CategoryCollection(this);
|
|
132
|
+
/**
|
|
133
|
+
* @type {import("@vcmap/core").VcsEvent<void>}
|
|
134
|
+
* @private
|
|
135
|
+
*/
|
|
136
|
+
this._destroyed = new VcsEvent();
|
|
137
|
+
/**
|
|
138
|
+
* @type {Promise<void>}
|
|
139
|
+
* @private
|
|
140
|
+
*/
|
|
141
|
+
this._contextMutationPromise = Promise.resolve();
|
|
142
|
+
vcsApps.set(this._id, this);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* @type {string}
|
|
147
|
+
* @readonly
|
|
148
|
+
*/
|
|
149
|
+
get id() { return this._id; }
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* @type {OverrideMapCollection}
|
|
153
|
+
* @readonly
|
|
154
|
+
*/
|
|
155
|
+
get maps() { return this._maps; }
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* @type {OverrideLayerCollection}
|
|
159
|
+
* @readonly
|
|
160
|
+
*/
|
|
161
|
+
get layers() { return this._layers; }
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* @type {OverrideCollection<import("@vcmap/core").ObliqueCollection>}
|
|
165
|
+
* @readonly
|
|
166
|
+
*/
|
|
167
|
+
get obliqueCollections() { return this._obliqueCollections; }
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* @type {OverrideCollection<import("@vcmap/core").ViewPoint>}
|
|
171
|
+
* @readonly
|
|
172
|
+
*/
|
|
173
|
+
get viewPoints() { return this._viewPoints; }
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* @type {OverrideCollection<import("@vcmap/core").StyleItem>}
|
|
177
|
+
* @readonly
|
|
178
|
+
*/
|
|
179
|
+
get styles() { return this._styles; }
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* @type {CategoryCollection}
|
|
183
|
+
* @readonly
|
|
184
|
+
*/
|
|
185
|
+
get categories() { return this._categories; }
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* @type {VcsEvent<void>}
|
|
189
|
+
* @readonly
|
|
190
|
+
*/
|
|
191
|
+
get destroyed() { return this._destroyed; }
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* @returns {VcsEvent<Context>}
|
|
195
|
+
* @readonly
|
|
196
|
+
*/
|
|
197
|
+
get contextAdded() { return this._contexts.added; }
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* @returns {VcsEvent<Context>}
|
|
201
|
+
* @readonly
|
|
202
|
+
*/
|
|
203
|
+
get contextRemoved() { return this._contexts.removed; }
|
|
204
|
+
|
|
205
|
+
get dynamicContextId() { return this._dynamicContext.id; }
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* @param {string} id
|
|
209
|
+
* @returns {Context}
|
|
210
|
+
*/
|
|
211
|
+
getContextById(id) {
|
|
212
|
+
return this._contexts.getByKey(id);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* @param {Context} context
|
|
217
|
+
* @returns {Promise<void>}
|
|
218
|
+
* @protected
|
|
219
|
+
*/
|
|
220
|
+
async _parseContext(context) {
|
|
221
|
+
const { config } = context;
|
|
222
|
+
if (config.projection) { // XXX this needs fixing. this should be _projections_ and there should be a `defaultProjection`
|
|
223
|
+
setDefaultProjectionOptions(config.projection);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
await this._styles.parseItems(config.styles, context.id);
|
|
227
|
+
await this._layers.parseItems(config.layers, context.id);
|
|
228
|
+
// TODO add flights & ade here
|
|
229
|
+
|
|
230
|
+
await this._obliqueCollections.parseItems(config.obliqueCollections, context.id);
|
|
231
|
+
await this._viewPoints.parseItems(config.viewpoints, context.id);
|
|
232
|
+
await this._maps.parseItems(config.maps, context.id);
|
|
233
|
+
|
|
234
|
+
if (Array.isArray(config.categories)) {
|
|
235
|
+
await Promise.all((config.categories).map(async ({ name, items }) => {
|
|
236
|
+
await this._categories.parseCategoryItems(name, items, context.id);
|
|
237
|
+
}));
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* @param {Context} context
|
|
243
|
+
* @returns {Promise<void>}
|
|
244
|
+
* @protected
|
|
245
|
+
*/
|
|
246
|
+
async _setContextState(context) {
|
|
247
|
+
const { config } = context;
|
|
248
|
+
[...this._layers]
|
|
249
|
+
.filter(l => l[contextIdSymbol] === context.id)
|
|
250
|
+
.forEach((l) => {
|
|
251
|
+
if (l.activeOnStartup) {
|
|
252
|
+
l.activate()
|
|
253
|
+
.catch((err) => {
|
|
254
|
+
getLogger().error(`Failed to activate active on startup layer ${l.name}`);
|
|
255
|
+
getLogger().error(err);
|
|
256
|
+
this._layers.remove(l);
|
|
257
|
+
l.destroy();
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
const activeObliqueCollection = [...this._obliqueCollections]
|
|
263
|
+
.find(c => c[contextIdSymbol] === context.id && c.activeOnStartup);
|
|
264
|
+
|
|
265
|
+
if (activeObliqueCollection) {
|
|
266
|
+
[...this._maps]
|
|
267
|
+
.filter(m => m instanceof Oblique)
|
|
268
|
+
.forEach((m) => { /** @type {Oblique} */ (m).setCollection(activeObliqueCollection); });
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (config.startingMapName) {
|
|
272
|
+
await this._maps.setActiveMap(config.startingMapName);
|
|
273
|
+
} else if (!this._maps.activeMap && this._maps.size > 0) {
|
|
274
|
+
await this._maps.setActiveMap([...this._maps][0].name);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (config.startingViewPointName && this._maps.activeMap) {
|
|
278
|
+
const startViewPoint = this._viewPoints.getByKey(config.startingViewPointName);
|
|
279
|
+
if (startViewPoint) {
|
|
280
|
+
await this._maps.activeMap.gotoViewPoint(startViewPoint);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* @param {Context} context
|
|
287
|
+
* @returns {Promise<void>}
|
|
288
|
+
*/
|
|
289
|
+
addContext(context) {
|
|
290
|
+
check(context, Context);
|
|
291
|
+
|
|
292
|
+
this._contextMutationPromise = this._contextMutationPromise
|
|
293
|
+
.then(async () => {
|
|
294
|
+
if (this._contexts.has(context)) {
|
|
295
|
+
getLogger().info(`context with id ${context.id} already loaded`);
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
await this._parseContext(context);
|
|
300
|
+
await this._setContextState(context);
|
|
301
|
+
this._contexts.add(context);
|
|
302
|
+
});
|
|
303
|
+
return this._contextMutationPromise;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* @param {string} contextId
|
|
308
|
+
* @returns {Promise<void>}
|
|
309
|
+
* @protected
|
|
310
|
+
*/
|
|
311
|
+
async _removeContext(contextId) {
|
|
312
|
+
await Promise.all([
|
|
313
|
+
this._maps.removeContext(contextId),
|
|
314
|
+
this._layers.removeContext(contextId),
|
|
315
|
+
this._viewPoints.removeContext(contextId),
|
|
316
|
+
this._styles.removeContext(contextId),
|
|
317
|
+
this._obliqueCollections.removeContext(contextId),
|
|
318
|
+
]);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* @param {string} contextId
|
|
323
|
+
* @returns {Promise<void>}
|
|
324
|
+
*/
|
|
325
|
+
removeContext(contextId) {
|
|
326
|
+
this._contextMutationPromise = this._contextMutationPromise
|
|
327
|
+
.then(async () => {
|
|
328
|
+
const context = this._contexts.getByKey(contextId);
|
|
329
|
+
if (!context) {
|
|
330
|
+
getLogger().info(`context with id ${contextId} has alread been removed`);
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
await this._removeContext(contextId);
|
|
334
|
+
this._contexts.remove(context);
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
return this._contextMutationPromise;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Destroys the app and all its collections, their content and ui managers.
|
|
342
|
+
*/
|
|
343
|
+
destroy() {
|
|
344
|
+
Object.defineProperty(this, '_contextMutationPromise', {
|
|
345
|
+
get() {
|
|
346
|
+
throw new Error('VcsApp was destroyed');
|
|
347
|
+
},
|
|
348
|
+
});
|
|
349
|
+
vcsApps.delete(this._id);
|
|
350
|
+
destroyCollection(this._maps);
|
|
351
|
+
destroyCollection(this._layers);
|
|
352
|
+
destroyCollection(this._obliqueCollections);
|
|
353
|
+
destroyCollection(this._viewPoints);
|
|
354
|
+
destroyCollection(this._styles);
|
|
355
|
+
destroyCollection(this._contexts);
|
|
356
|
+
destroyCollection(this._categories);
|
|
357
|
+
this.destroyed.raiseEvent();
|
|
358
|
+
this.destroyed.destroy();
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* @param {string} id
|
|
364
|
+
* @returns {VcsApp}
|
|
365
|
+
*/
|
|
366
|
+
export function getVcsAppById(id) {
|
|
367
|
+
return vcsApps.get(id);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
window.vcs = window.vcs || {};
|
|
371
|
+
window.vcs.apps = vcsApps;
|
|
372
|
+
|
|
373
|
+
export default VcsApp;
|