@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.
Files changed (146) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +44 -0
  3. package/build/postinstall.js +44 -0
  4. package/index.js +139 -0
  5. package/package.json +92 -0
  6. package/src/cesium/cesium3DTileFeature.js +9 -0
  7. package/src/cesium/cesium3DTilePointFeature.js +9 -0
  8. package/src/cesium/cesiumVcsCameraPrimitive.js +146 -0
  9. package/src/cesium/wallpaperMaterial.js +64 -0
  10. package/src/ol/feature.js +47 -0
  11. package/src/ol/geom/circle.js +24 -0
  12. package/src/ol/geom/geometryCollection.js +33 -0
  13. package/src/ol/render/canvas/canvasTileRenderer.js +179 -0
  14. package/src/ol/source/ClusterEnhancedVectorSource.js +39 -0
  15. package/src/ol/source/VcsCluster.js +37 -0
  16. package/src/vcs/vcm/classRegistry.js +106 -0
  17. package/src/vcs/vcm/event/vcsEvent.js +89 -0
  18. package/src/vcs/vcm/globalCollections.js +11 -0
  19. package/src/vcs/vcm/interaction/abstractInteraction.js +149 -0
  20. package/src/vcs/vcm/interaction/coordinateAtPixel.js +102 -0
  21. package/src/vcs/vcm/interaction/eventHandler.js +425 -0
  22. package/src/vcs/vcm/interaction/featureAtPixelInteraction.js +286 -0
  23. package/src/vcs/vcm/interaction/featureProviderInteraction.js +54 -0
  24. package/src/vcs/vcm/interaction/interactionChain.js +124 -0
  25. package/src/vcs/vcm/interaction/interactionType.js +114 -0
  26. package/src/vcs/vcm/layer/buildings.js +17 -0
  27. package/src/vcs/vcm/layer/cesium/cesiumTilesetCesium.js +359 -0
  28. package/src/vcs/vcm/layer/cesium/clusterContext.js +95 -0
  29. package/src/vcs/vcm/layer/cesium/dataSourceCesium.js +171 -0
  30. package/src/vcs/vcm/layer/cesium/openStreetMapCesium.js +29 -0
  31. package/src/vcs/vcm/layer/cesium/pointCloudCesium.js +58 -0
  32. package/src/vcs/vcm/layer/cesium/rasterLayerCesium.js +110 -0
  33. package/src/vcs/vcm/layer/cesium/singleImageCesium.js +49 -0
  34. package/src/vcs/vcm/layer/cesium/terrainCesium.js +80 -0
  35. package/src/vcs/vcm/layer/cesium/tmsCesium.js +54 -0
  36. package/src/vcs/vcm/layer/cesium/vectorCesium.js +255 -0
  37. package/src/vcs/vcm/layer/cesium/vectorContext.js +167 -0
  38. package/src/vcs/vcm/layer/cesium/vectorRasterTileCesium.js +116 -0
  39. package/src/vcs/vcm/layer/cesium/vectorTileImageryProvider.js +246 -0
  40. package/src/vcs/vcm/layer/cesium/wmsCesium.js +71 -0
  41. package/src/vcs/vcm/layer/cesium/wmtsCesium.js +101 -0
  42. package/src/vcs/vcm/layer/cesium/x3dmHelper.js +22 -0
  43. package/src/vcs/vcm/layer/cesiumTileset.js +376 -0
  44. package/src/vcs/vcm/layer/czml.js +141 -0
  45. package/src/vcs/vcm/layer/dataSource.js +259 -0
  46. package/src/vcs/vcm/layer/featureLayer.js +261 -0
  47. package/src/vcs/vcm/layer/featureStore.js +647 -0
  48. package/src/vcs/vcm/layer/featureStoreChanges.js +360 -0
  49. package/src/vcs/vcm/layer/featureStoreState.js +19 -0
  50. package/src/vcs/vcm/layer/featureVisibility.js +435 -0
  51. package/src/vcs/vcm/layer/geojson.js +185 -0
  52. package/src/vcs/vcm/layer/geojsonHelpers.js +450 -0
  53. package/src/vcs/vcm/layer/globalHider.js +157 -0
  54. package/src/vcs/vcm/layer/layer.js +752 -0
  55. package/src/vcs/vcm/layer/layerImplementation.js +102 -0
  56. package/src/vcs/vcm/layer/layerState.js +17 -0
  57. package/src/vcs/vcm/layer/layerSymbols.js +6 -0
  58. package/src/vcs/vcm/layer/oblique/layerOblique.js +76 -0
  59. package/src/vcs/vcm/layer/oblique/obliqueHelpers.js +175 -0
  60. package/src/vcs/vcm/layer/oblique/vectorOblique.js +469 -0
  61. package/src/vcs/vcm/layer/openStreetMap.js +194 -0
  62. package/src/vcs/vcm/layer/openlayers/layerOpenlayers.js +79 -0
  63. package/src/vcs/vcm/layer/openlayers/openStreetMapOpenlayers.js +27 -0
  64. package/src/vcs/vcm/layer/openlayers/rasterLayerOpenlayers.js +121 -0
  65. package/src/vcs/vcm/layer/openlayers/singleImageOpenlayers.js +49 -0
  66. package/src/vcs/vcm/layer/openlayers/tileDebugOpenlayers.js +39 -0
  67. package/src/vcs/vcm/layer/openlayers/tmsOpenlayers.js +62 -0
  68. package/src/vcs/vcm/layer/openlayers/vectorOpenlayers.js +118 -0
  69. package/src/vcs/vcm/layer/openlayers/vectorTileOpenlayers.js +177 -0
  70. package/src/vcs/vcm/layer/openlayers/wmsOpenlayers.js +55 -0
  71. package/src/vcs/vcm/layer/openlayers/wmtsOpenlayers.js +141 -0
  72. package/src/vcs/vcm/layer/pointCloud.js +162 -0
  73. package/src/vcs/vcm/layer/rasterLayer.js +294 -0
  74. package/src/vcs/vcm/layer/singleImage.js +119 -0
  75. package/src/vcs/vcm/layer/terrain.js +122 -0
  76. package/src/vcs/vcm/layer/terrainHelpers.js +123 -0
  77. package/src/vcs/vcm/layer/tileLoadedHelper.js +72 -0
  78. package/src/vcs/vcm/layer/tileProvider/mvtTileProvider.js +104 -0
  79. package/src/vcs/vcm/layer/tileProvider/staticGeojsonTileProvider.js +67 -0
  80. package/src/vcs/vcm/layer/tileProvider/tileProvider.js +584 -0
  81. package/src/vcs/vcm/layer/tileProvider/tileProviderFactory.js +28 -0
  82. package/src/vcs/vcm/layer/tileProvider/urlTemplateTileProvider.js +106 -0
  83. package/src/vcs/vcm/layer/tms.js +121 -0
  84. package/src/vcs/vcm/layer/vector.js +632 -0
  85. package/src/vcs/vcm/layer/vectorHelpers.js +206 -0
  86. package/src/vcs/vcm/layer/vectorProperties.js +1391 -0
  87. package/src/vcs/vcm/layer/vectorSymbols.js +40 -0
  88. package/src/vcs/vcm/layer/vectorTile.js +480 -0
  89. package/src/vcs/vcm/layer/wfs.js +165 -0
  90. package/src/vcs/vcm/layer/wms.js +270 -0
  91. package/src/vcs/vcm/layer/wmsHelpers.js +65 -0
  92. package/src/vcs/vcm/layer/wmts.js +235 -0
  93. package/src/vcs/vcm/maps/baseOLMap.js +257 -0
  94. package/src/vcs/vcm/maps/cameraLimiter.js +219 -0
  95. package/src/vcs/vcm/maps/cesium.js +1192 -0
  96. package/src/vcs/vcm/maps/map.js +511 -0
  97. package/src/vcs/vcm/maps/mapState.js +17 -0
  98. package/src/vcs/vcm/maps/oblique.js +536 -0
  99. package/src/vcs/vcm/maps/openlayers.js +205 -0
  100. package/src/vcs/vcm/object.js +92 -0
  101. package/src/vcs/vcm/oblique/ObliqueCollection.js +572 -0
  102. package/src/vcs/vcm/oblique/ObliqueDataSet.js +357 -0
  103. package/src/vcs/vcm/oblique/ObliqueImage.js +247 -0
  104. package/src/vcs/vcm/oblique/ObliqueImageMeta.js +126 -0
  105. package/src/vcs/vcm/oblique/ObliqueProvider.js +433 -0
  106. package/src/vcs/vcm/oblique/ObliqueView.js +130 -0
  107. package/src/vcs/vcm/oblique/ObliqueViewDirection.js +40 -0
  108. package/src/vcs/vcm/oblique/helpers.js +483 -0
  109. package/src/vcs/vcm/oblique/parseImageJson.js +248 -0
  110. package/src/vcs/vcm/util/clipping/clippingObject.js +386 -0
  111. package/src/vcs/vcm/util/clipping/clippingObjectManager.js +312 -0
  112. package/src/vcs/vcm/util/clipping/clippingPlaneHelper.js +413 -0
  113. package/src/vcs/vcm/util/collection.js +193 -0
  114. package/src/vcs/vcm/util/dateTime.js +60 -0
  115. package/src/vcs/vcm/util/exclusiveManager.js +135 -0
  116. package/src/vcs/vcm/util/extent.js +124 -0
  117. package/src/vcs/vcm/util/featureProvider/abstractFeatureProvider.js +196 -0
  118. package/src/vcs/vcm/util/featureProvider/featureProviderHelpers.js +51 -0
  119. package/src/vcs/vcm/util/featureProvider/featureProviderSymbols.js +11 -0
  120. package/src/vcs/vcm/util/featureProvider/tileProviderFeatureProvider.js +62 -0
  121. package/src/vcs/vcm/util/featureProvider/wmsFeatureProvider.js +280 -0
  122. package/src/vcs/vcm/util/featureconverter/circleToCesium.js +215 -0
  123. package/src/vcs/vcm/util/featureconverter/convert.js +83 -0
  124. package/src/vcs/vcm/util/featureconverter/extent3d.js +154 -0
  125. package/src/vcs/vcm/util/featureconverter/featureconverterHelper.js +591 -0
  126. package/src/vcs/vcm/util/featureconverter/lineStringToCesium.js +171 -0
  127. package/src/vcs/vcm/util/featureconverter/pointToCesium.js +359 -0
  128. package/src/vcs/vcm/util/featureconverter/polygonToCesium.js +229 -0
  129. package/src/vcs/vcm/util/geometryHelpers.js +172 -0
  130. package/src/vcs/vcm/util/indexedCollection.js +158 -0
  131. package/src/vcs/vcm/util/isMobile.js +12 -0
  132. package/src/vcs/vcm/util/layerCollection.js +216 -0
  133. package/src/vcs/vcm/util/locale.js +53 -0
  134. package/src/vcs/vcm/util/mapCollection.js +363 -0
  135. package/src/vcs/vcm/util/math.js +71 -0
  136. package/src/vcs/vcm/util/projection.js +348 -0
  137. package/src/vcs/vcm/util/splitScreen.js +233 -0
  138. package/src/vcs/vcm/util/style/declarativeStyleItem.js +631 -0
  139. package/src/vcs/vcm/util/style/shapesCategory.js +67 -0
  140. package/src/vcs/vcm/util/style/styleFactory.js +48 -0
  141. package/src/vcs/vcm/util/style/styleHelpers.js +555 -0
  142. package/src/vcs/vcm/util/style/styleItem.js +226 -0
  143. package/src/vcs/vcm/util/style/vectorStyleItem.js +927 -0
  144. package/src/vcs/vcm/util/style/writeStyle.js +48 -0
  145. package/src/vcs/vcm/util/urlHelpers.js +16 -0
  146. package/src/vcs/vcm/util/viewpoint.js +333 -0
