@open-pioneer/map 1.4.0-dev.20260727093741 → 1.5.0-dev.20260910103330
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/CHANGELOG.md +547 -485
- package/LayerFactory.d.ts +1 -1
- package/LayerFactory.js.map +1 -1
- package/MapRegistry.js.map +1 -1
- package/README.md +5 -8
- package/layers/AbstractLayer.d.ts +41 -3
- package/layers/AbstractLayer.js +139 -81
- package/layers/AbstractLayer.js.map +1 -1
- package/layers/AbstractLayerBase.d.ts +2 -2
- package/layers/AbstractLayerBase.js.map +1 -1
- package/layers/GroupLayer.d.ts +2 -1
- package/layers/GroupLayer.js +4 -1
- package/layers/GroupLayer.js.map +1 -1
- package/layers/SimpleLayer.d.ts +1 -1
- package/layers/SimpleLayer.js +1 -1
- package/layers/SimpleLayer.js.map +1 -1
- package/layers/WMSLayer.js +58 -10
- package/layers/WMSLayer.js.map +1 -1
- package/layers/WMTSLayer.d.ts +1 -1
- package/layers/WMTSLayer.js +10 -4
- package/layers/WMTSLayer.js.map +1 -1
- package/layers/group/GroupLayerCollection.d.ts +2 -2
- package/layers/group/GroupLayerCollection.js +1 -1
- package/layers/group/GroupLayerCollection.js.map +1 -1
- package/layers/shared/AddLayerOptions.d.ts +3 -2
- package/layers/shared/LayerConfig.d.ts +2 -0
- package/layers/shared/SublayerBaseType.d.ts +9 -0
- package/layers/shared/SublayersCollection.js.map +1 -1
- package/layers/shared/getRecursiveLayers.d.ts +1 -1
- package/layers/shared/getRecursiveLayers.js +12 -5
- package/layers/shared/getRecursiveLayers.js.map +1 -1
- package/layers/shared/internals.d.ts +4 -2
- package/layers/shared/internals.js +3 -1
- package/layers/shared/internals.js.map +1 -1
- package/layers/unions.js.map +1 -1
- package/layers/wms/WMSSublayer.d.ts +14 -1
- package/layers/wms/WMSSublayer.js +29 -2
- package/layers/wms/WMSSublayer.js.map +1 -1
- package/layers/wms/getAttributions.js.map +1 -1
- package/layers/wms/getLegendUrl.js.map +1 -1
- package/layers/wmts/getAttributions.js.map +1 -1
- package/layers/wmts/getLegendUrl.js.map +1 -1
- package/model/Highlights.js.map +1 -1
- package/model/LayerCollection.js +38 -23
- package/model/LayerCollection.js.map +1 -1
- package/model/MapAttributions.js.map +1 -1
- package/model/MapConfig.d.ts +16 -0
- package/model/MapModel.d.ts +5 -5
- package/model/MapModel.js +4 -4
- package/model/MapModel.js.map +1 -1
- package/model/Overlays.d.ts +2 -2
- package/model/Overlays.js +2 -2
- package/model/Overlays.js.map +1 -1
- package/model/createMapModel.js +57 -2
- package/model/createMapModel.js.map +1 -1
- package/model/getGeometries.js.map +1 -1
- package/package.json +17 -13
- package/ui/DefaultMapProvider.js.map +1 -1
- package/ui/MapAnchor.js.map +1 -1
- package/ui/MapContainer.js +1 -1
- package/ui/MapContainer.js.map +1 -1
- package/ui/MapContainerContext.js.map +1 -1
- package/ui/OverlaysRenderer.js.map +1 -1
- package/ui/computeMapAnchorStyles.js.map +1 -1
- package/ui/hooks/useMapModel.js +2 -2
- package/ui/hooks/useMapModel.js.map +1 -1
- package/utils/fetch.js.map +1 -1
- package/utils/geometry-utils.js.map +1 -1
- package/utils/ol-test-support.js.map +1 -1
- package/utils/projections.js.map +1 -1
- package/utils/sanitize.js.map +1 -1
package/LayerFactory.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { HttpService } from "@open-pioneer/http";
|
|
2
2
|
import { DECLARE_SERVICE_INTERFACE, ServiceOptions } from "@open-pioneer/runtime";
|
|
3
|
-
import { LayerConfig } from "./layers/shared/LayerConfig";
|
|
4
3
|
import { LayerConstructor } from "./layers/shared/internals";
|
|
4
|
+
import { LayerConfig } from "./layers/shared/LayerConfig";
|
|
5
5
|
import { Layer } from "./layers/unions";
|
|
6
6
|
interface References {
|
|
7
7
|
httpService: HttpService;
|
package/LayerFactory.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LayerFactory.js","sources":["LayerFactory.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { HttpService } from \"@open-pioneer/http\";\nimport { DECLARE_SERVICE_INTERFACE, ServiceOptions } from \"@open-pioneer/runtime\";\nimport { AbstractLayer } from \"./layers/AbstractLayer\";\nimport {
|
|
1
|
+
{"version":3,"file":"LayerFactory.js","sources":["LayerFactory.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\n\nimport { HttpService } from \"@open-pioneer/http\";\nimport { DECLARE_SERVICE_INTERFACE, ServiceOptions } from \"@open-pioneer/runtime\";\nimport { AbstractLayer } from \"./layers/AbstractLayer\";\nimport { LayerConstructor } from \"./layers/shared/internals\";\nimport { LayerConfig } from \"./layers/shared/LayerConfig\";\nimport { Layer } from \"./layers/unions\";\nimport { INTERNAL_CONSTRUCTOR_TAG } from \"./utils/InternalConstructorTag\";\n\ninterface References {\n httpService: HttpService;\n}\n\n/**\n * Options that can be passed to {@link LayerFactory.create}.\n *\n * The `type` option is mandatory and indicates the type of the layer (e.g. `WMSLayer`).\n * The other options depend on the specific layer type.\n *\n * @group Services\n */\nexport type LayerCreateOptions<LayerType extends Layer, Config extends LayerConfig> = {\n /** The layer type to construct. */\n type: LayerConstructor<Config, LayerType>;\n} & Config;\n\n/**\n * Creates instances of layer classes.\n *\n * Use the interface `\"map.LayerFactory\"` to obtain an instance of this service.\n *\n * @group Services\n */\nexport class LayerFactory {\n declare [DECLARE_SERVICE_INTERFACE]: \"map.LayerFactory\";\n\n #httpService: HttpService;\n\n constructor(options: ServiceOptions<References>) {\n this.#httpService = options.references.httpService;\n }\n\n /**\n * Creates a new instance of the given layer type.\n * The `\"type\"` option is mandatory and specifies which layer type to create.\n *\n * The other configuration options may be dependent on the specific layer type.\n *\n * Example:\n *\n * ```ts\n * import { SimpleLayer } from \"@open-pioneer/map\";\n *\n * const layerFactory = ...; // injected\n * const layer = layerFactory.create({\n * type: SimpleLayer,\n * title: \"Layer title\",\n * olLayer: new TileLayer({}),\n * // ... other options\n * });\n * ```\n */\n create<LayerType extends Layer, Config extends LayerConfig>(\n config: LayerCreateOptions<LayerType, Config>\n ): LayerType {\n const { type, ...rest } = config;\n if (!type || !(type.prototype instanceof AbstractLayer)) {\n throw new Error(\n `Invalid layer type option. Use one of the layer classes exported by this package.`\n );\n }\n return new type(\n rest as unknown as Config,\n { httpService: this.#httpService },\n INTERNAL_CONSTRUCTOR_TAG\n );\n }\n}\n"],"names":[],"mappings":";;;AAmCO,MAAM,YAAA,CAAa;AAAA,EAGtB,YAAA;AAAA,EAEA,YAAY,OAAA,EAAqC;AAC7C,IAAA,IAAA,CAAK,YAAA,GAAe,QAAQ,UAAA,CAAW,WAAA;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBA,OACI,MAAA,EACS;AACT,IAAA,MAAM,EAAE,IAAA,EAAM,GAAG,IAAA,EAAK,GAAI,MAAA;AAC1B,IAAA,IAAI,CAAC,IAAA,IAAQ,EAAE,IAAA,CAAK,qBAAqB,aAAA,CAAA,EAAgB;AACrD,MAAA,MAAM,IAAI,KAAA;AAAA,QACN,CAAA,iFAAA;AAAA,OACJ;AAAA,IACJ;AACA,IAAA,OAAO,IAAI,IAAA;AAAA,MACP,IAAA;AAAA,MACA,EAAE,WAAA,EAAa,IAAA,CAAK,YAAA,EAAa;AAAA,MACjC;AAAA,KACJ;AAAA,EACJ;AACJ;;;;"}
|
package/MapRegistry.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MapRegistry.js","sources":["MapRegistry.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { batch, ReadonlyReactive } from \"@conterra/reactivity-core\";\nimport { on } from \"@conterra/reactivity-events\";\nimport { createLogger, Resource } from \"@open-pioneer/core\";\nimport { HttpService } from \"@open-pioneer/http\";\nimport {\n DECLARE_SERVICE_INTERFACE,\n PackageIntl,\n Service,\n ServiceOptions\n} from \"@open-pioneer/runtime\";\nimport OlMap from \"ol/Map\";\nimport { sourceId } from \"open-pioneer:source-info\";\nimport { LayerFactory } from \"./LayerFactory\";\nimport { createMapModel } from \"./model/createMapModel\";\nimport { MapConfig } from \"./model/MapConfig\";\nimport { MapModel } from \"./model/MapModel\";\n\nconst LOG = createLogger(sourceId);\n\n/**\n * Options passed to the {@link MapConfigProvider.getMapConfig} method.\n *\n * @group Services\n */\nexport interface MapConfigProviderOptions {\n /**\n * A reference to the layer factory, for the construction of new layer instances.\n */\n layerFactory: LayerFactory;\n}\n\n/**\n * Provides an OpenLayers map configuration with a given map id.\n *\n * The implementor must also provide the interface name `\"map.MapConfigProvider\"`.\n *\n * @group Services\n */\nexport interface MapConfigProvider {\n /**\n * Unique identifier of the map.\n */\n readonly mapId: string;\n\n /**\n * Returns the map configuration for this map.\n *\n * Called by the {@link MapRegistry} when the map is requested for the first time.\n *\n * See {@link MapConfig} for supported options during map creation.\n * Use {@link MapConfigProviderOptions.layerFactory} to construct new layers.\n */\n getMapConfig(options: MapConfigProviderOptions): Promise<MapConfig>;\n}\n\ninterface References {\n providers: MapConfigProvider[];\n httpService: HttpService;\n layerFactory: LayerFactory;\n}\n\ntype ModelJobResult =\n { kind: \"model\"; model: MapModel; listener: Resource } | { kind: \"error\"; error: Error };\n\n/**\n * Provides access to registered map instances.\n *\n * Maps are identified by a unique id.\n *\n * Inject an instance of this service by referencing the interface name `\"map.MapRegistry\"`.\n *\n * @group Services\n */\nexport class MapRegistry implements Service {\n declare [DECLARE_SERVICE_INTERFACE]: \"map.MapRegistry\";\n\n #currentIntl: ReadonlyReactive<PackageIntl>;\n #httpService: HttpService;\n #layerFactory: LayerFactory;\n\n #configProviders = new Map<string, MapConfigProvider>();\n #entries = new Map<string, ModelJobResult>();\n #modelCreationJobs = new Map<string, Promise<ModelJobResult>>();\n #modelsByOlMap = new WeakMap<OlMap, MapModel>();\n #destroyed = false;\n\n constructor({ references, currentIntl }: ServiceOptions<References>) {\n this.#currentIntl = currentIntl;\n this.#httpService = references.httpService;\n this.#layerFactory = references.layerFactory;\n\n const providers = references.providers;\n for (const provider of providers) {\n this.#configProviders.set(provider.mapId, provider);\n }\n }\n\n destroy(): void {\n if (this.#destroyed) {\n return;\n }\n\n batch(() => {\n LOG.debug(`Destroy map registry and all maps`);\n this.#destroyed = true;\n this.#entries.forEach((entry) => {\n if (entry.kind === \"model\") {\n entry.listener.destroy();\n entry.model.destroy();\n }\n });\n this.#entries.clear();\n this.#modelCreationJobs.clear();\n });\n }\n\n /**\n * Returns the map model associated with the given id.\n * Returns undefined if there is no such model.\n */\n async getMapModel(mapId: string): Promise<MapModel | undefined> {\n if (this.#destroyed) {\n throw new Error(\"MapRegistry has already been destroyed.\");\n }\n\n const entry = this.#entries.get(mapId);\n if (entry) {\n return unbox(entry);\n }\n\n const creationJob = this.#modelCreationJobs.get(mapId);\n if (creationJob) {\n return await waitForResult(creationJob);\n }\n\n const provider = this.#configProviders.get(mapId);\n if (!provider) {\n LOG.debug(`Failed to find a config provider for map id '${mapId}'.`);\n return undefined;\n }\n\n return await this.#createMapModel(mapId, () =>\n provider.getMapConfig({\n layerFactory: this.#layerFactory\n })\n );\n }\n\n /**\n * Like {@link getMapModel}, but throws if no model exists for the given `mapId`.\n */\n async expectMapModel(mapId: string): Promise<MapModel> {\n const model = await this.getMapModel(mapId);\n if (!model) {\n throw new Error(`No configuration available for map with id '${mapId}'.`);\n }\n return model;\n }\n\n /**\n * Creates a MapModel without the need to provide a {@link MapConfigProvider}.\n * Throws an error if a map with the given id already exists or if the map config is invalid.\n */\n async createMapModel(mapId: string, options?: MapConfig): Promise<MapModel> {\n if (this.#destroyed) {\n throw new Error(\"MapRegistry has already been destroyed.\");\n }\n if (this.#entries.has(mapId)) {\n throw new Error(`Map id '${mapId}' is not unique.`);\n }\n if (this.#modelCreationJobs.has(mapId)) {\n throw new Error(`A map with the id '${mapId}' is already under construction.`);\n }\n return await this.#createMapModel(mapId, () => Promise.resolve(options ?? {}));\n }\n\n /**\n * Given a raw OpenLayers map instance, returns the associated {@link MapModel} - or undefined\n * if the map is unknown to this registry.\n *\n * All OpenLayers maps created by this registry (e.g. via {@link MapConfigProvider} or {@link createMapModel}) have an associated map model.\n */\n getMapModelByRawInstance(olMap: OlMap): MapModel | undefined {\n return this.#modelsByOlMap.get(olMap);\n }\n\n // Wrapper method to ensure that in-progress construction of maps can be observed.\n #createMapModel(mapId: string, configProvider: () => Promise<MapConfig>): Promise<MapModel> {\n const creationJob = this.#modelCreationJobs.get(mapId);\n if (creationJob) {\n throw new Error(\"Internal error: a map model is already being created for this mapId\");\n }\n\n const modelPromise = this.#createMapModelImpl(mapId, configProvider)\n .then((mapModel) => {\n if (this.#destroyed) {\n mapModel.destroy();\n throw new Error(`MapRegistry has been destroyed.`);\n }\n\n const listener = on(\n mapModel.destroyed,\n () => {\n // Allow id reuse for dynamically created maps\n if (this.#isDynamic(mapId)) {\n const currentEntry = this.#entries.get(mapId);\n if (currentEntry === entry) {\n this.#entries.delete(mapId);\n }\n }\n },\n { dispatch: \"sync\" }\n );\n\n const entry: ModelJobResult = { kind: \"model\", model: mapModel, listener };\n this.#entries.set(mapId, entry);\n this.#modelCreationJobs.delete(mapId);\n this.#modelsByOlMap.set(mapModel.olMap, mapModel);\n return entry;\n })\n .catch((cause) => {\n const error = new Error(`Failed to construct map '${mapId}'`, { cause });\n const entry: ModelJobResult = { kind: \"error\", error };\n this.#modelCreationJobs.delete(mapId);\n if (!this.#isDynamic(mapId)) {\n // Don't store errors for dynamically created maps (the caller already got the error via promise).\n this.#entries.set(mapId, entry);\n }\n return entry;\n });\n this.#modelCreationJobs.set(mapId, modelPromise);\n return waitForResult(modelPromise);\n }\n\n async #createMapModelImpl(\n mapId: string,\n configProvider: () => Promise<MapConfig>\n ): Promise<MapModel> {\n LOG.info(`Creating map with id '${mapId}'`);\n const mapConfig = await configProvider();\n const mapModel = await createMapModel(\n mapId,\n mapConfig,\n this.#currentIntl,\n this.#httpService\n );\n return mapModel;\n }\n\n #isDynamic(mapId: string): boolean {\n return !this.#configProviders.has(mapId);\n }\n}\n\nasync function waitForResult(job: Promise<ModelJobResult>): Promise<MapModel> {\n return unbox(await job);\n}\n\nfunction unbox(entry: ModelJobResult): MapModel {\n if (entry.kind === \"error\") {\n throw entry.error;\n }\n return entry.model;\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MapRegistry.js","sources":["MapRegistry.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\n\nimport { batch, ReadonlyReactive } from \"@conterra/reactivity-core\";\nimport { on } from \"@conterra/reactivity-events\";\nimport { createLogger, Resource } from \"@open-pioneer/core\";\nimport { HttpService } from \"@open-pioneer/http\";\nimport {\n DECLARE_SERVICE_INTERFACE,\n PackageIntl,\n Service,\n ServiceOptions\n} from \"@open-pioneer/runtime\";\nimport OlMap from \"ol/Map\";\nimport { sourceId } from \"open-pioneer:source-info\";\nimport { LayerFactory } from \"./LayerFactory\";\nimport { createMapModel } from \"./model/createMapModel\";\nimport { MapConfig } from \"./model/MapConfig\";\nimport { MapModel } from \"./model/MapModel\";\n\nconst LOG = createLogger(sourceId);\n\n/**\n * Options passed to the {@link MapConfigProvider.getMapConfig} method.\n *\n * @group Services\n */\nexport interface MapConfigProviderOptions {\n /**\n * A reference to the layer factory, for the construction of new layer instances.\n */\n layerFactory: LayerFactory;\n}\n\n/**\n * Provides an OpenLayers map configuration with a given map id.\n *\n * The implementor must also provide the interface name `\"map.MapConfigProvider\"`.\n *\n * @group Services\n */\nexport interface MapConfigProvider {\n /**\n * Unique identifier of the map.\n */\n readonly mapId: string;\n\n /**\n * Returns the map configuration for this map.\n *\n * Called by the {@link MapRegistry} when the map is requested for the first time.\n *\n * See {@link MapConfig} for supported options during map creation.\n * Use {@link MapConfigProviderOptions.layerFactory} to construct new layers.\n */\n getMapConfig(options: MapConfigProviderOptions): Promise<MapConfig>;\n}\n\ninterface References {\n providers: MapConfigProvider[];\n httpService: HttpService;\n layerFactory: LayerFactory;\n}\n\ntype ModelJobResult =\n | { kind: \"model\"; model: MapModel; listener: Resource }\n | { kind: \"error\"; error: Error };\n\n/**\n * Provides access to registered map instances.\n *\n * Maps are identified by a unique id.\n *\n * Inject an instance of this service by referencing the interface name `\"map.MapRegistry\"`.\n *\n * @group Services\n */\nexport class MapRegistry implements Service {\n declare [DECLARE_SERVICE_INTERFACE]: \"map.MapRegistry\";\n\n #currentIntl: ReadonlyReactive<PackageIntl>;\n #httpService: HttpService;\n #layerFactory: LayerFactory;\n\n #configProviders = new Map<string, MapConfigProvider>();\n #entries = new Map<string, ModelJobResult>();\n #modelCreationJobs = new Map<string, Promise<ModelJobResult>>();\n #modelsByOlMap = new WeakMap<OlMap, MapModel>();\n #destroyed = false;\n\n constructor({ references, currentIntl }: ServiceOptions<References>) {\n this.#currentIntl = currentIntl;\n this.#httpService = references.httpService;\n this.#layerFactory = references.layerFactory;\n\n const providers = references.providers;\n for (const provider of providers) {\n this.#configProviders.set(provider.mapId, provider);\n }\n }\n\n destroy(): void {\n if (this.#destroyed) {\n return;\n }\n\n batch(() => {\n LOG.debug(`Destroy map registry and all maps`);\n this.#destroyed = true;\n this.#entries.forEach((entry) => {\n if (entry.kind === \"model\") {\n entry.listener.destroy();\n entry.model.destroy();\n }\n });\n this.#entries.clear();\n this.#modelCreationJobs.clear();\n });\n }\n\n /**\n * Returns the map model associated with the given id.\n * Returns undefined if there is no such model.\n */\n async getMapModel(mapId: string): Promise<MapModel | undefined> {\n if (this.#destroyed) {\n throw new Error(\"MapRegistry has already been destroyed.\");\n }\n\n const entry = this.#entries.get(mapId);\n if (entry) {\n return unbox(entry);\n }\n\n const creationJob = this.#modelCreationJobs.get(mapId);\n if (creationJob) {\n return await waitForResult(creationJob);\n }\n\n const provider = this.#configProviders.get(mapId);\n if (!provider) {\n LOG.debug(`Failed to find a config provider for map id '${mapId}'.`);\n return undefined;\n }\n\n return await this.#createMapModel(mapId, () =>\n provider.getMapConfig({\n layerFactory: this.#layerFactory\n })\n );\n }\n\n /**\n * Like {@link getMapModel}, but throws if no model exists for the given `mapId`.\n */\n async expectMapModel(mapId: string): Promise<MapModel> {\n const model = await this.getMapModel(mapId);\n if (!model) {\n throw new Error(`No configuration available for map with id '${mapId}'.`);\n }\n return model;\n }\n\n /**\n * Creates a MapModel without the need to provide a {@link MapConfigProvider}.\n * Throws an error if a map with the given id already exists or if the map config is invalid.\n */\n async createMapModel(mapId: string, options?: MapConfig): Promise<MapModel> {\n if (this.#destroyed) {\n throw new Error(\"MapRegistry has already been destroyed.\");\n }\n if (this.#entries.has(mapId)) {\n throw new Error(`Map id '${mapId}' is not unique.`);\n }\n if (this.#modelCreationJobs.has(mapId)) {\n throw new Error(`A map with the id '${mapId}' is already under construction.`);\n }\n return await this.#createMapModel(mapId, () => Promise.resolve(options ?? {}));\n }\n\n /**\n * Given a raw OpenLayers map instance, returns the associated {@link MapModel} - or undefined\n * if the map is unknown to this registry.\n *\n * All OpenLayers maps created by this registry (e.g. via {@link MapConfigProvider} or {@link createMapModel}) have an associated map model.\n */\n getMapModelByRawInstance(olMap: OlMap): MapModel | undefined {\n return this.#modelsByOlMap.get(olMap);\n }\n\n // Wrapper method to ensure that in-progress construction of maps can be observed.\n #createMapModel(mapId: string, configProvider: () => Promise<MapConfig>): Promise<MapModel> {\n const creationJob = this.#modelCreationJobs.get(mapId);\n if (creationJob) {\n throw new Error(\"Internal error: a map model is already being created for this mapId\");\n }\n\n const modelPromise = this.#createMapModelImpl(mapId, configProvider)\n .then((mapModel) => {\n if (this.#destroyed) {\n mapModel.destroy();\n throw new Error(`MapRegistry has been destroyed.`);\n }\n\n const listener = on(\n mapModel.destroyed,\n () => {\n // Allow id reuse for dynamically created maps\n if (this.#isDynamic(mapId)) {\n const currentEntry = this.#entries.get(mapId);\n if (currentEntry === entry) {\n this.#entries.delete(mapId);\n }\n }\n },\n { dispatch: \"sync\" }\n );\n\n const entry: ModelJobResult = { kind: \"model\", model: mapModel, listener };\n this.#entries.set(mapId, entry);\n this.#modelCreationJobs.delete(mapId);\n this.#modelsByOlMap.set(mapModel.olMap, mapModel);\n return entry;\n })\n .catch((cause) => {\n const error = new Error(`Failed to construct map '${mapId}'`, { cause });\n const entry: ModelJobResult = { kind: \"error\", error };\n this.#modelCreationJobs.delete(mapId);\n if (!this.#isDynamic(mapId)) {\n // Don't store errors for dynamically created maps (the caller already got the error via promise).\n this.#entries.set(mapId, entry);\n }\n return entry;\n });\n this.#modelCreationJobs.set(mapId, modelPromise);\n return waitForResult(modelPromise);\n }\n\n async #createMapModelImpl(\n mapId: string,\n configProvider: () => Promise<MapConfig>\n ): Promise<MapModel> {\n LOG.info(`Creating map with id '${mapId}'`);\n const mapConfig = await configProvider();\n const mapModel = await createMapModel(\n mapId,\n mapConfig,\n this.#currentIntl,\n this.#httpService\n );\n return mapModel;\n }\n\n #isDynamic(mapId: string): boolean {\n return !this.#configProviders.has(mapId);\n }\n}\n\nasync function waitForResult(job: Promise<ModelJobResult>): Promise<MapModel> {\n return unbox(await job);\n}\n\nfunction unbox(entry: ModelJobResult): MapModel {\n if (entry.kind === \"error\") {\n throw entry.error;\n }\n return entry.model;\n}\n"],"names":[],"mappings":"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"}
|
package/README.md
CHANGED
|
@@ -325,7 +325,6 @@ layerFactory.create({
|
|
|
325
325
|
// Any properties supported by the layer type
|
|
326
326
|
title: "OSM",
|
|
327
327
|
id: "osm",
|
|
328
|
-
isBaseLayer: true,
|
|
329
328
|
olLayer: new TileLayer({
|
|
330
329
|
source: new OSM()
|
|
331
330
|
})
|
|
@@ -348,7 +347,7 @@ import OSM from "ol/source/OSM";
|
|
|
348
347
|
export class MapConfigProviderImpl implements MapConfigProvider {
|
|
349
348
|
async getMapConfig({ layerFactory }: MapConfigProviderOptions): Promise<MapConfig> {
|
|
350
349
|
return {
|
|
351
|
-
|
|
350
|
+
baseLayers: [
|
|
352
351
|
layerFactory.create({
|
|
353
352
|
// minimal layer configuration
|
|
354
353
|
type: SimpleLayer,
|
|
@@ -356,7 +355,9 @@ export class MapConfigProviderImpl implements MapConfigProvider {
|
|
|
356
355
|
olLayer: new TileLayer({
|
|
357
356
|
source: new OSM()
|
|
358
357
|
})
|
|
359
|
-
})
|
|
358
|
+
})
|
|
359
|
+
],
|
|
360
|
+
layers: [
|
|
360
361
|
layerFactory.create({
|
|
361
362
|
// layer configuration with optional properties
|
|
362
363
|
type: SimpleLayer,
|
|
@@ -369,7 +370,6 @@ export class MapConfigProviderImpl implements MapConfigProvider {
|
|
|
369
370
|
foo: "bar"
|
|
370
371
|
},
|
|
371
372
|
description: "additional description",
|
|
372
|
-
isBaseLayer: false,
|
|
373
373
|
visible: false
|
|
374
374
|
})
|
|
375
375
|
]
|
|
@@ -442,7 +442,6 @@ export class MapConfigProviderImpl implements MapConfigProvider {
|
|
|
442
442
|
// check layer availability by requesting the provided URL
|
|
443
443
|
healthCheck:
|
|
444
444
|
"https://sgx.geodatenzentrum.de/wmts_topplus_open/1.0.0/WMTSCapabilities.xml",
|
|
445
|
-
isBaseLayer: false,
|
|
446
445
|
visible: true
|
|
447
446
|
}),
|
|
448
447
|
layerFactory.create({
|
|
@@ -461,7 +460,6 @@ export class MapConfigProviderImpl implements MapConfigProvider {
|
|
|
461
460
|
await wait(3000);
|
|
462
461
|
return "error";
|
|
463
462
|
},
|
|
464
|
-
isBaseLayer: false,
|
|
465
463
|
visible: false
|
|
466
464
|
})
|
|
467
465
|
]
|
|
@@ -604,12 +602,11 @@ export class MapConfigProviderImpl implements MapConfigProvider {
|
|
|
604
602
|
zoom: 14
|
|
605
603
|
},
|
|
606
604
|
projection: "EPSG:31466",
|
|
607
|
-
|
|
605
|
+
baseLayers: [
|
|
608
606
|
layerFactory.create({
|
|
609
607
|
type: SimpleLayer,
|
|
610
608
|
id: "topplus_open",
|
|
611
609
|
title: "TopPlus Open",
|
|
612
|
-
isBaseLayer: true,
|
|
613
610
|
visible: true,
|
|
614
611
|
olLayer: new TileLayer({
|
|
615
612
|
source: createWMTSSource("web")
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import OlBaseLayer from "ol/layer/Base";
|
|
2
|
+
import OlSource from "ol/source/Source";
|
|
2
3
|
import { MapModel } from "../model/MapModel";
|
|
3
4
|
import { InternalConstructorTag } from "../utils/InternalConstructorTag";
|
|
4
5
|
import { AbstractLayerBase } from "./AbstractLayerBase";
|
|
5
|
-
import { ATTACH_TO_MAP, GET_DEPS, LayerDependencies, SET_VISIBLE } from "./shared/internals";
|
|
6
|
+
import { ATTACH_TO_MAP, DECLARED_AS_BASE_LAYER, GET_DEPS, LayerDependencies, SET_METADATA_LOAD_INFO, SET_VISIBLE } from "./shared/internals";
|
|
6
7
|
import { SimpleLayerConfig } from "./SimpleLayer";
|
|
7
8
|
import { LayerTypes } from "./unions";
|
|
8
9
|
/**
|
|
@@ -11,6 +12,15 @@ import { LayerTypes } from "./unions";
|
|
|
11
12
|
* @group Layer Utilities
|
|
12
13
|
**/
|
|
13
14
|
export type LayerLoadState = "not-loaded" | "loading" | "loaded" | "error";
|
|
15
|
+
/**
|
|
16
|
+
* Load state of a single layer, bundling the state with its error.
|
|
17
|
+
*
|
|
18
|
+
* @internal
|
|
19
|
+
*/
|
|
20
|
+
export type LayerLoadInfo = "not-loaded" | "loading" | "loaded" | {
|
|
21
|
+
kind: "error";
|
|
22
|
+
error: Error;
|
|
23
|
+
};
|
|
14
24
|
/**
|
|
15
25
|
* Represents an operational layer in the map.
|
|
16
26
|
*
|
|
@@ -23,7 +33,10 @@ export type LayerLoadState = "not-loaded" | "loading" | "loaded" | "error";
|
|
|
23
33
|
*/
|
|
24
34
|
export declare abstract class AbstractLayer extends AbstractLayerBase {
|
|
25
35
|
#private;
|
|
26
|
-
constructor(config: SimpleLayerConfig
|
|
36
|
+
constructor(config: SimpleLayerConfig & {
|
|
37
|
+
/** The initial load state (default: not-loaded). */
|
|
38
|
+
initialLoadInfo?: LayerLoadInfo;
|
|
39
|
+
}, deps?: LayerDependencies, internalTag?: InternalConstructorTag);
|
|
27
40
|
destroy(): void;
|
|
28
41
|
/**
|
|
29
42
|
* Identifies the type of this layer.
|
|
@@ -34,6 +47,10 @@ export declare abstract class AbstractLayer extends AbstractLayerBase {
|
|
|
34
47
|
* The raw OpenLayers layer.
|
|
35
48
|
*/
|
|
36
49
|
get olLayer(): OlBaseLayer;
|
|
50
|
+
/**
|
|
51
|
+
* The current source of the {@link olLayer}.
|
|
52
|
+
*/
|
|
53
|
+
get olSource(): OlSource | undefined;
|
|
37
54
|
/**
|
|
38
55
|
* True if this layer is a base layer.
|
|
39
56
|
*
|
|
@@ -41,9 +58,19 @@ export declare abstract class AbstractLayer extends AbstractLayerBase {
|
|
|
41
58
|
*/
|
|
42
59
|
get isBaseLayer(): boolean;
|
|
43
60
|
/**
|
|
44
|
-
* The load state of a layer.
|
|
61
|
+
* The combined load state of a layer.
|
|
62
|
+
*
|
|
63
|
+
* Aggregates the OpenLayers source state, health check and metadata state.
|
|
64
|
+
* Priority for the state: `error` > `loading` > `not-loaded` > `loaded`.
|
|
45
65
|
*/
|
|
46
66
|
get loadState(): LayerLoadState;
|
|
67
|
+
/**
|
|
68
|
+
* The error (if any) that prevented this layer from loading.
|
|
69
|
+
*
|
|
70
|
+
* Combines errors from the OpenLayers source, the health check and the
|
|
71
|
+
* metadata request (health > metadata > source).
|
|
72
|
+
*/
|
|
73
|
+
get loadError(): Error | undefined;
|
|
47
74
|
/**
|
|
48
75
|
* The minimum resolution (inclusive) at which this layer will be visible.
|
|
49
76
|
*/
|
|
@@ -86,9 +113,20 @@ export declare abstract class AbstractLayer extends AbstractLayerBase {
|
|
|
86
113
|
* @internal
|
|
87
114
|
*/
|
|
88
115
|
[ATTACH_TO_MAP](map: MapModel): void;
|
|
116
|
+
/**
|
|
117
|
+
* Updates the load state of the layer's metadata request.
|
|
118
|
+
*
|
|
119
|
+
* @internal
|
|
120
|
+
*/
|
|
121
|
+
[SET_METADATA_LOAD_INFO](loadInfo: LayerLoadInfo): void;
|
|
89
122
|
setVisible(newVisibility: boolean): void;
|
|
90
123
|
/** @internal */
|
|
91
124
|
[SET_VISIBLE](newVisibility: boolean): void;
|
|
92
125
|
/** @internal */
|
|
93
126
|
[GET_DEPS](): LayerDependencies;
|
|
127
|
+
/**
|
|
128
|
+
* Always returns original, configured `isBaseLayer` value from LayerConfig instead of computed value from `get isBaseLayer()`
|
|
129
|
+
*
|
|
130
|
+
* @internal */
|
|
131
|
+
get [DECLARED_AS_BASE_LAYER](): boolean | undefined;
|
|
94
132
|
}
|
package/layers/AbstractLayer.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { synchronized, reactive,
|
|
2
|
-
import { createLogger
|
|
1
|
+
import { computed, synchronized, reactive, constant } from '@conterra/reactivity-core';
|
|
2
|
+
import { createLogger } from '@open-pioneer/core';
|
|
3
3
|
import OlLayer from 'ol/layer/Layer.js';
|
|
4
4
|
import { unByKey } from 'ol/Observable.js';
|
|
5
5
|
import { sourceId } from '../_virtual/source-info.js';
|
|
6
6
|
import { AbstractLayerBase } from './AbstractLayerBase.js';
|
|
7
|
-
import { getLayerDependencies, SET_VISIBLE, ATTACH_TO_MAP, GET_DEPS, LAYER_DEPS } from './shared/internals.js';
|
|
7
|
+
import { getLayerDependencies, SET_VISIBLE, ATTACH_TO_MAP, SET_METADATA_LOAD_INFO, GET_DEPS, LAYER_DEPS, DECLARED_AS_BASE_LAYER } from './shared/internals.js';
|
|
8
8
|
|
|
9
9
|
const LOG = createLogger(sourceId);
|
|
10
10
|
class AbstractLayer extends AbstractLayerBase {
|
|
@@ -13,22 +13,37 @@ class AbstractLayer extends AbstractLayerBase {
|
|
|
13
13
|
// from the map, once connected).
|
|
14
14
|
#deps;
|
|
15
15
|
#olLayer;
|
|
16
|
-
#
|
|
16
|
+
#olSource;
|
|
17
|
+
#declaredAsBaseLayer;
|
|
18
|
+
//original value from LayerConfig, only used internally
|
|
17
19
|
#healthCheck;
|
|
20
|
+
#isBaseLayer;
|
|
18
21
|
#visible;
|
|
19
22
|
#minResolution;
|
|
20
23
|
#maxResolution;
|
|
21
24
|
#minZoom;
|
|
22
25
|
#maxZoom;
|
|
23
|
-
#
|
|
24
|
-
#
|
|
26
|
+
#sourceState;
|
|
27
|
+
#sourceInfo;
|
|
28
|
+
#healthInfo;
|
|
29
|
+
#healthCheckStarted = false;
|
|
30
|
+
#metadataInfo;
|
|
31
|
+
#loadInfo = computed(
|
|
32
|
+
() => combineLoadInfos(this.#sourceInfo.value, this.#healthInfo.value, this.#metadataInfo.value)
|
|
33
|
+
);
|
|
25
34
|
#visibleInScale;
|
|
26
35
|
constructor(config, deps, internalTag) {
|
|
27
36
|
super(config);
|
|
28
37
|
this.#deps = getLayerDependencies(deps, internalTag);
|
|
29
38
|
this.#olLayer = config.olLayer;
|
|
30
|
-
this.#
|
|
39
|
+
this.#olSource = synchronizedOlSource(this.#olLayer);
|
|
40
|
+
this.#declaredAsBaseLayer = config.isBaseLayer;
|
|
31
41
|
this.#healthCheck = config.healthCheck;
|
|
42
|
+
this.#isBaseLayer = computed(() => {
|
|
43
|
+
const effective = this.nullableMap?.layers.getBaseLayers().includes(this);
|
|
44
|
+
const declared = this.#declaredAsBaseLayer;
|
|
45
|
+
return effective || declared || false;
|
|
46
|
+
});
|
|
32
47
|
this.#visible = synchronized(
|
|
33
48
|
() => this.#olLayer.getVisible(),
|
|
34
49
|
(cb) => {
|
|
@@ -64,7 +79,22 @@ class AbstractLayer extends AbstractLayerBase {
|
|
|
64
79
|
return () => unByKey(key);
|
|
65
80
|
}
|
|
66
81
|
);
|
|
67
|
-
this.#
|
|
82
|
+
this.#sourceState = computed(() => {
|
|
83
|
+
const olSource = this.olSource;
|
|
84
|
+
if (!olSource) {
|
|
85
|
+
return void 0;
|
|
86
|
+
}
|
|
87
|
+
return synchronized(
|
|
88
|
+
() => getSourceState(olSource),
|
|
89
|
+
(cb) => {
|
|
90
|
+
const key = olSource.on("change", cb);
|
|
91
|
+
return () => unByKey(key);
|
|
92
|
+
}
|
|
93
|
+
);
|
|
94
|
+
});
|
|
95
|
+
this.#sourceInfo = computed(() => makeSourceInfo(this.id, this.#sourceState.value?.value));
|
|
96
|
+
this.#healthInfo = reactive("not-loaded");
|
|
97
|
+
this.#metadataInfo = reactive(config.initialLoadInfo ?? "not-loaded");
|
|
68
98
|
this[SET_VISIBLE](config.visible ?? true);
|
|
69
99
|
this.#visibleInScale = computed(() => {
|
|
70
100
|
const map = this.nullableMap;
|
|
@@ -102,7 +132,6 @@ class AbstractLayer extends AbstractLayerBase {
|
|
|
102
132
|
if (this.isDestroyed) {
|
|
103
133
|
return;
|
|
104
134
|
}
|
|
105
|
-
this.#stateWatchResource = destroyResource(this.#stateWatchResource);
|
|
106
135
|
this.olLayer.dispose();
|
|
107
136
|
super.destroy();
|
|
108
137
|
}
|
|
@@ -115,19 +144,37 @@ class AbstractLayer extends AbstractLayerBase {
|
|
|
115
144
|
get olLayer() {
|
|
116
145
|
return this.#olLayer;
|
|
117
146
|
}
|
|
147
|
+
/**
|
|
148
|
+
* The current source of the {@link olLayer}.
|
|
149
|
+
*/
|
|
150
|
+
get olSource() {
|
|
151
|
+
return this.#olSource.value;
|
|
152
|
+
}
|
|
118
153
|
/**
|
|
119
154
|
* True if this layer is a base layer.
|
|
120
155
|
*
|
|
121
156
|
* Only one base layer can be visible at a time.
|
|
122
157
|
*/
|
|
123
158
|
get isBaseLayer() {
|
|
124
|
-
return this.#isBaseLayer;
|
|
159
|
+
return this.#isBaseLayer.value;
|
|
125
160
|
}
|
|
126
161
|
/**
|
|
127
|
-
* The load state of a layer.
|
|
162
|
+
* The combined load state of a layer.
|
|
163
|
+
*
|
|
164
|
+
* Aggregates the OpenLayers source state, health check and metadata state.
|
|
165
|
+
* Priority for the state: `error` > `loading` > `not-loaded` > `loaded`.
|
|
128
166
|
*/
|
|
129
167
|
get loadState() {
|
|
130
|
-
return this.#
|
|
168
|
+
return loadInfoState(this.#loadInfo.value);
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* The error (if any) that prevented this layer from loading.
|
|
172
|
+
*
|
|
173
|
+
* Combines errors from the OpenLayers source, the health check and the
|
|
174
|
+
* metadata request (health > metadata > source).
|
|
175
|
+
*/
|
|
176
|
+
get loadError() {
|
|
177
|
+
return errorOf(this.#loadInfo.value);
|
|
131
178
|
}
|
|
132
179
|
/**
|
|
133
180
|
* The minimum resolution (inclusive) at which this layer will be visible.
|
|
@@ -190,18 +237,21 @@ class AbstractLayer extends AbstractLayerBase {
|
|
|
190
237
|
*/
|
|
191
238
|
[ATTACH_TO_MAP](map) {
|
|
192
239
|
super[ATTACH_TO_MAP](map);
|
|
193
|
-
if (!this.#
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
this.#
|
|
197
|
-
|
|
198
|
-
this.#loadState.value = state;
|
|
199
|
-
}
|
|
200
|
-
);
|
|
201
|
-
this.#stateWatchResource = stateWatchResource;
|
|
202
|
-
this.#loadState.value = initialState;
|
|
240
|
+
if (!this.#healthCheckStarted && errorOf(this.#sourceInfo.value) == null) {
|
|
241
|
+
this.#healthCheckStarted = true;
|
|
242
|
+
doHealthCheck(this, this.#healthCheck).then((loadInfo) => {
|
|
243
|
+
this.#healthInfo.value = loadInfo;
|
|
244
|
+
});
|
|
203
245
|
}
|
|
204
246
|
}
|
|
247
|
+
/**
|
|
248
|
+
* Updates the load state of the layer's metadata request.
|
|
249
|
+
*
|
|
250
|
+
* @internal
|
|
251
|
+
*/
|
|
252
|
+
[SET_METADATA_LOAD_INFO](loadInfo) {
|
|
253
|
+
this.#metadataInfo.value = loadInfo;
|
|
254
|
+
}
|
|
205
255
|
setVisible(newVisibility) {
|
|
206
256
|
if (this.isBaseLayer) {
|
|
207
257
|
LOG.warn(
|
|
@@ -232,58 +282,13 @@ class AbstractLayer extends AbstractLayerBase {
|
|
|
232
282
|
+ "Use the LayerFactory to create an instance or add the layer to the map first.`
|
|
233
283
|
);
|
|
234
284
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
resource: {
|
|
242
|
-
destroy() {
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
};
|
|
246
|
-
}
|
|
247
|
-
let currentSource = getSource(olLayer);
|
|
248
|
-
const currentOlLayerState = getSourceState(currentSource);
|
|
249
|
-
let currentLoadState = currentOlLayerState;
|
|
250
|
-
let currentHealthState = "loading";
|
|
251
|
-
if (currentOlLayerState !== "error") {
|
|
252
|
-
doHealthCheck(layer, healthCheck).then((state) => {
|
|
253
|
-
currentHealthState = state;
|
|
254
|
-
updateState();
|
|
255
|
-
});
|
|
285
|
+
/**
|
|
286
|
+
* Always returns original, configured `isBaseLayer` value from LayerConfig instead of computed value from `get isBaseLayer()`
|
|
287
|
+
*
|
|
288
|
+
* @internal */
|
|
289
|
+
get [DECLARED_AS_BASE_LAYER]() {
|
|
290
|
+
return this.#declaredAsBaseLayer;
|
|
256
291
|
}
|
|
257
|
-
const updateState = () => {
|
|
258
|
-
const olLayerState = getSourceState(currentSource);
|
|
259
|
-
const nextLoadState = currentHealthState === "error" ? "error" : olLayerState;
|
|
260
|
-
if (currentLoadState !== nextLoadState) {
|
|
261
|
-
currentLoadState = nextLoadState;
|
|
262
|
-
onChange(currentLoadState);
|
|
263
|
-
}
|
|
264
|
-
};
|
|
265
|
-
let stateHandle;
|
|
266
|
-
stateHandle = currentSource?.on("change", () => {
|
|
267
|
-
updateState();
|
|
268
|
-
});
|
|
269
|
-
const sourceHandle = olLayer.on("change:source", () => {
|
|
270
|
-
stateHandle && unByKey(stateHandle);
|
|
271
|
-
stateHandle = void 0;
|
|
272
|
-
currentSource = getSource(olLayer);
|
|
273
|
-
stateHandle = currentSource?.on("change", () => {
|
|
274
|
-
updateState();
|
|
275
|
-
});
|
|
276
|
-
updateState();
|
|
277
|
-
});
|
|
278
|
-
return {
|
|
279
|
-
initial: currentLoadState,
|
|
280
|
-
resource: {
|
|
281
|
-
destroy() {
|
|
282
|
-
stateHandle && unByKey(stateHandle);
|
|
283
|
-
unByKey(sourceHandle);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
};
|
|
287
292
|
}
|
|
288
293
|
async function doHealthCheck(layer, healthCheck) {
|
|
289
294
|
if (healthCheck == null) {
|
|
@@ -309,23 +314,76 @@ async function doHealthCheck(layer, healthCheck) {
|
|
|
309
314
|
`Unexpected object for 'healthCheck' parameter of layer '${layer.id}'`,
|
|
310
315
|
healthCheck
|
|
311
316
|
);
|
|
312
|
-
return
|
|
317
|
+
return {
|
|
318
|
+
kind: "error",
|
|
319
|
+
error: new Error(`Invalid 'healthCheck' configuration for layer '${layer.id}'`)
|
|
320
|
+
};
|
|
313
321
|
}
|
|
314
322
|
try {
|
|
315
|
-
|
|
323
|
+
const state = await healthCheckFn(layer);
|
|
324
|
+
if (state === "error") {
|
|
325
|
+
return {
|
|
326
|
+
kind: "error",
|
|
327
|
+
error: new Error(`Health check failed for layer '${layer.id}'`)
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
return state;
|
|
316
331
|
} catch (e) {
|
|
317
332
|
LOG.warn(`Health check failed for layer '${layer.id}'`, e);
|
|
318
|
-
return
|
|
333
|
+
return {
|
|
334
|
+
kind: "error",
|
|
335
|
+
error: e instanceof Error ? e : new Error(String(e))
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
const LOAD_STATE_SEVERITY = {
|
|
340
|
+
"not-loaded": 0,
|
|
341
|
+
loaded: 1,
|
|
342
|
+
loading: 2,
|
|
343
|
+
error: 3
|
|
344
|
+
};
|
|
345
|
+
function higherSeverity(a, b) {
|
|
346
|
+
return LOAD_STATE_SEVERITY[a] >= LOAD_STATE_SEVERITY[b] ? a : b;
|
|
347
|
+
}
|
|
348
|
+
function combineLoadInfos(source, health, metadata) {
|
|
349
|
+
const error = errorOf(health) ?? errorOf(metadata) ?? errorOf(source);
|
|
350
|
+
if (error) {
|
|
351
|
+
return { kind: "error", error };
|
|
319
352
|
}
|
|
353
|
+
return higherSeverity(loadInfoState(source), loadInfoState(metadata));
|
|
320
354
|
}
|
|
321
|
-
function
|
|
322
|
-
|
|
323
|
-
|
|
355
|
+
function errorOf(info) {
|
|
356
|
+
return typeof info === "object" ? info.error : void 0;
|
|
357
|
+
}
|
|
358
|
+
function loadInfoState(info) {
|
|
359
|
+
return typeof info === "object" ? "error" : info;
|
|
360
|
+
}
|
|
361
|
+
function makeSourceInfo(id, state) {
|
|
362
|
+
if (state == null) {
|
|
363
|
+
return "loaded";
|
|
324
364
|
}
|
|
325
|
-
|
|
365
|
+
if (state === "error") {
|
|
366
|
+
return {
|
|
367
|
+
kind: "error",
|
|
368
|
+
error: new Error(`Source of layer '${id}' is in error state`)
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
return state;
|
|
372
|
+
}
|
|
373
|
+
function synchronizedOlSource(layer) {
|
|
374
|
+
if (!(layer instanceof OlLayer)) {
|
|
375
|
+
return constant(void 0);
|
|
376
|
+
}
|
|
377
|
+
return synchronized(
|
|
378
|
+
() => layer.getSource() ?? void 0,
|
|
379
|
+
(cb) => {
|
|
380
|
+
const key = layer.on("change:source", cb);
|
|
381
|
+
return () => unByKey(key);
|
|
382
|
+
}
|
|
383
|
+
);
|
|
326
384
|
}
|
|
327
385
|
function getSourceState(olSource) {
|
|
328
|
-
const state = olSource
|
|
386
|
+
const state = olSource.getState();
|
|
329
387
|
switch (state) {
|
|
330
388
|
case void 0:
|
|
331
389
|
return "loaded";
|