@vcmap/core 5.0.0-rc.0
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/LICENSE.md +21 -0
- package/README.md +44 -0
- package/build/postinstall.js +44 -0
- package/index.js +139 -0
- package/package.json +92 -0
- package/src/cesium/cesium3DTileFeature.js +9 -0
- package/src/cesium/cesium3DTilePointFeature.js +9 -0
- package/src/cesium/cesiumVcsCameraPrimitive.js +146 -0
- package/src/cesium/wallpaperMaterial.js +64 -0
- package/src/ol/feature.js +47 -0
- package/src/ol/geom/circle.js +24 -0
- package/src/ol/geom/geometryCollection.js +33 -0
- package/src/ol/render/canvas/canvasTileRenderer.js +179 -0
- package/src/ol/source/ClusterEnhancedVectorSource.js +39 -0
- package/src/ol/source/VcsCluster.js +37 -0
- package/src/vcs/vcm/classRegistry.js +106 -0
- package/src/vcs/vcm/event/vcsEvent.js +89 -0
- package/src/vcs/vcm/globalCollections.js +11 -0
- package/src/vcs/vcm/interaction/abstractInteraction.js +149 -0
- package/src/vcs/vcm/interaction/coordinateAtPixel.js +102 -0
- package/src/vcs/vcm/interaction/eventHandler.js +425 -0
- package/src/vcs/vcm/interaction/featureAtPixelInteraction.js +286 -0
- package/src/vcs/vcm/interaction/featureProviderInteraction.js +54 -0
- package/src/vcs/vcm/interaction/interactionChain.js +124 -0
- package/src/vcs/vcm/interaction/interactionType.js +114 -0
- package/src/vcs/vcm/layer/buildings.js +17 -0
- package/src/vcs/vcm/layer/cesium/cesiumTilesetCesium.js +359 -0
- package/src/vcs/vcm/layer/cesium/clusterContext.js +95 -0
- package/src/vcs/vcm/layer/cesium/dataSourceCesium.js +171 -0
- package/src/vcs/vcm/layer/cesium/openStreetMapCesium.js +29 -0
- package/src/vcs/vcm/layer/cesium/pointCloudCesium.js +58 -0
- package/src/vcs/vcm/layer/cesium/rasterLayerCesium.js +110 -0
- package/src/vcs/vcm/layer/cesium/singleImageCesium.js +49 -0
- package/src/vcs/vcm/layer/cesium/terrainCesium.js +80 -0
- package/src/vcs/vcm/layer/cesium/tmsCesium.js +54 -0
- package/src/vcs/vcm/layer/cesium/vectorCesium.js +255 -0
- package/src/vcs/vcm/layer/cesium/vectorContext.js +167 -0
- package/src/vcs/vcm/layer/cesium/vectorRasterTileCesium.js +116 -0
- package/src/vcs/vcm/layer/cesium/vectorTileImageryProvider.js +246 -0
- package/src/vcs/vcm/layer/cesium/wmsCesium.js +71 -0
- package/src/vcs/vcm/layer/cesium/wmtsCesium.js +101 -0
- package/src/vcs/vcm/layer/cesium/x3dmHelper.js +22 -0
- package/src/vcs/vcm/layer/cesiumTileset.js +376 -0
- package/src/vcs/vcm/layer/czml.js +141 -0
- package/src/vcs/vcm/layer/dataSource.js +259 -0
- package/src/vcs/vcm/layer/featureLayer.js +261 -0
- package/src/vcs/vcm/layer/featureStore.js +647 -0
- package/src/vcs/vcm/layer/featureStoreChanges.js +360 -0
- package/src/vcs/vcm/layer/featureStoreState.js +19 -0
- package/src/vcs/vcm/layer/featureVisibility.js +435 -0
- package/src/vcs/vcm/layer/geojson.js +185 -0
- package/src/vcs/vcm/layer/geojsonHelpers.js +450 -0
- package/src/vcs/vcm/layer/globalHider.js +157 -0
- package/src/vcs/vcm/layer/layer.js +752 -0
- package/src/vcs/vcm/layer/layerImplementation.js +102 -0
- package/src/vcs/vcm/layer/layerState.js +17 -0
- package/src/vcs/vcm/layer/layerSymbols.js +6 -0
- package/src/vcs/vcm/layer/oblique/layerOblique.js +76 -0
- package/src/vcs/vcm/layer/oblique/obliqueHelpers.js +175 -0
- package/src/vcs/vcm/layer/oblique/vectorOblique.js +469 -0
- package/src/vcs/vcm/layer/openStreetMap.js +194 -0
- package/src/vcs/vcm/layer/openlayers/layerOpenlayers.js +79 -0
- package/src/vcs/vcm/layer/openlayers/openStreetMapOpenlayers.js +27 -0
- package/src/vcs/vcm/layer/openlayers/rasterLayerOpenlayers.js +121 -0
- package/src/vcs/vcm/layer/openlayers/singleImageOpenlayers.js +49 -0
- package/src/vcs/vcm/layer/openlayers/tileDebugOpenlayers.js +39 -0
- package/src/vcs/vcm/layer/openlayers/tmsOpenlayers.js +62 -0
- package/src/vcs/vcm/layer/openlayers/vectorOpenlayers.js +118 -0
- package/src/vcs/vcm/layer/openlayers/vectorTileOpenlayers.js +177 -0
- package/src/vcs/vcm/layer/openlayers/wmsOpenlayers.js +55 -0
- package/src/vcs/vcm/layer/openlayers/wmtsOpenlayers.js +141 -0
- package/src/vcs/vcm/layer/pointCloud.js +162 -0
- package/src/vcs/vcm/layer/rasterLayer.js +294 -0
- package/src/vcs/vcm/layer/singleImage.js +119 -0
- package/src/vcs/vcm/layer/terrain.js +122 -0
- package/src/vcs/vcm/layer/terrainHelpers.js +123 -0
- package/src/vcs/vcm/layer/tileLoadedHelper.js +72 -0
- package/src/vcs/vcm/layer/tileProvider/mvtTileProvider.js +104 -0
- package/src/vcs/vcm/layer/tileProvider/staticGeojsonTileProvider.js +67 -0
- package/src/vcs/vcm/layer/tileProvider/tileProvider.js +584 -0
- package/src/vcs/vcm/layer/tileProvider/tileProviderFactory.js +28 -0
- package/src/vcs/vcm/layer/tileProvider/urlTemplateTileProvider.js +106 -0
- package/src/vcs/vcm/layer/tms.js +121 -0
- package/src/vcs/vcm/layer/vector.js +632 -0
- package/src/vcs/vcm/layer/vectorHelpers.js +206 -0
- package/src/vcs/vcm/layer/vectorProperties.js +1391 -0
- package/src/vcs/vcm/layer/vectorSymbols.js +40 -0
- package/src/vcs/vcm/layer/vectorTile.js +480 -0
- package/src/vcs/vcm/layer/wfs.js +165 -0
- package/src/vcs/vcm/layer/wms.js +270 -0
- package/src/vcs/vcm/layer/wmsHelpers.js +65 -0
- package/src/vcs/vcm/layer/wmts.js +235 -0
- package/src/vcs/vcm/maps/baseOLMap.js +257 -0
- package/src/vcs/vcm/maps/cameraLimiter.js +219 -0
- package/src/vcs/vcm/maps/cesium.js +1192 -0
- package/src/vcs/vcm/maps/map.js +511 -0
- package/src/vcs/vcm/maps/mapState.js +17 -0
- package/src/vcs/vcm/maps/oblique.js +536 -0
- package/src/vcs/vcm/maps/openlayers.js +205 -0
- package/src/vcs/vcm/object.js +92 -0
- package/src/vcs/vcm/oblique/ObliqueCollection.js +572 -0
- package/src/vcs/vcm/oblique/ObliqueDataSet.js +357 -0
- package/src/vcs/vcm/oblique/ObliqueImage.js +247 -0
- package/src/vcs/vcm/oblique/ObliqueImageMeta.js +126 -0
- package/src/vcs/vcm/oblique/ObliqueProvider.js +433 -0
- package/src/vcs/vcm/oblique/ObliqueView.js +130 -0
- package/src/vcs/vcm/oblique/ObliqueViewDirection.js +40 -0
- package/src/vcs/vcm/oblique/helpers.js +483 -0
- package/src/vcs/vcm/oblique/parseImageJson.js +248 -0
- package/src/vcs/vcm/util/clipping/clippingObject.js +386 -0
- package/src/vcs/vcm/util/clipping/clippingObjectManager.js +312 -0
- package/src/vcs/vcm/util/clipping/clippingPlaneHelper.js +413 -0
- package/src/vcs/vcm/util/collection.js +193 -0
- package/src/vcs/vcm/util/dateTime.js +60 -0
- package/src/vcs/vcm/util/exclusiveManager.js +135 -0
- package/src/vcs/vcm/util/extent.js +124 -0
- package/src/vcs/vcm/util/featureProvider/abstractFeatureProvider.js +196 -0
- package/src/vcs/vcm/util/featureProvider/featureProviderHelpers.js +51 -0
- package/src/vcs/vcm/util/featureProvider/featureProviderSymbols.js +11 -0
- package/src/vcs/vcm/util/featureProvider/tileProviderFeatureProvider.js +62 -0
- package/src/vcs/vcm/util/featureProvider/wmsFeatureProvider.js +280 -0
- package/src/vcs/vcm/util/featureconverter/circleToCesium.js +215 -0
- package/src/vcs/vcm/util/featureconverter/convert.js +83 -0
- package/src/vcs/vcm/util/featureconverter/extent3d.js +154 -0
- package/src/vcs/vcm/util/featureconverter/featureconverterHelper.js +591 -0
- package/src/vcs/vcm/util/featureconverter/lineStringToCesium.js +171 -0
- package/src/vcs/vcm/util/featureconverter/pointToCesium.js +359 -0
- package/src/vcs/vcm/util/featureconverter/polygonToCesium.js +229 -0
- package/src/vcs/vcm/util/geometryHelpers.js +172 -0
- package/src/vcs/vcm/util/indexedCollection.js +158 -0
- package/src/vcs/vcm/util/isMobile.js +12 -0
- package/src/vcs/vcm/util/layerCollection.js +216 -0
- package/src/vcs/vcm/util/locale.js +53 -0
- package/src/vcs/vcm/util/mapCollection.js +363 -0
- package/src/vcs/vcm/util/math.js +71 -0
- package/src/vcs/vcm/util/projection.js +348 -0
- package/src/vcs/vcm/util/splitScreen.js +233 -0
- package/src/vcs/vcm/util/style/declarativeStyleItem.js +631 -0
- package/src/vcs/vcm/util/style/shapesCategory.js +67 -0
- package/src/vcs/vcm/util/style/styleFactory.js +48 -0
- package/src/vcs/vcm/util/style/styleHelpers.js +555 -0
- package/src/vcs/vcm/util/style/styleItem.js +226 -0
- package/src/vcs/vcm/util/style/vectorStyleItem.js +927 -0
- package/src/vcs/vcm/util/style/writeStyle.js +48 -0
- package/src/vcs/vcm/util/urlHelpers.js +16 -0
- package/src/vcs/vcm/util/viewpoint.js +333 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import IndexedCollection from './indexedCollection.js';
|
|
2
|
+
import ExclusiveManager from './exclusiveManager.js';
|
|
3
|
+
import LayerState from '../layer/layerState.js';
|
|
4
|
+
import VcsEvent from '../event/vcsEvent.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A collection of layers. Manages rendering order and layer exclusivity. Emits state changes for convenience. Passed to
|
|
8
|
+
* {@link Map} for layers available to said map. Layers must have unique names.
|
|
9
|
+
* @class
|
|
10
|
+
* @export
|
|
11
|
+
* @api
|
|
12
|
+
* @extends {IndexedCollection<import("@vcmap/core").Layer>}}
|
|
13
|
+
*/
|
|
14
|
+
// ignored do to static issues, see https://github.com/microsoft/TypeScript/issues/4628
|
|
15
|
+
// @ts-ignore
|
|
16
|
+
class LayerCollection extends IndexedCollection {
|
|
17
|
+
/**
|
|
18
|
+
* Creates a LayerCollection from an iterable of layers, such as an Array.
|
|
19
|
+
* @param {Iterable<import("@vcmap/core").Layer>} iterable
|
|
20
|
+
* @returns {LayerCollection}
|
|
21
|
+
* @override
|
|
22
|
+
* @api
|
|
23
|
+
*/
|
|
24
|
+
static from(iterable) {
|
|
25
|
+
const collection = new LayerCollection();
|
|
26
|
+
|
|
27
|
+
if (iterable) {
|
|
28
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
29
|
+
for (const layer of iterable) {
|
|
30
|
+
collection.add(layer);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return collection;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
constructor() {
|
|
37
|
+
super();
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Array of layer event listeners
|
|
41
|
+
* @type {Object<string, Array<Function>>}
|
|
42
|
+
* @private
|
|
43
|
+
*/
|
|
44
|
+
this._layerEventListeners = {};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* A symbol to describe the local z index of a layer. The local z index must not equal the layers z index, but is
|
|
48
|
+
* always consistent in comparison to the neighbouring layers. If a layer is moved other then by z index, the collection
|
|
49
|
+
* ensures consistency by setting a new local z index if needed.
|
|
50
|
+
* @type {symbol}
|
|
51
|
+
* @private
|
|
52
|
+
*/
|
|
53
|
+
this._zIndexSymbol = Symbol('zIndex');
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Event raised, when a layer of this collection changes its state. Passed the layer.
|
|
57
|
+
* @type {VcsEvent<import("@vcmap/core").Layer>}
|
|
58
|
+
* @api
|
|
59
|
+
*/
|
|
60
|
+
this.stateChanged = new VcsEvent();
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* The exclusive manager for this collection. Layers within this collection are automatically added and tracked.
|
|
64
|
+
* @type {ExclusiveManager}
|
|
65
|
+
* @api
|
|
66
|
+
*/
|
|
67
|
+
this.exclusiveManager = new ExclusiveManager();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* @param {import("@vcmap/core").Layer} layer
|
|
72
|
+
* @private
|
|
73
|
+
*/
|
|
74
|
+
_listenToLayerEvents(layer) {
|
|
75
|
+
const stateListener = layer.stateChanged.addEventListener((state) => {
|
|
76
|
+
if (state === LayerState.ACTIVE) {
|
|
77
|
+
this.exclusiveManager.handleLayerActivated(layer);
|
|
78
|
+
}
|
|
79
|
+
this.stateChanged.raiseEvent(layer);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const zIndexListener = layer.zIndexChanged.addEventListener(() => {
|
|
83
|
+
this._zIndexChanged(layer);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const exclusiveGroupsListener = layer.exclusiveGroupsChanged.addEventListener(() => {
|
|
87
|
+
this.exclusiveManager.handleExclusiveGroupsChanged(layer);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const listeners = [stateListener, zIndexListener, exclusiveGroupsListener];
|
|
91
|
+
if (/** @type {SplitLayer} */ (layer).splitDirectionChanged) {
|
|
92
|
+
listeners.push(/** @type {SplitLayer} */ (layer).splitDirectionChanged.addEventListener(() => {
|
|
93
|
+
this.exclusiveManager.handleSplitDirectionChanged(layer);
|
|
94
|
+
}));
|
|
95
|
+
}
|
|
96
|
+
this._layerEventListeners[layer.name] = listeners;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Determines the location in the array before the first entry with a higher local z index or null if there is no such position
|
|
101
|
+
* @param {number} zIndex
|
|
102
|
+
* @returns {number|null}
|
|
103
|
+
* @private
|
|
104
|
+
*/
|
|
105
|
+
_findZIndexPosition(zIndex) {
|
|
106
|
+
const usedIndex = this._array.findIndex(l => l[this._zIndexSymbol] > zIndex);
|
|
107
|
+
return usedIndex > -1 ? usedIndex : null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* This is callback for a layers zIndex changed. It reevaluates the array given the new zIndex
|
|
112
|
+
* an moves the specified layer to its new location determined by findeZIndexPosition or the end of the array failing that.
|
|
113
|
+
* @param {import("@vcmap/core").Layer} layer
|
|
114
|
+
* @private
|
|
115
|
+
*/
|
|
116
|
+
_zIndexChanged(layer) {
|
|
117
|
+
const currentIndex = this.indexOf(layer);
|
|
118
|
+
if (currentIndex > -1) {
|
|
119
|
+
const increased = layer[this._zIndexSymbol] < layer.zIndex;
|
|
120
|
+
layer[this._zIndexSymbol] = layer.zIndex;
|
|
121
|
+
let zIndexPosition = this._findZIndexPosition(layer.zIndex);
|
|
122
|
+
if (increased && zIndexPosition > 0) {
|
|
123
|
+
zIndexPosition -= 1; // remove self from count
|
|
124
|
+
}
|
|
125
|
+
zIndexPosition = zIndexPosition != null ? zIndexPosition : this._array.length - 1;
|
|
126
|
+
this._move(layer, currentIndex, zIndexPosition);
|
|
127
|
+
this._ensureLocalZIndex(layer);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Ensures the local z index is consisten with the neighbours of a given layer.
|
|
133
|
+
* e.g. the layer on elower must have a lower or equal zIndex
|
|
134
|
+
* and the one higher a higher or equal zIndex.
|
|
135
|
+
* @param {import("@vcmap/core").Layer} layer
|
|
136
|
+
* @private
|
|
137
|
+
*/
|
|
138
|
+
_ensureLocalZIndex(layer) {
|
|
139
|
+
const currentIndex = this.indexOf(layer);
|
|
140
|
+
if (currentIndex > 0) {
|
|
141
|
+
const below = this._array[currentIndex - 1][this._zIndexSymbol];
|
|
142
|
+
if (below > layer[this._zIndexSymbol]) {
|
|
143
|
+
layer[this._zIndexSymbol] = below;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (currentIndex < this._array.length - 1) {
|
|
148
|
+
const above = this._array[currentIndex + 1][this._zIndexSymbol];
|
|
149
|
+
if (above < layer[this._zIndexSymbol]) {
|
|
150
|
+
layer[this._zIndexSymbol] = above;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Adds a layer to the collection. Can optionally be passed an index at which to insert the layer.
|
|
157
|
+
* @param {import("@vcmap/core").Layer} layer
|
|
158
|
+
* @param {number=} index
|
|
159
|
+
* @returns {number|null} returns the layer index or null, if the layers name is not unique
|
|
160
|
+
* @api
|
|
161
|
+
*/
|
|
162
|
+
add(layer, index) {
|
|
163
|
+
let usedIndex = index;
|
|
164
|
+
if (index == null) {
|
|
165
|
+
usedIndex = this._findZIndexPosition(layer.zIndex);
|
|
166
|
+
}
|
|
167
|
+
const insertedAt = super.add(layer, usedIndex);
|
|
168
|
+
if (insertedAt != null) {
|
|
169
|
+
layer[this._zIndexSymbol] = layer.zIndex;
|
|
170
|
+
this._ensureLocalZIndex(layer);
|
|
171
|
+
this._listenToLayerEvents(layer);
|
|
172
|
+
this.exclusiveManager.registerLayer(layer);
|
|
173
|
+
}
|
|
174
|
+
return insertedAt;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Removes a layer from the collection.
|
|
179
|
+
* @param {import("@vcmap/core").Layer} layer
|
|
180
|
+
* @api
|
|
181
|
+
*/
|
|
182
|
+
remove(layer) {
|
|
183
|
+
if (this._layerEventListeners[layer.name]) {
|
|
184
|
+
this._layerEventListeners[layer.name].forEach((cb) => { cb(); });
|
|
185
|
+
delete this._layerEventListeners[layer.name];
|
|
186
|
+
}
|
|
187
|
+
delete layer[this._zIndexSymbol];
|
|
188
|
+
this.exclusiveManager.unregisterLayer(layer);
|
|
189
|
+
super.remove(layer);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
clear() {
|
|
193
|
+
Object.values(this._layerEventListeners)
|
|
194
|
+
.flat()
|
|
195
|
+
.forEach((r) => { r(); });
|
|
196
|
+
this._array.forEach((l) => {
|
|
197
|
+
delete l[this._zIndexSymbol];
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
this.exclusiveManager.clear();
|
|
201
|
+
this._layerEventListeners = {};
|
|
202
|
+
super.clear();
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
destroy() {
|
|
206
|
+
Object.values(this._layerEventListeners)
|
|
207
|
+
.flat()
|
|
208
|
+
.forEach((r) => { r(); });
|
|
209
|
+
|
|
210
|
+
this._layerEventListeners = {};
|
|
211
|
+
this.exclusiveManager.destroy();
|
|
212
|
+
super.destroy();
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export default LayerCollection;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import VcsEvent from '../event/vcsEvent.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @type {VcsEvent<string>}
|
|
5
|
+
*/
|
|
6
|
+
let localeChangedEvent;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @returns {VcsEvent<string>}
|
|
10
|
+
*/
|
|
11
|
+
export function getLocaleChangedEvent() {
|
|
12
|
+
if (!localeChangedEvent) {
|
|
13
|
+
localeChangedEvent = new VcsEvent();
|
|
14
|
+
}
|
|
15
|
+
return localeChangedEvent;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* returns the default browserLocale, if not possible 'en'
|
|
20
|
+
* @returns {string}
|
|
21
|
+
*/
|
|
22
|
+
export function detectBrowserLocale() {
|
|
23
|
+
if (navigator.language) {
|
|
24
|
+
const lang = navigator.language;
|
|
25
|
+
return lang.substring(0, 2);
|
|
26
|
+
}
|
|
27
|
+
return 'en';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @type {string}
|
|
32
|
+
*/
|
|
33
|
+
let currentLocale;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @returns {string}
|
|
37
|
+
*/
|
|
38
|
+
export function getCurrentLocale() {
|
|
39
|
+
if (!currentLocale) {
|
|
40
|
+
currentLocale = detectBrowserLocale();
|
|
41
|
+
}
|
|
42
|
+
return currentLocale;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @param {string} value
|
|
47
|
+
*/
|
|
48
|
+
export function setCurrentLocale(value) {
|
|
49
|
+
if (typeof value === 'string') {
|
|
50
|
+
currentLocale = value;
|
|
51
|
+
getLocaleChangedEvent().raiseEvent(value);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
import { checkMaybe } from '@vcsuite/check';
|
|
2
|
+
import { getLogger } from '@vcsuite/logger';
|
|
3
|
+
import VcsEvent from '../event/vcsEvent.js';
|
|
4
|
+
import Collection from './collection.js';
|
|
5
|
+
import EventHandler from '../interaction/eventHandler.js';
|
|
6
|
+
import LayerCollection from './layerCollection.js';
|
|
7
|
+
import ClippingObjectManager from './clipping/clippingObjectManager.js';
|
|
8
|
+
import SplitScreen from './splitScreen.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @typedef {Object} MapCollectionInitializationError
|
|
12
|
+
* @property {Error} error
|
|
13
|
+
* @property {import("@vcmap/core").VcsMap} map
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @param {import("@vcmap/core").CesiumMap} cesiumMap
|
|
18
|
+
* @param {import("@vcmap/core").Openlayers} olMap
|
|
19
|
+
* @returns {Promise<void>}
|
|
20
|
+
*/
|
|
21
|
+
async function setCesiumToOLViewpoint(cesiumMap, olMap) {
|
|
22
|
+
const viewPoint = cesiumMap.getViewPointSync();
|
|
23
|
+
const northDownVp = viewPoint.clone();
|
|
24
|
+
northDownVp.heading = 0;
|
|
25
|
+
northDownVp.pitch = -90;
|
|
26
|
+
if (viewPoint && !viewPoint.equals(northDownVp)) {
|
|
27
|
+
if (olMap.fixedNorthOrientation) {
|
|
28
|
+
viewPoint.heading = 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
viewPoint.pitch = -90;
|
|
32
|
+
viewPoint.animate = true;
|
|
33
|
+
viewPoint.duration = 1;
|
|
34
|
+
|
|
35
|
+
if (viewPoint.groundPosition) {
|
|
36
|
+
viewPoint.cameraPosition = null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
await cesiumMap.gotoViewPoint(viewPoint);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @class
|
|
45
|
+
* @export
|
|
46
|
+
* @extends {Collection<import("@vcmap/core").VcsMap>}}
|
|
47
|
+
*/
|
|
48
|
+
// ignored do to static issues, see https://github.com/microsoft/TypeScript/issues/4628
|
|
49
|
+
// @ts-ignore
|
|
50
|
+
class MapCollection extends Collection {
|
|
51
|
+
/**
|
|
52
|
+
* Creates a LayerCollection from an iterable of layers, such as an Array.
|
|
53
|
+
* @param {Iterable<import("@vcmap/core").VcsMap>} iterable
|
|
54
|
+
* @returns {MapCollection}
|
|
55
|
+
* @override
|
|
56
|
+
* @api
|
|
57
|
+
*/
|
|
58
|
+
static from(iterable) {
|
|
59
|
+
const collection = new MapCollection();
|
|
60
|
+
|
|
61
|
+
if (iterable) {
|
|
62
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
63
|
+
for (const map of iterable) {
|
|
64
|
+
collection.add(map);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return collection;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
constructor() {
|
|
71
|
+
super();
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* @type {import("@vcmap/core").VcsMap}
|
|
75
|
+
* @private
|
|
76
|
+
*/
|
|
77
|
+
this._activeMap = null;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
*
|
|
81
|
+
* @type {HTMLElement}
|
|
82
|
+
* @private
|
|
83
|
+
*/
|
|
84
|
+
this._target = null;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* The map pointer event handler. The EventHandler is shared amongst all maps within the collection.
|
|
88
|
+
* @type {EventHandler}
|
|
89
|
+
* @api
|
|
90
|
+
*/
|
|
91
|
+
this.eventHandler = new EventHandler();
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Collection of layers shared amongst the maps within this collection,
|
|
95
|
+
* layers will be rendered if supported on the currently active map.
|
|
96
|
+
* @type {LayerCollection}
|
|
97
|
+
* @api
|
|
98
|
+
*/
|
|
99
|
+
this.layerCollection = new LayerCollection();
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Called, if a map fails to initialize. The map causing the error will be removed from the collection.
|
|
103
|
+
* @type {VcsEvent<MapCollectionInitializationError>}
|
|
104
|
+
* @api
|
|
105
|
+
*/
|
|
106
|
+
this.initializeError = new VcsEvent();
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Called, when a map (typically an oblique map) cannot show the current viewpoint. Is passed
|
|
110
|
+
* the map which cannot show the current viewpoint.
|
|
111
|
+
* @type {VcsEvent<import("@vcmap/core").VcsMap>}
|
|
112
|
+
* @api
|
|
113
|
+
*/
|
|
114
|
+
this.fallbackMapActivated = new VcsEvent();
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Called, when a map is activated. Is passed the activated map.
|
|
118
|
+
* @type {VcsEvent<import("@vcmap/core").VcsMap>}
|
|
119
|
+
* @api
|
|
120
|
+
*/
|
|
121
|
+
this.mapActivated = new VcsEvent();
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Manages the clipping object for the maps in this collection.
|
|
125
|
+
* @type {ClippingObjectManager}
|
|
126
|
+
* @api
|
|
127
|
+
*/
|
|
128
|
+
this.clippingObjectManager = new ClippingObjectManager(this.layerCollection);
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* @type {SplitScreen}
|
|
132
|
+
*/
|
|
133
|
+
this.splitScreen = new SplitScreen(this.clippingObjectManager);
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* @type {Array<Function>}
|
|
137
|
+
* @private
|
|
138
|
+
*/
|
|
139
|
+
this._mapPointerListeners = [];
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* The currently active map
|
|
144
|
+
* @type {import("@vcmap/core").VcsMap}
|
|
145
|
+
* @api
|
|
146
|
+
* @readonly
|
|
147
|
+
*/
|
|
148
|
+
get activeMap() { return this._activeMap; }
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* The currently set HTML element in which to render the maps
|
|
152
|
+
* @type {HTMLElement|null}
|
|
153
|
+
* @api
|
|
154
|
+
* @readonly
|
|
155
|
+
*/
|
|
156
|
+
get target() {
|
|
157
|
+
return this._target;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Adds a map to the collection. This will set the collections target, {@link SplitScreen}
|
|
162
|
+
* and the collections {@link LayerCollection} on the map.
|
|
163
|
+
* It will add map event listeners and pass them to the event handler of this collection.
|
|
164
|
+
* @param {import("@vcmap/core").VcsMap} map
|
|
165
|
+
* @returns {number|null}
|
|
166
|
+
*/
|
|
167
|
+
add(map) {
|
|
168
|
+
const added = super.add(map);
|
|
169
|
+
if (added !== null) {
|
|
170
|
+
this._mapPointerListeners
|
|
171
|
+
.push(map.pointerInteractionEvent.addEventListener(this.eventHandler.handleMapEvent.bind(this.eventHandler)));
|
|
172
|
+
map.layerCollection = this.layerCollection;
|
|
173
|
+
map.splitScreen = this.splitScreen;
|
|
174
|
+
map.setTarget(this._target);
|
|
175
|
+
}
|
|
176
|
+
return added;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Removes the map from the collection. Will also set splitScreen & target to null and an empty layerCollection on the map,
|
|
181
|
+
* if the map is currently part of the collection.
|
|
182
|
+
* @param {import("@vcmap/core").VcsMap} map
|
|
183
|
+
*/
|
|
184
|
+
remove(map) {
|
|
185
|
+
if (this.has(map)) {
|
|
186
|
+
map.setTarget(null);
|
|
187
|
+
map.splitScreen = null;
|
|
188
|
+
map.layerCollection = new LayerCollection();
|
|
189
|
+
}
|
|
190
|
+
super.remove(map);
|
|
191
|
+
if (this._activeMap === map) {
|
|
192
|
+
this._activeMap = null;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* @private
|
|
198
|
+
*/
|
|
199
|
+
_setActiveMapCSSClass() {
|
|
200
|
+
if (this._target && this._activeMap) {
|
|
201
|
+
const mapClassName = this._activeMap.className.split('.').pop();
|
|
202
|
+
this._target.classList.add(mapClassName);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Set the target for these maps.
|
|
208
|
+
* @param {(string|HTMLElement)} target
|
|
209
|
+
* @api
|
|
210
|
+
*/
|
|
211
|
+
setTarget(target) {
|
|
212
|
+
checkMaybe(target, [String, HTMLElement]);
|
|
213
|
+
|
|
214
|
+
this._target = typeof target === 'string' ? document.getElementById(target) : target;
|
|
215
|
+
this._array.forEach((map) => {
|
|
216
|
+
map.setTarget(this._target);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
this._setActiveMapCSSClass();
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* @param {import("@vcmap/core").VcsMap} map
|
|
224
|
+
* @returns {null|import("@vcmap/core").VcsMap}
|
|
225
|
+
* @private
|
|
226
|
+
*/
|
|
227
|
+
_getFallbackMap(map) {
|
|
228
|
+
const { fallbackMap } = map;
|
|
229
|
+
if (fallbackMap) {
|
|
230
|
+
const fMap = this.getByKey(fallbackMap);
|
|
231
|
+
if (fMap && fMap !== map) {
|
|
232
|
+
return fMap;
|
|
233
|
+
} else {
|
|
234
|
+
getLogger().warning(`the fallback map with the name: ${fallbackMap} is missconfigured`);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* @param {import("@vcmap/core").VcsMap} map
|
|
242
|
+
* @returns {null|import("@vcmap/core").VcsMap}
|
|
243
|
+
* @private
|
|
244
|
+
*/
|
|
245
|
+
_getFallbackMapOrDefault(map) {
|
|
246
|
+
const fallbackMap = this._getFallbackMap(map);
|
|
247
|
+
return fallbackMap ||
|
|
248
|
+
this.getByType('vcs.vcm.maps.Openlayers')[0] ||
|
|
249
|
+
this._array[0];
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Sets the active map. This will 1. get the current viewpoint of an acitve map (if one is set) 2.
|
|
254
|
+
* determine that the map to be activated can show this viewpoint or has no fallback map set and 3.
|
|
255
|
+
* activates the map 4. calls gotoViewpoint with the previous maps viewpoint
|
|
256
|
+
* @param {string} mapName
|
|
257
|
+
* @returns {Promise<void>}
|
|
258
|
+
*/
|
|
259
|
+
async setActiveMap(mapName) {
|
|
260
|
+
const map = this.getByKey(mapName);
|
|
261
|
+
if (!map) {
|
|
262
|
+
getLogger('vcs.vcm.util.MapCollection').warning(`could not find map with name ${mapName}`);
|
|
263
|
+
return Promise.resolve();
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (
|
|
267
|
+
this._activeMap &&
|
|
268
|
+
this._activeMap.className === 'vcs.vcm.maps.Cesium' &&
|
|
269
|
+
map.className === 'vcs.vcm.maps.Openlayers'
|
|
270
|
+
) {
|
|
271
|
+
await setCesiumToOLViewpoint(
|
|
272
|
+
/** @type {import("@vcmap/core").CesiumMap} */ (this._activeMap),
|
|
273
|
+
/** @type {import("@vcmap/core").Openlayers} */ (map),
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
try {
|
|
278
|
+
await map.initialize();
|
|
279
|
+
} catch (error) { // typically unsupported webGL and cesium map
|
|
280
|
+
getLogger('vcs.vcm.util.MapCollection').error(error);
|
|
281
|
+
this.remove(map);
|
|
282
|
+
const fallbackMap = this._getFallbackMapOrDefault(map);
|
|
283
|
+
this.initializeError.raiseEvent({
|
|
284
|
+
map,
|
|
285
|
+
error,
|
|
286
|
+
});
|
|
287
|
+
if (fallbackMap) {
|
|
288
|
+
this.fallbackMapActivated.raiseEvent(map);
|
|
289
|
+
return this.setActiveMap(fallbackMap.name);
|
|
290
|
+
}
|
|
291
|
+
throw new Error('cannot activate a single map');
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
let viewpoint;
|
|
295
|
+
if (this._activeMap) {
|
|
296
|
+
if (this._activeMap === map) {
|
|
297
|
+
return map.activate();
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
viewpoint = await this._activeMap.getViewPoint();
|
|
301
|
+
const canShow = await map.canShowViewpoint(viewpoint);
|
|
302
|
+
if (!canShow) {
|
|
303
|
+
const fallbackMap = this._getFallbackMap(map);
|
|
304
|
+
if (fallbackMap) {
|
|
305
|
+
this.fallbackMapActivated.raiseEvent(map);
|
|
306
|
+
return this.setActiveMap(fallbackMap.name);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
this._activeMap.deactivate();
|
|
310
|
+
if (this._target) {
|
|
311
|
+
const mapClassName = this._activeMap.className.split('.').pop();
|
|
312
|
+
this._target.classList.remove(mapClassName);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
this._activeMap = map;
|
|
317
|
+
await this._activeMap.activate();
|
|
318
|
+
this._setActiveMapCSSClass();
|
|
319
|
+
|
|
320
|
+
if (viewpoint) {
|
|
321
|
+
await this._activeMap.gotoViewPoint(viewpoint);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
this.clippingObjectManager.mapActivated(map);
|
|
325
|
+
this.splitScreen.mapActivated(map);
|
|
326
|
+
this.mapActivated.raiseEvent(map);
|
|
327
|
+
return Promise.resolve();
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Returns all maps of a specified type
|
|
332
|
+
* @param {string} type
|
|
333
|
+
* @returns {Array<import("@vcmap/core").VcsMap>}
|
|
334
|
+
* @api
|
|
335
|
+
*/
|
|
336
|
+
getByType(type) {
|
|
337
|
+
return this._array.filter(m => m.className === type);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* @inheritDoc
|
|
342
|
+
*/
|
|
343
|
+
destroy() {
|
|
344
|
+
super.destroy();
|
|
345
|
+
[...this.layerCollection].forEach((l) => { l.destroy(); });
|
|
346
|
+
this.layerCollection.destroy();
|
|
347
|
+
this.eventHandler.destroy();
|
|
348
|
+
this.mapActivated.destroy();
|
|
349
|
+
this.clippingObjectManager.destroy();
|
|
350
|
+
this.clippingObjectManager = null;
|
|
351
|
+
this.splitScreen.destroy();
|
|
352
|
+
this.splitScreen = null;
|
|
353
|
+
this.fallbackMapActivated.destroy();
|
|
354
|
+
this.initializeError.destroy();
|
|
355
|
+
|
|
356
|
+
this._mapPointerListeners.forEach((cb) => { cb(); });
|
|
357
|
+
this._mapPointerListeners = [];
|
|
358
|
+
|
|
359
|
+
this._target = null;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
export default MapCollection;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Math as CesiumMath, Cartesian3 } from '@vcmap/cesium';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* returns a new coordinate ([lon, lat] in degrees) from a distance, bearing and starting coordinate
|
|
5
|
+
* @param {Array.<number>} coord [lon, lat] in degrees
|
|
6
|
+
* @param {number} d distance in m to new coordinate
|
|
7
|
+
* @param {number} brng bearing in degrees ( 0 == north, 90° == east)
|
|
8
|
+
* @returns {Array.<number>};
|
|
9
|
+
*/
|
|
10
|
+
export function coordinateAtDistance(coord, d, brng) {
|
|
11
|
+
const R = 6371000;
|
|
12
|
+
const brngRadians = CesiumMath.toRadians(brng);
|
|
13
|
+
const lat1 = CesiumMath.toRadians(coord[1]);
|
|
14
|
+
const lon1 = CesiumMath.toRadians(coord[0]);
|
|
15
|
+
const lat2 = Math.asin((Math.sin(lat1) * Math.cos(d / R)) +
|
|
16
|
+
(Math.cos(lat1) * Math.sin(d / R) * Math.cos(brngRadians)));
|
|
17
|
+
const lon2 = lon1 + Math.atan2(
|
|
18
|
+
Math.sin(brngRadians) * Math.sin(d / R) * Math.cos(lat1),
|
|
19
|
+
Math.cos(d / R) - (Math.sin(lat1) * Math.sin(lat2)),
|
|
20
|
+
);
|
|
21
|
+
return [parseFloat(CesiumMath.toDegrees(lon2).toFixed(5)), parseFloat(CesiumMath.toDegrees(lat2).toFixed(5))];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* returns the initial bearing in degrees (0-360) between two coordinates
|
|
27
|
+
* @param {Array.<number>} coords1 [lon, lat] in degrees
|
|
28
|
+
* @param {Array.<number>} coords2 [lon, lat] in degrees
|
|
29
|
+
* @returns {number};
|
|
30
|
+
*/
|
|
31
|
+
export function initialBearingBetweenCoords(coords1, coords2) {
|
|
32
|
+
// long
|
|
33
|
+
const l1 = CesiumMath.toRadians(coords1[0]);
|
|
34
|
+
// lat
|
|
35
|
+
const f1 = CesiumMath.toRadians(coords1[1]);
|
|
36
|
+
// long
|
|
37
|
+
const l2 = CesiumMath.toRadians(coords2[0]);
|
|
38
|
+
// lat
|
|
39
|
+
const f2 = CesiumMath.toRadians(coords2[1]);
|
|
40
|
+
|
|
41
|
+
const y = Math.sin(l2 - l1) * Math.cos(f2);
|
|
42
|
+
const x = (Math.cos(f1) * Math.sin(f2)) - (Math.sin(f1) * Math.cos(f2) * Math.cos(l2 - l1));
|
|
43
|
+
let brng = CesiumMath.toDegrees(Math.atan2(y, x));
|
|
44
|
+
brng = (brng + 360) % 360;
|
|
45
|
+
return brng;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* returns distance between two coordinates
|
|
51
|
+
* @param {import("ol/coordinate").Coordinate} point0
|
|
52
|
+
* @param {import("ol/coordinate").Coordinate} point1
|
|
53
|
+
* @returns {number}
|
|
54
|
+
*/
|
|
55
|
+
export function cartesian2DDistance(point0, point1) {
|
|
56
|
+
const distX = point0[0] - point1[0];
|
|
57
|
+
const distY = point0[1] - point1[1];
|
|
58
|
+
return Math.sqrt((distX ** 2) + (distY ** 2));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @param {import("ol/coordinate").Coordinate} p1
|
|
63
|
+
* @param {import("ol/coordinate").Coordinate} p2
|
|
64
|
+
* @returns {number}
|
|
65
|
+
*/
|
|
66
|
+
export function cartesian3DDistance(p1, p2) {
|
|
67
|
+
const point0 = Cartesian3.fromElements(p1[0], p1[1], p1[2]);
|
|
68
|
+
const point1 = Cartesian3.fromElements(p2[0], p2[1], p2[2]);
|
|
69
|
+
return Cartesian3.distance(point0, point1);
|
|
70
|
+
}
|
|
71
|
+
|