@@ -0,0 +1,752 @@
1
+ import { check } from '@vcsuite/check';
2
+ import { parseBoolean, parseInteger } from '@vcsuite/parsers';
3
+ import VcsObject from '../object.js';
4
+ import Extent from '../util/extent.js';
5
+ import { getGlobalHider } from './globalHider.js';
6
+ import { vcsLayerName } from './layerSymbols.js';
7
+ import LayerState from './layerState.js';
8
+ import VcsEvent from '../event/vcsEvent.js';
9
+ import { getCurrentLocale, getLocaleChangedEvent } from '../util/locale.js';
10
+ import { VcsClassRegistry } from '../classRegistry.js';
11
+
12
+ /**
13
+ * @typedef {Object} GenericFeature
14
+ * @property {number} longitude
15
+ * @property {number} latitude
16
+ * @property {number} height
17
+ * @property {string} layerName
18
+ * @property {string} layerClass
19
+ * @property {any} attributes
20
+ * @property {boolean} relativeToGround
21
+ */
22
+
23
+ /**
24
+ * @typedef {import("@vcmap/core").Layer} SplitLayer
25
+ * @property {import("@vcmap/cesium").ImagerySplitDirection} splitDirection
26
+ * @property {VcsEvent<import("@vcmap/cesium").ImagerySplitDirection>} splitDirectionChanged
27
+ */
28
+
29
+ /**
30
+ * @typedef {Object} CopyrightOptions
31
+ * @property {string|undefined} provider
32
+ * @property {string|undefined} url
33
+ * @property {string|undefined} year
34
+ * @api
35
+ */
36
+
37
+ // TODO add flight options if flight is moved to core
38
+ /**
39
+ * @typedef {VectorPropertiesOptions} VcsMeta
40
+ * @property {string|undefined} version - the version of the vcsMeta schema
41
+ * @property {VectorStyleItemOptions|DeclarativeStyleItemOptions|Reference|undefined} style
42
+ * @property {Array<string>|undefined} embeddedIcons
43
+ * @property {number|undefined} screenSpaceError
44
+ * @property {*|undefined} flightOptions
45
+ * @property {string|undefined} baseUrl
46
+ * @api
47
+ */
48
+
49
+ /**
50
+ * @typedef {VcsObjectOptions} LayerOptions
51
+ * @property {string|undefined} name - the name of the layer, used to retrieve the layer from the framework. if not specified, a uuid is generated
52
+ * @property {boolean} [activeOnStartup=false] - if true the layer will be activated on initialization
53
+ * @property {boolean} [allowPicking=true] - whether to allow picking on this layer
54
+ * @property {number|undefined} zIndex - zIndex of this layer
55
+ * @property {ExtentOptions|undefined} extent - metadata on the data extent of the layer.
56
+ * @property {Array<string|symbol>|undefined} [exclusiveGroups=[]] -
57
+ * @property {Array<string>|undefined} mapNames - the map names on which this layer is shown, all if empty
58
+ * @property {string|Object|undefined} url - for most layers, a resource url will be needed
59
+ * @property {Array<string>|undefined} hiddenObjectIds - an array of building ids which should be hidden if this layer is active
60
+ * @property {CopyrightOptions|undefined} copyright
61
+ * @api
62
+ */
63
+
64
+ /**
65
+ * The options passed to a layer implementation.
66
+ * @typedef {Object} LayerImplementationOptions
67
+ * @property {string} name
68
+ * @property {string} url
69
+ * @api
70
+ */
71
+
72
+ /**
73
+ * Layer implementations for the {@link CesiumMap} map
74
+ * @namespace cesium
75
+ * @api stable
76
+ */
77
+
78
+ /**
79
+ * Layer implementations for the {@link Oblique} map
80
+ * @namespace oblique
81
+ * @api stable
82
+ */
83
+
84
+ /**
85
+ * Layer implementations for the {@link Openlayers} map
86
+ * @namespace openlayers
87
+ * @api stable
88
+ */
89
+
90
+ /**
91
+ * The version of vcsMeta schema being written by this helper
92
+ * @type {string}
93
+ * @const
94
+ */
95
+ export const vcsMetaVersion = '2.0';
96
+
97
+ /**
98
+ * Abstract base class for Layers.
99
+ * To create a layer Implementation the function `createImplementationsForMap` has to be implemented.
100
+ * To receive implementation options, implement `geImplementationOptions`
101
+ * @abstract
102
+ * @class
103
+ * @export
104
+ * @extends {VcsObject}
105
+ * @api stable
106
+ */
107
+ class Layer extends VcsObject {
108
+ /** @type {string} */
109
+ static get className() { return 'vcs.vcm.layer.Layer'; }
110
+
111
+ /**
112
+ * Symbol to declare a layers name on its visualizations, e.g. ol.layer.Layer, Cesium.Cesium3DTileset
113
+ * @type {symbol}
114
+ * @api
115
+ */
116
+ static get vcsLayerNameSymbol() { return vcsLayerName; }
117
+
118
+ /** @returns {LayerOptions} */
119
+ static getDefaultOptions() {
120
+ return {
121
+ name: undefined,
122
+ extent: undefined,
123
+ activeOnStartup: false,
124
+ allowPicking: true,
125
+ exclusiveGroups: [],
126
+ mapNames: [],
127
+ url: undefined,
128
+ hiddenObjectIds: [],
129
+ copyright: undefined,
130
+ };
131
+ }
132
+
133
+ /**
134
+ * @param {LayerOptions} options
135
+ */
136
+ constructor(options) {
137
+ super(options);
138
+ const defaultOptions = Layer.getDefaultOptions();
139
+
140
+ /**
141
+ * Metadata on the extent of the data in this layer. Depending on the implementation, data is only requested
142
+ * for this extent (e.g. {@see RasterLayer})
143
+ * @type {Extent|null}
144
+ * @api
145
+ */
146
+ this.extent = options.extent ? new Extent(options.extent) : null;
147
+ /**
148
+ * Whether this layer should be active on startup or not. Relevant for creating links.
149
+ * @type {boolean}
150
+ * @api
151
+ */
152
+ this.activeOnStartup = parseBoolean(options.activeOnStartup, defaultOptions.activeOnStartup);
153
+ /**
154
+ * @type {boolean}
155
+ * @private
156
+ */
157
+ this._allowPicking = parseBoolean(options.allowPicking, defaultOptions.allowPicking);
158
+ /**
159
+ * @type {LayerState}
160
+ * @private
161
+ */
162
+ this._state = LayerState.INACTIVE;
163
+ /**
164
+ * @type {Promise<void>|null}
165
+ * @private
166
+ */
167
+ this._loadingPromise = null;
168
+
169
+ /**
170
+ * @type {boolean}
171
+ * @private
172
+ */
173
+ this._initialized = false;
174
+
175
+ /**
176
+ * the names of the maps this layer is shown, all if empty
177
+ * @type {Array.<string>}
178
+ */
179
+ this.mapNames = options.mapNames || defaultOptions.mapNames;
180
+
181
+ /**
182
+ * The class names of the supported maps.
183
+ * @type {Array<string>}
184
+ * @protected
185
+ * @api
186
+ */
187
+ this._supportedMaps = [];
188
+
189
+ /**
190
+ * @type {string|Object}
191
+ * @private
192
+ */
193
+ this._url = options.url;
194
+
195
+ /**
196
+ * @type {Function}
197
+ * @private
198
+ */
199
+ this._localeChangedListener = null;
200
+
201
+ /**
202
+ * @type {number}
203
+ * @private
204
+ */
205
+ this._zIndex = parseInteger(options.zIndex, 0);
206
+
207
+ /**
208
+ * Called when the zIndex of this layer is changed. Is passed the new zIndex as its only argument.
209
+ * @type {VcsEvent<number>}
210
+ * @api
211
+ */
212
+ this.zIndexChanged = new VcsEvent();
213
+
214
+ /**
215
+ * array of object Ids which should be hidden within the context of the layers layerCollection, if this layer is active
216
+ * @type {Array.<string>}
217
+ * @api
218
+ */
219
+ this.hiddenObjectIds = Array.isArray(options.hiddenObjectIds) ?
220
+ options.hiddenObjectIds :
221
+ defaultOptions.hiddenObjectIds;
222
+
223
+ /**
224
+ * @type {Array<string|symbol>}
225
+ * @private
226
+ */
227
+ this._exclusiveGroups = Array.isArray(options.exclusiveGroups) ?
228
+ options.exclusiveGroups.slice() :
229
+ defaultOptions.exclusiveGroups;
230
+
231
+ /**
232
+ * event raised if the exclusives group of the layer changes. is passed the array of exclusive groups as its only argument
233
+ * @type {VcsEvent<Array<string|symbol>>}
234
+ * @api
235
+ */
236
+ this.exclusiveGroupsChanged = new VcsEvent();
237
+
238
+ /** @type {import("@vcmap/core").GlobalHider} */
239
+ this.globalHider = getGlobalHider();
240
+
241
+ /**
242
+ * @type {CopyrightOptions|undefined}
243
+ */
244
+ this.copyright = options.copyright || defaultOptions.copyright;
245
+
246
+ /**
247
+ * @type {Map<import("@vcmap/core").VcsMap, Array<import("@vcmap/core").LayerImplementation>>}
248
+ * @private
249
+ */
250
+ this._implementations = new Map();
251
+
252
+ /**
253
+ * @type {Set<import("@vcmap/core").VcsMap>}
254
+ * @private
255
+ */
256
+ this._activeMaps = new Set();
257
+
258
+ /**
259
+ * Event raised, if the layers state changes. Is passed the LayerState as its only parameter
260
+ * @type {VcsEvent<LayerState>}
261
+ * @api
262
+ */
263
+ this.stateChanged = new VcsEvent();
264
+
265
+ /**
266
+ * An optional feature provider to provider features based on click events.
267
+ * @type {import("@vcmap/core").AbstractFeatureProvider}
268
+ * @api
269
+ */
270
+ this.featureProvider = undefined;
271
+ }
272
+
273
+ /**
274
+ * True if this layer has been initialized, typically after its first activation.
275
+ * @type {boolean}
276
+ * @readonly
277
+ * @api
278
+ */
279
+ get initialized() {
280
+ return this._initialized;
281
+ }
282
+
283
+ /**
284
+ * @api
285
+ * @type {boolean}
286
+ * @readonly
287
+ */
288
+ get active() {
289
+ return this._state === LayerState.ACTIVE;
290
+ }
291
+
292
+ /**
293
+ * @api
294
+ * @type {boolean}
295
+ * @readonly
296
+ */
297
+ get loading() {
298
+ return !!(this._state & LayerState.LOADING);
299
+ }
300
+
301
+ /**
302
+ * @api
303
+ * @type {LayerState}
304
+ * @readonly
305
+ */
306
+ get state() {
307
+ return this._state;
308
+ }
309
+
310
+ /**
311
+ * @api
312
+ * @type {boolean}
313
+ */
314
+ get allowPicking() {
315
+ return this._allowPicking;
316
+ }
317
+
318
+ /**
319
+ * @param {boolean} allowPicking
320
+ */
321
+ set allowPicking(allowPicking) {
322
+ this._allowPicking = allowPicking;
323
+ }
324
+
325
+ /**
326
+ * A layers url, should on be configured, else an empty string
327
+ * @type {string}
328
+ * @api
329
+ */
330
+ get url() {
331
+ if (this._url) {
332
+ if (typeof this._url === 'string') {
333
+ return this._url;
334
+ }
335
+ const locale = getCurrentLocale();
336
+ if (this._url[locale]) {
337
+ return this._url[locale];
338
+ }
339
+ return Object.values(this._url)[0];
340
+ }
341
+ return '';
342
+ }
343
+
344
+ /**
345
+ * @param {string|Object} url
346
+ */
347
+ set url(url) {
348
+ check(url, [String, Object]);
349
+
350
+ if (this._url !== url) {
351
+ this._url = url;
352
+ this.reload();
353
+ }
354
+ }
355
+
356
+ /**
357
+ * Indicates, that this layer is part of an exclusiveGroup
358
+ * @api
359
+ * @type {boolean}
360
+ * @readonly
361
+ */
362
+ get exclusive() {
363
+ return this._exclusiveGroups.length > 0;
364
+ }
365
+
366
+ /**
367
+ * An array of arbitrary exclusive groups
368
+ * @returns {Array<string|symbol>}
369
+ * @readonly
370
+ * @api
371
+ */
372
+ get exclusiveGroups() {
373
+ return this._exclusiveGroups.slice();
374
+ }
375
+
376
+ /**
377
+ * @param {Array<string|symbol>} groups
378
+ */
379
+ set exclusiveGroups(groups) {
380
+ check(groups, [[String, Symbol]]);
381
+
382
+ if (
383
+ groups.length !== this._exclusiveGroups.length ||
384
+ !groups.every(g => this._exclusiveGroups.includes(g))
385
+ ) {
386
+ this._exclusiveGroups = groups.slice();
387
+ this.exclusiveGroupsChanged.raiseEvent(groups);
388
+ }
389
+ }
390
+
391
+ /**
392
+ * @type {number}
393
+ * @api
394
+ */
395
+ get zIndex() { return this._zIndex; }
396
+
397
+ /**
398
+ * @param {number} index
399
+ */
400
+ set zIndex(index) {
401
+ check(index, Number);
402
+
403
+ if (this._zIndex !== index) {
404
+ this._zIndex = index;
405
+ this.zIndexChanged.raiseEvent(index);
406
+ }
407
+ }
408
+
409
+ /**
410
+ * creates an array of layer implementations for the given map.
411
+ * @param {import("@vcmap/core").VcsMap} map Map
412
+ * @returns {Array<import("@vcmap/core").LayerImplementation<import("@vcmap/core").VcsMap>>} return the specific implementation
413
+ */
414
+ // eslint-disable-next-line class-methods-use-this,no-unused-vars
415
+ createImplementationsForMap(map) {
416
+ return [];
417
+ }
418
+
419
+ /**
420
+ * creates or returns a cached array of layer implementations for the given map.
421
+ * @param {import("@vcmap/core").VcsMap} map initialized Map
422
+ * @returns {Array<import("@vcmap/core").LayerImplementation<import("@vcmap/core").VcsMap>>} return the specific implementation
423
+ * @api
424
+ */
425
+ getImplementationsForMap(map) {
426
+ if (!this._implementations.has(map)) {
427
+ if (this.isSupported(map)) {
428
+ this._implementations.set(map, this.createImplementationsForMap(map));
429
+ } else {
430
+ this._implementations.set(map, []);
431
+ }
432
+ }
433
+ return this._implementations.get(map);
434
+ }
435
+
436
+ /**
437
+ * Returns all implementation of this layer for all maps
438
+ * @returns {Array<import("@vcmap/core").LayerImplementation<import("@vcmap/core").VcsMap>>}
439
+ * @api
440
+ */
441
+ getImplementations() {
442
+ return [...this._implementations.values()].flat();
443
+ }
444
+
445
+ /**
446
+ * @returns {LayerImplementationOptions}
447
+ */
448
+ getImplementationOptions() {
449
+ return {
450
+ name: this.name,
451
+ url: this.url,
452
+ };
453
+ }
454
+
455
+ /**
456
+ * Reloads all the data loaded and forces a redraw
457
+ * @returns {Promise<void>}
458
+ * @api
459
+ */
460
+ reload() {
461
+ return this.forceRedraw();
462
+ }
463
+
464
+ /**
465
+ * destroys all current implementations and recreates the ones which have an active map.
466
+ * called for instance when the URL for a layer changes
467
+ * @returns {Promise<void>}
468
+ * @api
469
+ */
470
+ async forceRedraw() {
471
+ const maps = [...this._implementations.keys()];
472
+
473
+ const promises = maps.map((map) => {
474
+ this.removedFromMap(map);
475
+ if (map.active) {
476
+ return this.mapActivated(map);
477
+ }
478
+ return Promise.resolve();
479
+ });
480
+ await Promise.all(promises);
481
+ }
482
+
483
+ /**
484
+ * returns the Extent of this layer
485
+ * @returns {Extent}
486
+ * @api stable
487
+ */
488
+ getExtent() {
489
+ return this.extent;
490
+ }
491
+
492
+ /**
493
+ * returns the Extent of this layer or null, if the layers extent was not defined or cannot be established
494
+ * @returns {Extent|null}
495
+ * @api stable
496
+ */
497
+ getZoomToExtent() {
498
+ if (this.extent && this.extent.isValid()) {
499
+ return this.extent;
500
+ }
501
+ return null;
502
+ }
503
+
504
+ /**
505
+ * recreates the implementations on locale change, if the url of this layer is an Object
506
+ * @param {string} locale
507
+ * @private
508
+ */
509
+ _handleLocaleChange(locale) {
510
+ if (this._url && typeof this._url === 'object' && this._url[locale]) {
511
+ this.reload();
512
+ }
513
+ }
514
+
515
+ /**
516
+ * initializes the layer, can be used to defer loading
517
+ * @returns {Promise<void>}
518
+ */
519
+ initialize() {
520
+ if (!this.initialized) {
521
+ this._localeChangedListener = getLocaleChangedEvent().addEventListener(this._handleLocaleChange.bind(this));
522
+ }
523
+ this._initialized = true;
524
+ return Promise.resolve();
525
+ }
526
+
527
+ /**
528
+ * is called from the map when the map is activated, and this layer is in the layerCollection of the map.
529
+ * Will create an implementation if it does not exits and will forward the activation call to the implementation.
530
+ * @param {import("@vcmap/core").VcsMap} map
531
+ * @returns {Promise<void>}
532
+ */
533
+ async mapActivated(map) {
534
+ this.getLogger().debug(`Layer: ${this.name} mapActivated is called from Map: ${map.name}`);
535
+ this._activeMaps.add(map);
536
+ if (this.active || (this.loading && this.initialized)) {
537
+ await this._activateImplsForMap(map);
538
+ }
539
+ }
540
+
541
+ /**
542
+ * is called from the map when the map is deactivated, and this layer is in the layerCollection of the map.
543
+ * will forward deactivation call to the map specific implementation
544
+ * @param {import("@vcmap/core").VcsMap} map
545
+ */
546
+ mapDeactivated(map) {
547
+ this.getLogger().debug(`Layer: ${this.name} mapDeactivated is called from Map: ${map.name}`);
548
+ this._activeMaps.delete(map);
549
+ if (this.active || this.loading) {
550
+ this.getImplementationsForMap(map)
551
+ .forEach((impl) => {
552
+ impl.deactivate();
553
+ });
554
+ }
555
+ }
556
+
557
+ /**
558
+ * is called when a layer is removed from the layer collection of a map or said map is destroyed.
559
+ * destroys the associated implementation.
560
+ * @param {import("@vcmap/core").VcsMap} map
561
+ */
562
+ removedFromMap(map) {
563
+ this._activeMaps.delete(map);
564
+ this.getImplementationsForMap(map)
565
+ .forEach((impl) => {
566
+ impl.destroy();
567
+ });
568
+ this._implementations.delete(map);
569
+ }
570
+
571
+ /**
572
+ * checks if the currently active map supports this layer
573
+ * @param {import("@vcmap/core").VcsMap} map
574
+ * @returns {boolean}
575
+ * @api stable
576
+ */
577
+ isSupported(map) {
578
+ return map &&
579
+ this._supportedMaps.includes(map.className) &&
580
+ (this.mapNames.length === 0 || this.mapNames.indexOf(map.name) >= 0);
581
+ }
582
+
583
+ /**
584
+ * @param {import("@vcmap/core").VcsMap} map
585
+ * @returns {Promise<void>}
586
+ * @private
587
+ */
588
+ async _activateImplsForMap(map) {
589
+ const impls = this.getImplementationsForMap(map);
590
+ try {
591
+ await Promise.all(impls.map(i => i.activate()));
592
+ } catch (err) {
593
+ this.getLogger().error(`Layer ${this.name} could not activate impl for map ${map.name}`);
594
+ this.getLogger().error(err);
595
+ this._implementations.set(map, []);
596
+ impls.forEach((i) => { i.destroy(); });
597
+ }
598
+ }
599
+
600
+ /**
601
+ * @returns {Promise<void>}
602
+ * @private
603
+ */
604
+ async _activate() {
605
+ this._state = LayerState.LOADING;
606
+ try {
607
+ this.stateChanged.raiseEvent(LayerState.LOADING);
608
+ } catch (e) {
609
+ this.getLogger().debug(`Error on raising LayerState.LOADING event for layer ${this.name} : ${e.message}`);
610
+ }
611
+ await this.initialize();
612
+ if (this._state !== LayerState.LOADING) {
613
+ return;
614
+ }
615
+
616
+ await Promise.all([...this._activeMaps].map(m => this._activateImplsForMap(m)));
617
+ if (this._state !== LayerState.LOADING) {
618
+ return;
619
+ }
620
+ this.globalHider.hideObjects(this.hiddenObjectIds);
621
+ this._state = LayerState.ACTIVE;
622
+ try {
623
+ this.stateChanged.raiseEvent(LayerState.ACTIVE);
624
+ } catch (e) {
625
+ this.getLogger().debug(`Error on raising LayerState.ACTIVE event for layer ${this.name} : ${e.message}`);
626
+ }
627
+ this._loadingPromise = null;
628
+ }
629
+
630
+ /**
631
+ * Activates this layer object, i.e. changes its internal view state
632
+ * and updates the map. The returned promise resolves, once the layer & any _implementations are initialized
633
+ * and all data is loaded.
634
+ * Once the promise resolves, the layer can still be inactive, if deactivate was called while initializing the layer.
635
+ * @returns {Promise<void>}
636
+ * @api stable
637
+ */
638
+ activate() {
639
+ if (this._loadingPromise) {
640
+ return this._loadingPromise;
641
+ }
642
+
643
+ if (this._state === LayerState.INACTIVE) {
644
+ this._loadingPromise = this._activate()
645
+ .catch((err) => {
646
+ this._state = LayerState.INACTIVE;
647
+ return Promise.reject(err);
648
+ });
649
+ return this._loadingPromise;
650
+ }
651
+
652
+ return Promise.resolve();
653
+ }
654
+
655
+ /**
656
+ * Deactivates a layer, changing the internal view state
657
+ * @api
658
+ */
659
+ deactivate() {
660
+ if (this._loadingPromise) {
661
+ this._loadingPromise = null;
662
+ }
663
+
664
+ if (this._state !== LayerState.INACTIVE) {
665
+ this.getImplementations().forEach((impl) => {
666
+ if (impl.loading || impl.active) {
667
+ impl.deactivate();
668
+ }
669
+ });
670
+ this.globalHider.showObjects(this.hiddenObjectIds);
671
+ this._state = LayerState.INACTIVE;
672
+ try {
673
+ this.stateChanged.raiseEvent(LayerState.INACTIVE);
674
+ } catch (e) {
675
+ this.getLogger().debug(`Error on raising LayerState.INACTIVE event for layer ${this.name} : ${e.message}`);
676
+ }
677
+ }
678
+ }
679
+
680
+ /**
681
+ * @returns {LayerOptions}
682
+ */
683
+ getConfigObject() {
684
+ /** @type {LayerOptions} */
685
+ const config = super.getConfigObject();
686
+ const defaultOptions = Layer.getDefaultOptions();
687
+
688
+ if (this.activeOnStartup !== defaultOptions.activeOnStartup) {
689
+ config.activeOnStartup = this.activeOnStartup;
690
+ }
691
+
692
+ if (this.allowPicking !== defaultOptions.allowPicking) {
693
+ config.allowPicking = this.allowPicking;
694
+ }
695
+
696
+ if (this.mapNames.length > 0) {
697
+ config.mapNames = this.mapNames.slice();
698
+ }
699
+
700
+ if (this.hiddenObjectIds.length > 0) {
701
+ config.hiddenObjectIds = this.hiddenObjectIds.slice();
702
+ }
703
+
704
+ if (this._url) {
705
+ config.url = this._url;
706
+ }
707
+
708
+ if (this.extent && this.extent.isValid()) {
709
+ config.extent = this.extent.getConfigObject();
710
+ }
711
+
712
+ if (this._exclusiveGroups.length > 0) {
713
+ config.exclusiveGroups = this._exclusiveGroups.slice();
714
+ }
715
+
716
+ if (this.copyright !== defaultOptions.copyright) {
717
+ config.copyright = { ...this.copyright };
718
+ }
719
+
720
+ return config;
721
+ }
722
+
723
+ /**
724
+ * disposes of this layer, removes instances from the current maps and the framework
725
+ * @api stable
726
+ */
727
+ destroy() {
728
+ super.destroy();
729
+ if (this.featureProvider) {
730
+ this.featureProvider.destroy();
731
+ }
732
+
733
+ this._activeMaps.clear();
734
+ this.getImplementations()
735
+ .forEach((impl) => {
736
+ impl.destroy();
737
+ });
738
+
739
+ if (this._localeChangedListener) {
740
+ this._localeChangedListener();
741
+ this._localeChangedListener = null;
742
+ }
743
+ this._initialized = false;
744
+ this._implementations.clear();
745
+ this.stateChanged.destroy();
746
+ this.zIndexChanged.destroy();
747
+ this.exclusiveGroupsChanged.destroy();
748
+ }
749
+ }
750
+
751
+ VcsClassRegistry.registerClass(Layer.className, Layer);
752
+ export default Layer;