@open-pioneer/map 0.1.0 → 0.2.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/CHANGELOG.md CHANGED
@@ -1,12 +1,32 @@
1
1
  # @open-pioneer/map
2
2
 
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 70349a8: Update to new core packages major versions
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [70349a8]
12
+ - @open-pioneer/react-utils@0.2.0
13
+
14
+ ## 0.1.1
15
+
16
+ ### Patch Changes
17
+
18
+ - 08bffbc: MapModel API has got new methods for zooming/highlighting
19
+ - a58546b: Use `HttpService` for default health checks made by the map model.
20
+ - a58546b: Use `HttpService` when loading images in WMSLayer.
21
+ - 0c4ce04: Add OGC API Tiles (vector tiles) support
22
+
3
23
  ## 0.1.0
4
24
 
5
25
  ### Minor Changes
6
26
 
7
- - bb2f27a: Initial release.
27
+ - bb2f27a: Initial release.
8
28
 
9
29
  ### Patch Changes
10
30
 
11
- - Updated dependencies [182da1c]
12
- - @open-pioneer/react-utils@0.1.0
31
+ - Updated dependencies [182da1c]
32
+ - @open-pioneer/react-utils@0.1.0
@@ -1,12 +1,14 @@
1
- import { Service, ServiceOptions, ServiceType } from "@open-pioneer/runtime";
1
+ import { Service, ServiceOptions } from "@open-pioneer/runtime";
2
2
  import OlMap from "ol/Map";
3
- import { MapModel, MapRegistry } from "./api";
3
+ import { MapConfigProvider, MapModel, MapRegistry } from "./api";
4
+ import { HttpService } from "@open-pioneer/http";
4
5
  interface References {
5
- providers: ServiceType<"map.MapConfigProvider">[];
6
+ providers: MapConfigProvider[];
7
+ httpService: HttpService;
6
8
  }
7
9
  export declare class MapRegistryImpl implements Service, MapRegistry {
8
10
  #private;
9
- constructor(options: ServiceOptions<References>);
11
+ constructor({ references }: ServiceOptions<References>);
10
12
  destroy(): void;
11
13
  getMapModel(mapId: string): Promise<MapModel | undefined>;
12
14
  expectMapModel(mapId: string): Promise<MapModel>;
@@ -3,13 +3,15 @@ import { createMapModel } from './model/createMapModel.js';
3
3
 
4
4
  const LOG = createLogger("map:MapRegistry");
5
5
  class MapRegistryImpl {
6
+ #httpService;
6
7
  #configProviders = /* @__PURE__ */ new Map();
7
8
  #entries = /* @__PURE__ */ new Map();
8
9
  #modelCreationJobs = /* @__PURE__ */ new Map();
9
10
  #modelsByOlMap = /* @__PURE__ */ new WeakMap();
10
11
  #destroyed = false;
11
- constructor(options) {
12
- const providers = options.references.providers;
12
+ constructor({ references }) {
13
+ this.#httpService = references.httpService;
14
+ const providers = references.providers;
13
15
  for (const provider of providers) {
14
16
  this.#configProviders.set(provider.mapId, provider);
15
17
  }
@@ -66,7 +68,7 @@ class MapRegistryImpl {
66
68
  async #createModel(mapId, provider) {
67
69
  LOG.info(`Creating map with id '${mapId}'`);
68
70
  const mapConfig = await provider.getMapConfig();
69
- const mapModel = await createMapModel(mapId, mapConfig);
71
+ const mapModel = await createMapModel(mapId, mapConfig, this.#httpService);
70
72
  if (this.#destroyed) {
71
73
  mapModel.destroy();
72
74
  throw new Error(`MapRegistry has been destroyed.`);
@@ -1 +1 @@
1
- {"version":3,"file":"MapRegistryImpl.js","sources":["MapRegistryImpl.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { createLogger } from \"@open-pioneer/core\";\nimport { Service, ServiceOptions, ServiceType } from \"@open-pioneer/runtime\";\nimport OlMap from \"ol/Map\";\nimport { MapModelImpl } from \"./model/MapModelImpl\";\nimport { MapConfigProvider, MapModel, MapRegistry } from \"./api\";\nimport { createMapModel } from \"./model/createMapModel\";\n\nconst LOG = createLogger(\"map:MapRegistry\");\n\ninterface References {\n providers: ServiceType<\"map.MapConfigProvider\">[];\n}\n\ntype ModelJobResult = { kind: \"model\"; model: MapModelImpl } | { kind: \"error\"; error: Error };\n\nexport class MapRegistryImpl implements Service, MapRegistry {\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(options: ServiceOptions<References>) {\n const providers = options.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 LOG.info(`Destroy map registry and all maps`);\n this.#destroyed = true;\n this.#entries.forEach((model) => {\n model.kind === \"model\" && model.model.destroy();\n });\n this.#entries.clear();\n this.#modelCreationJobs.clear();\n }\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 creationJob = this.#modelCreationJobs.get(mapId);\n if (creationJob) {\n return unbox(await creationJob);\n }\n\n const entry = this.#entries.get(mapId);\n if (entry) {\n return unbox(entry);\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 const modelPromise = this.#createModel(mapId, provider).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 this.#entries.set(mapId, entry);\n return entry;\n });\n this.#modelCreationJobs.set(mapId, modelPromise);\n return unbox(await modelPromise);\n }\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 getMapModelByRawInstance(olMap: OlMap): MapModel | undefined {\n return this.#modelsByOlMap.get(olMap);\n }\n\n async #createModel(mapId: string, provider: MapConfigProvider): Promise<ModelJobResult> {\n LOG.info(`Creating map with id '${mapId}'`);\n const mapConfig = await provider.getMapConfig();\n const mapModel = await createMapModel(mapId, mapConfig);\n\n if (this.#destroyed) {\n mapModel.destroy();\n throw new Error(`MapRegistry has been destroyed.`);\n }\n\n const entry: ModelJobResult = { kind: \"model\", model: mapModel };\n this.#entries.set(mapId, entry);\n this.#modelCreationJobs.delete(mapId);\n this.#modelsByOlMap.set(mapModel.olMap, mapModel);\n return entry;\n }\n}\n\nfunction unbox(entry: ModelJobResult): MapModelImpl {\n if (entry.kind === \"error\") {\n throw entry.error;\n }\n return entry.model;\n}\n"],"names":["entry"],"mappings":"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"}
1
+ {"version":3,"file":"MapRegistryImpl.js","sources":["MapRegistryImpl.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { createLogger } from \"@open-pioneer/core\";\nimport { Service, ServiceOptions } from \"@open-pioneer/runtime\";\nimport OlMap from \"ol/Map\";\nimport { MapModelImpl } from \"./model/MapModelImpl\";\nimport { MapConfigProvider, MapModel, MapRegistry } from \"./api\";\nimport { createMapModel } from \"./model/createMapModel\";\nimport { HttpService } from \"@open-pioneer/http\";\n\nconst LOG = createLogger(\"map:MapRegistry\");\n\ninterface References {\n providers: MapConfigProvider[];\n httpService: HttpService;\n}\n\ntype ModelJobResult = { kind: \"model\"; model: MapModelImpl } | { kind: \"error\"; error: Error };\n\nexport class MapRegistryImpl implements Service, MapRegistry {\n #httpService: HttpService;\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 }: ServiceOptions<References>) {\n this.#httpService = references.httpService;\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 LOG.info(`Destroy map registry and all maps`);\n this.#destroyed = true;\n this.#entries.forEach((model) => {\n model.kind === \"model\" && model.model.destroy();\n });\n this.#entries.clear();\n this.#modelCreationJobs.clear();\n }\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 creationJob = this.#modelCreationJobs.get(mapId);\n if (creationJob) {\n return unbox(await creationJob);\n }\n\n const entry = this.#entries.get(mapId);\n if (entry) {\n return unbox(entry);\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 const modelPromise = this.#createModel(mapId, provider).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 this.#entries.set(mapId, entry);\n return entry;\n });\n this.#modelCreationJobs.set(mapId, modelPromise);\n return unbox(await modelPromise);\n }\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 getMapModelByRawInstance(olMap: OlMap): MapModel | undefined {\n return this.#modelsByOlMap.get(olMap);\n }\n\n async #createModel(mapId: string, provider: MapConfigProvider): Promise<ModelJobResult> {\n LOG.info(`Creating map with id '${mapId}'`);\n const mapConfig = await provider.getMapConfig();\n const mapModel = await createMapModel(mapId, mapConfig, this.#httpService);\n\n if (this.#destroyed) {\n mapModel.destroy();\n throw new Error(`MapRegistry has been destroyed.`);\n }\n\n const entry: ModelJobResult = { kind: \"model\", model: mapModel };\n this.#entries.set(mapId, entry);\n this.#modelCreationJobs.delete(mapId);\n this.#modelsByOlMap.set(mapModel.olMap, mapModel);\n return entry;\n }\n}\n\nfunction unbox(entry: ModelJobResult): MapModelImpl {\n if (entry.kind === \"error\") {\n throw entry.error;\n }\n return entry.model;\n}\n"],"names":["entry"],"mappings":"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"}
package/README.md CHANGED
@@ -258,6 +258,65 @@ layer.updateAttributes({
258
258
  layer.deleteAttribute("foo");
259
259
  ```
260
260
 
261
+ An optional property `healthCheck` allows to determine the availability status of a layer (e.g. map service down). The health check is performed asynchronous.
262
+
263
+ It is possible to provide
264
+
265
+ - either a URL to perform a test request check the returned HTTP status
266
+ - or a `HealthCheckFunction` performing a custom check and returning the state
267
+
268
+ **Important**: The availability of a layer is only checked once during initialization to reduce the load on server side. If a service becomes available again later, the application will need to be reloaded in order to update the availability status.
269
+
270
+ The availability status of a layer can be accessed with the property `loadState`. Its value depends on the result of the health check and the OpenLayers `Source` of the layer. If at least one of both checks returns the state `error`, the `loadState` will be set to `error`.
271
+
272
+ Example: Check of layer availability ("health check")
273
+
274
+ ```ts
275
+ // YOUR-APP/MapConfigProviderImpl.ts
276
+ import { MapConfig, MapConfigProvider, SimpleLayer } from "@open-pioneer/map";
277
+ import TileLayer from "ol/layer/Tile";
278
+ import OSM from "ol/source/OSM";
279
+
280
+ export class MapConfigProviderImpl implements MapConfigProvider {
281
+ async getMapConfig(): Promise<MapConfig> {
282
+ return {
283
+ layers: [
284
+ new SimpleLayer({
285
+ id: "1",
286
+ title: "Layer 1",
287
+ olLayer: new TileLayer({
288
+ source: new OSM()
289
+ }),
290
+ // check layer availability by requesting the provided URL
291
+ healthCheck:
292
+ "https://sgx.geodatenzentrum.de/wmts_topplus_open/1.0.0/WMTSCapabilities.xml",
293
+ isBaseLayer: false,
294
+ visible: true
295
+ }),
296
+ new SimpleLayer({
297
+ id: "2",
298
+ title: "Layer 2",
299
+ olLayer: new TileLayer({
300
+ source: new OSM()
301
+ }),
302
+ // check layer availability by providing a custom health check function
303
+ healthCheck: async () => {
304
+ function wait(milliseconds: number): Promise<void> {
305
+ return new Promise((resolve) => setTimeout(resolve, milliseconds));
306
+ }
307
+
308
+ await wait(3000);
309
+ return "error";
310
+ },
311
+ isBaseLayer: false,
312
+ visible: false
313
+ })
314
+ ]
315
+ };
316
+ }
317
+ }
318
+ ```
319
+
261
320
  > NOTE: The visibility of base layers cannot be changed through the method `setVisible`.
262
321
  > Call `activateBaseLayer` instead.
263
322
 
@@ -266,7 +325,7 @@ layer.deleteAttribute("foo");
266
325
  To create an OGC API Features layer, use the `ogc-features` package.
267
326
  Details about the necessary steps are described in the package's [README](../ogc-features/README.md) file.
268
327
 
269
- ##### Mapbox / MapLibre styles
328
+ ###### Mapbox / MapLibre styles
270
329
 
271
330
  To use layers of a Mapbox / MapLibre style document, use the class `MapboxVectorLayer` from the package `ol-mapbox-style` as in the following sample:
272
331
 
@@ -294,8 +353,7 @@ export class MapConfigProviderImpl implements MapConfigProvider {
294
353
  {
295
354
  title: "Abschnitte/Äste mit Unfällen (Mapbox Style)",
296
355
  layer: new MapboxVectorLayer({
297
- styleUrl: "https://demo.ldproxy.net/strassen/styles/default?f=mbs",
298
- accessToken: null
356
+ styleUrl: "https://demo.ldproxy.net/strassen/styles/default?f=mbs"
299
357
  })
300
358
  }
301
359
  ]
@@ -304,12 +362,56 @@ export class MapConfigProviderImpl implements MapConfigProvider {
304
362
  }
305
363
  ```
306
364
 
307
- As with the current version 12.0.0 of `ol-mapbox-style`, it is not possible to use the MapboxVectorLayer
308
- with styleUrls in format `mbs` (parameter `f=mbs`) due to a bug. A patch has been provided for this and is active
309
- with the current version of the trails base package.
310
- The patch enables the user to explicitly set the `accessToken` to `null`, if it is not needed/supported.
365
+ Because of the changed license of Mapbox as of version 2.0, we recommend to override the implementation with the code of MapLibre (see the main package.json of this repository for a sample).
366
+
367
+ ##### OGC API Tiles
368
+
369
+ OpenLayers supports OGC API Tiles (vector tiles) by default (see [OpenLayers API](https://openlayers.org/en/latest/apidoc/module-ol_source_OGCVectorTile-OGCVectorTile.html)).
370
+
371
+ > IMPORTANT: The configured vector tile layer must have the same projection like the map. Otherwise OGC API Tiles cannot be displayed correctly in a map.
372
+
373
+ Example: How to configure a vector tile layer:
311
374
 
312
- Because of the changed licence of Mapbox as of version 2.0, we recommend to override the implementation with the code of MapLibre (see the main package.json of this repository for a sample).
375
+ ```ts
376
+ // YOUR-APP/MapConfigProviderImpl.ts
377
+ export class MapConfigProviderImpl implements MapConfigProvider {
378
+ async getMapConfig(): Promise<MapConfig> {
379
+ return {
380
+ projection: "EPSG:3857",
381
+ initialView: {
382
+ kind: "position",
383
+ center: {
384
+ x: 848890,
385
+ y: 6793350
386
+ },
387
+ zoom: 13
388
+ },
389
+ layers: [
390
+ new SimpleLayer({
391
+ title: "Pendleratlas",
392
+ visible: true,
393
+ olLayer: new VectorTileLayer({
394
+ source: new VectorTileSource({
395
+ url: "https://pendleratlas.statistikportal.de/_vector_tiles/2022/vg250/{z}/{x}/{y}.pbf",
396
+ format: new MVT(),
397
+ projection: "EPSG:3857"
398
+ }),
399
+ style: new Style({
400
+ fill: new Fill({
401
+ color: "rgba(173, 209, 158, 0.6)"
402
+ }),
403
+ stroke: new Stroke({
404
+ color: "#2d7d9f",
405
+ width: 3
406
+ })
407
+ })
408
+ })
409
+ })
410
+ ]
411
+ };
412
+ }
413
+ }
414
+ ```
313
415
 
314
416
  ##### OGC Web Map Tile Service (WMTS)
315
417
 
@@ -435,7 +537,7 @@ registerProjections({
435
537
  const mapModel: MapModel = ... // retrieved via MapRegistry service
436
538
  await mapModel.whenDisplayed();
437
539
 
438
- const response = await fetch("https://sgx.geodatenzentrum.de/wmts_topplus_open/1.0.0/WMTSCapabilities.xml");
540
+ const response = await httpService.fetch("https://sgx.geodatenzentrum.de/wmts_topplus_open/1.0.0/WMTSCapabilities.xml");
439
541
  const responseText = await response.text();
440
542
 
441
543
  const wmtsParser = new WMTSCapabilities();
package/api/MapModel.d.ts CHANGED
@@ -4,6 +4,8 @@ import type OlBaseLayer from "ol/layer/Base";
4
4
  import type { ExtentConfig } from "./MapConfig";
5
5
  import type { Layer, LayerBase } from "./layers";
6
6
  import type { LayerRetrievalOptions } from "./shared";
7
+ import type { Geometry } from "ol/geom";
8
+ import type { StyleLike } from "ol/style/Style";
7
9
  /** Events emitted by the {@link MapModel}. */
8
10
  export interface MapModelEvents {
9
11
  "changed": void;
@@ -11,6 +13,26 @@ export interface MapModelEvents {
11
13
  "changed:initialExtent": void;
12
14
  "destroy": void;
13
15
  }
16
+ /** Options supported by the map model's {@link MapModel.highlightAndZoom | highlightAndZoom} method. */
17
+ export interface HighlightOptions {
18
+ /**
19
+ * Optional styles to override the default styles.
20
+ */
21
+ highlightStyle?: HighlightStyle;
22
+ /**
23
+ * The zoom-level used if there is no valid extend (such as for single points).
24
+ */
25
+ pointZoom?: number;
26
+ /**
27
+ * The maximum zoom-level for line or polygon results.
28
+ */
29
+ maxZoom?: number;
30
+ }
31
+ export interface HighlightStyle {
32
+ Point?: StyleLike;
33
+ LineString?: StyleLike;
34
+ Polygon?: StyleLike;
35
+ }
14
36
  /**
15
37
  * Represents a map.
16
38
  */
@@ -52,6 +74,17 @@ export interface MapModel extends EventSource<MapModelEvents> {
52
74
  * Returns a promise that resolves when the map has mounted in the DOM.
53
75
  */
54
76
  whenDisplayed(): Promise<void>;
77
+ /**
78
+ * Highlights the given geometries on the map.
79
+ * Centers and zooms the view on the geometries.
80
+ *
81
+ * Removes any previous highlights.
82
+ */
83
+ highlightAndZoom(geometries: Geometry[], options?: HighlightOptions): void;
84
+ /**
85
+ * Removes any existing highlights from the map.
86
+ */
87
+ removeHighlight(): void;
55
88
  }
56
89
  /** Events emitted by the {@link LayerCollection}. */
57
90
  export interface LayerCollectionEvents {
@@ -1,6 +1,7 @@
1
1
  import type OlMap from "ol/Map";
2
2
  import type { MapConfig } from "./MapConfig";
3
3
  import type { MapModel } from "./MapModel";
4
+ import type { DeclaredService } from "@open-pioneer/runtime";
4
5
  /**
5
6
  * Provides access to registered map instances.
6
7
  *
@@ -8,7 +9,7 @@ import type { MapModel } from "./MapModel";
8
9
  *
9
10
  * Inject an instance of this service by referencing the interface name `"map.MapRegistry"`.
10
11
  */
11
- export interface MapRegistry {
12
+ export interface MapRegistry extends DeclaredService<"map.MapRegistry"> {
12
13
  /**
13
14
  * Returns the map model associated with the given id.
14
15
  * Returns undefined if there is no such model.
@@ -45,10 +46,3 @@ export interface MapConfigProvider {
45
46
  */
46
47
  getMapConfig(): Promise<MapConfig>;
47
48
  }
48
- import "@open-pioneer/runtime";
49
- declare module "@open-pioneer/runtime" {
50
- interface ServiceRegistry {
51
- "map.MapRegistry": MapRegistry;
52
- "map.MapConfigProvider": MapConfigProvider;
53
- }
54
- }
package/api/index.d.ts CHANGED
@@ -9,4 +9,5 @@ export { useCenter, useProjection, useResolution, useScale } from "../ui/hooks";
9
9
  export { MapAnchor, type MapAnchorProps, type MapAnchorPosition } from "../ui/MapAnchor";
10
10
  export { MapContainer, type MapContainerProps, type MapPadding } from "../ui/MapContainer";
11
11
  export { useMapModel, type UseMapModelResult, type UseMapModelLoading, type UseMapModelResolved, type UseMapModelRejected } from "../ui/useMapModel";
12
+ export { calculateBufferedExtent } from "../util/geometry-utils";
12
13
  export { TOPMOST_LAYER_Z } from "../model/LayerCollectionImpl";
@@ -1,9 +1,9 @@
1
1
  import type { Options as WMSSourceOptions } from "ol/source/ImageWMS";
2
- import type { LayerBaseConfig, Layer, SublayersCollection } from "./base";
2
+ import type { LayerBaseConfig, Layer, SublayersCollection, LayerConfig } from "./base";
3
3
  /**
4
4
  * Configuration options to construct a WMS layer.
5
5
  */
6
- export interface WMSLayerConfig extends LayerBaseConfig {
6
+ export interface WMSLayerConfig extends LayerConfig {
7
7
  /** URL of the WMS service. */
8
8
  url: string;
9
9
  /** Configures the layer's sublayers. */
@@ -12,7 +12,7 @@ export interface WMSLayerConfig extends LayerBaseConfig {
12
12
  * Additional source options for the layer's WMS source.
13
13
  *
14
14
  * NOTE: These options are intended for advanced configuration:
15
- * the WMS Layer manages some of the open layers source options itself.
15
+ * the WMS Layer manages some of the OpenLayers source options itself.
16
16
  */
17
17
  sourceOptions?: Partial<WMSSourceOptions>;
18
18
  }
@@ -1 +1 @@
1
- {"version":3,"file":"WMSLayer.js","sources":["WMSLayer.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport type { Options as WMSSourceOptions } from \"ol/source/ImageWMS\";\nimport { WMSLayerImpl } from \"../../model/layers/WMSLayerImpl\";\nimport type { LayerBaseConfig, Layer, SublayersCollection } from \"./base\";\n\n/**\n * Configuration options to construct a WMS layer.\n */\nexport interface WMSLayerConfig extends LayerBaseConfig {\n /** URL of the WMS service. */\n url: string;\n\n /** Configures the layer's sublayers. */\n sublayers?: WMSSublayerConfig[];\n\n /**\n * Additional source options for the layer's WMS source.\n *\n * NOTE: These options are intended for advanced configuration:\n * the WMS Layer manages some of the open layers source options itself.\n */\n sourceOptions?: Partial<WMSSourceOptions>;\n}\n\n/**\n * Configuration options to construct the sublayers of a WMS layer.\n */\nexport interface WMSSublayerConfig extends LayerBaseConfig {\n /** The name of the WMS sublayer in the service's capabilities. */\n name: string;\n\n /** Configuration for nested sublayers. */\n sublayers?: WMSSublayerConfig[];\n}\n\n/** Represents a WMS layer. */\nexport interface WMSLayer extends Layer {\n readonly sublayers: SublayersCollection;\n\n /** The URL of the WMS service that was used during layer construction. */\n readonly url: string;\n}\n\n/**\n * Constructor for {@link WMSLayer}.\n */\nexport interface WMSLayerConstructor {\n prototype: WMSLayer;\n\n /** Creates a new {@link WMSLayer}. */\n new (config: WMSLayerConfig): WMSLayer;\n}\n\nexport const WMSLayer: WMSLayerConstructor = WMSLayerImpl;\n"],"names":[],"mappings":";;AAsDO,MAAM,QAAgC,GAAA;;;;"}
1
+ {"version":3,"file":"WMSLayer.js","sources":["WMSLayer.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport type { Options as WMSSourceOptions } from \"ol/source/ImageWMS\";\nimport { WMSLayerImpl } from \"../../model/layers/WMSLayerImpl\";\nimport type { LayerBaseConfig, Layer, SublayersCollection, LayerConfig } from \"./base\";\n\n/**\n * Configuration options to construct a WMS layer.\n */\nexport interface WMSLayerConfig extends LayerConfig {\n /** URL of the WMS service. */\n url: string;\n\n /** Configures the layer's sublayers. */\n sublayers?: WMSSublayerConfig[];\n\n /**\n * Additional source options for the layer's WMS source.\n *\n * NOTE: These options are intended for advanced configuration:\n * the WMS Layer manages some of the OpenLayers source options itself.\n */\n sourceOptions?: Partial<WMSSourceOptions>;\n}\n\n/**\n * Configuration options to construct the sublayers of a WMS layer.\n */\nexport interface WMSSublayerConfig extends LayerBaseConfig {\n /** The name of the WMS sublayer in the service's capabilities. */\n name: string;\n\n /** Configuration for nested sublayers. */\n sublayers?: WMSSublayerConfig[];\n}\n\n/** Represents a WMS layer. */\nexport interface WMSLayer extends Layer {\n readonly sublayers: SublayersCollection;\n\n /** The URL of the WMS service that was used during layer construction. */\n readonly url: string;\n}\n\n/**\n * Constructor for {@link WMSLayer}.\n */\nexport interface WMSLayerConstructor {\n prototype: WMSLayer;\n\n /** Creates a new {@link WMSLayer}. */\n new (config: WMSLayerConfig): WMSLayer;\n}\n\nexport const WMSLayer: WMSLayerConstructor = WMSLayerImpl;\n"],"names":[],"mappings":";;AAsDO,MAAM,QAAgC,GAAA;;;;"}
@@ -14,6 +14,8 @@ export interface LayerBaseEvents {
14
14
  }
15
15
  /** The load state of a layer. */
16
16
  export type LayerLoadState = "not-loaded" | "loading" | "loaded" | "error";
17
+ /** Custom function to check the state of a layer and returning a "loaded" or "error". */
18
+ export type HealthCheckFunction = (layer: LayerBase) => Promise<"loaded" | "error">;
17
19
  /**
18
20
  * Configuration options supported by all layer types (layers and sublayers).
19
21
  */
@@ -116,6 +118,12 @@ export interface LayerConfig extends LayerBaseConfig {
116
118
  * Defaults to `false`.
117
119
  */
118
120
  isBaseLayer?: boolean;
121
+ /**
122
+ * Optional property to check the availability of the layer.
123
+ * It is possible to provide either a URL which indicates the state of the service (2xx response meaning "ok")
124
+ * or a {@link HealthCheckFunction} performing a custom check and returning the state.
125
+ */
126
+ healthCheck?: string | HealthCheckFunction;
119
127
  }
120
128
  /**
121
129
  * Represents an operational layer in the map.
Binary file
package/index.js CHANGED
@@ -1,4 +1,3 @@
1
- import '@open-pioneer/runtime';
2
1
  export { SimpleLayer } from './api/layers/SimpleLayer.js';
3
2
  export { WMSLayer } from './api/layers/WMSLayer.js';
4
3
  export { getProjection, registerProjections } from './projections.js';
@@ -7,5 +6,6 @@ export { useCenter, useProjection, useResolution, useScale } from './ui/hooks.js
7
6
  export { MapAnchor } from './ui/MapAnchor.js';
8
7
  export { MapContainer } from './ui/MapContainer.js';
9
8
  export { useMapModel } from './ui/useMapModel.js';
9
+ export { calculateBufferedExtent } from './util/geometry-utils.js';
10
10
  export { TOPMOST_LAYER_Z } from './model/LayerCollectionImpl.js';
11
11
  //# sourceMappingURL=index.js.map
@@ -52,7 +52,7 @@ class BkgTopPlusOpen extends WMTS {
52
52
  matrixIds
53
53
  }),
54
54
  style: "default",
55
- attributions: `Kartendarstellung und Pr\xE4sentationsgraphiken: \xA9 Bundesamt f\xFCr Kartographie und Geod\xE4sie ${( new Date()).getFullYear()}, <a href="https://sg.geodatenzentrum.de/web_public/gdz/datenquellen/Datenquellen_TopPlusOpen.html" target="_blank">Datenquellen</a>`
55
+ attributions: `Kartendarstellung und Pr\xE4sentationsgraphiken: \xA9 Bundesamt f\xFCr Kartographie und Geod\xE4sie ${(/* @__PURE__ */ new Date()).getFullYear()}, <a href="https://sg.geodatenzentrum.de/web_public/gdz/datenquellen/Datenquellen_TopPlusOpen.html" target="_blank">Datenquellen</a>`
56
56
  });
57
57
  }
58
58
  }
@@ -1 +1 @@
1
- {"version":3,"file":"BkgTopPlusOpen.js","sources":["BkgTopPlusOpen.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport WMTS from \"ol/source/WMTS\";\nimport WMTSTileGrid from \"ol/tilegrid/WMTS\";\n\n/** @internal */\nexport interface BkgTopPlusOpenProps {\n /**\n * The name of the requesting layer.\n * @default \"web\"\n */\n layer?: \"web\" | \"web_grau\" | \"web_light\";\n}\n\n/**\n * Layer source for BKG TopPlus Open.\n *\n * Used for @open-pioneer unit tests: not part of the public interface.\n *\n * @see https://gdz.bkg.bund.de/index.php/default/wmts-topplusopen-wmts-topplus-open.html\n *\n * @internal\n */\nexport class BkgTopPlusOpen extends WMTS {\n constructor(options?: BkgTopPlusOpenProps) {\n const topLeftCorner = [-3803165.98427299, 8805908.08284866];\n\n /**\n * Resolutions taken from AdV WMTS-Profil\n * @see https://www.adv-online.de/AdV-Produkte/Standards-und-Produktblaetter/AdV-Profile/\n */\n const resolutions = [\n 4891.96981025128, // AdV-Level 0 (1:17471320.7508974)\n 2445.98490512564, // AdV-Level 1 (1:8735660.37544872)\n 1222.99245256282, // AdV-Level 2 (1:4367830.18772436)\n 611.49622628141, // AdV-Level 3 (1:2183915.09386218)\n 305.748113140705, // AdV-Level 4 (1:1091957.54693109)\n 152.874056570353, // AdV-Level 5 (1:545978.773465545)\n 76.4370282851763, // AdV-Level 6 (1:272989,386732772)\n 38.2185141425881, // AdV-Level 7 (1:136494,693366386)\n 19.1092570712941, // AdV-Level 8 (1:68247,3466831931)\n 9.55462853564703, // AdV-Level 9 (1:34123,6733415966)\n 4.77731426782352, // AdV-Level 10 (1:17061,8366707983)\n 2.38865713391176, // AdV-Level 11 (1:8530,91833539914)\n 1.19432856695588, // AdV-Level 12 (1:4265,45916769957)\n 0.59716428347794 // AdV-Level 13 (1:2132,72958384978)\n ];\n\n /**\n * The length of matrixIds needs to match the length of the resolutions array\n * @see https://openlayers.org/en/latest/apidoc/module-ol_tilegrid_WMTS-WMTSTileGrid.html\n */\n const matrixIds = new Array(resolutions.length);\n for (let i = 0; i < resolutions.length; i++) {\n matrixIds[i] = i;\n }\n\n const layer = options?.layer ?? \"web\";\n\n super({\n url: `https://sgx.geodatenzentrum.de/wmts_topplus_open/tile/1.0.0/${layer}/{Style}/{TileMatrixSet}/{TileMatrix}/{TileRow}/{TileCol}.png`,\n layer: layer,\n matrixSet: \"EU_EPSG_25832_TOPPLUS\",\n format: \"image/png\",\n projection: \"EPSG:25832\",\n requestEncoding: \"REST\",\n tileGrid: new WMTSTileGrid({\n origin: topLeftCorner,\n resolutions: resolutions,\n matrixIds: matrixIds\n }),\n style: \"default\",\n attributions: `Kartendarstellung und Präsentationsgraphiken: © Bundesamt für Kartographie und Geodäsie ${new Date().getFullYear()}, <a href=\"https://sg.geodatenzentrum.de/web_public/gdz/datenquellen/Datenquellen_TopPlusOpen.html\" target=\"_blank\">Datenquellen</a>`\n });\n }\n}\n"],"names":[],"mappings":";;;AAuBO,MAAM,uBAAuB,IAAK,CAAA;AAAA,EACrC,YAAY,OAA+B,EAAA;AACvC,IAAM,MAAA,aAAA,GAAgB,CAAC,CAAA,kBAAA,EAAmB,kBAAgB,CAAA,CAAA;AAM1D,IAAA,MAAM,WAAc,GAAA;AAAA,MAChB,gBAAA;AAAA;AAAA,MACA,gBAAA;AAAA;AAAA,MACA,gBAAA;AAAA;AAAA,MACA,eAAA;AAAA;AAAA,MACA,gBAAA;AAAA;AAAA,MACA,gBAAA;AAAA;AAAA,MACA,gBAAA;AAAA;AAAA,MACA,gBAAA;AAAA;AAAA,MACA,gBAAA;AAAA;AAAA,MACA,gBAAA;AAAA;AAAA,MACA,gBAAA;AAAA;AAAA,MACA,gBAAA;AAAA;AAAA,MACA,gBAAA;AAAA;AAAA,MACA,gBAAA;AAAA;AAAA,KACJ,CAAA;AAMA,IAAA,MAAM,SAAY,GAAA,IAAI,KAAM,CAAA,WAAA,CAAY,MAAM,CAAA,CAAA;AAC9C,IAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,GAAA,WAAA,CAAY,QAAQ,CAAK,EAAA,EAAA;AACzC,MAAA,SAAA,CAAU,CAAC,CAAI,GAAA,CAAA,CAAA;AAAA,KACnB;AAEA,IAAM,MAAA,KAAA,GAAQ,SAAS,KAAS,IAAA,KAAA,CAAA;AAEhC,IAAM,KAAA,CAAA;AAAA,MACF,GAAA,EAAK,+DAA+D,KAAK,CAAA,6DAAA,CAAA;AAAA,MACzE,KAAA;AAAA,MACA,SAAW,EAAA,uBAAA;AAAA,MACX,MAAQ,EAAA,WAAA;AAAA,MACR,UAAY,EAAA,YAAA;AAAA,MACZ,eAAiB,EAAA,MAAA;AAAA,MACjB,QAAA,EAAU,IAAI,YAAa,CAAA;AAAA,QACvB,MAAQ,EAAA,aAAA;AAAA,QACR,WAAA;AAAA,QACA,SAAA;AAAA,OACH,CAAA;AAAA,MACD,KAAO,EAAA,SAAA;AAAA,MACP,cAAc,CAA2F,oGAAA,EAAA,CAAA,CAAA,IAAI,IAAK,EAAA,EAAE,aAAa,CAAA,oIAAA,CAAA;AAAA,KACpI,CAAA,CAAA;AAAA,GACL;AACJ;;;;"}
1
+ {"version":3,"file":"BkgTopPlusOpen.js","sources":["BkgTopPlusOpen.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport WMTS from \"ol/source/WMTS\";\nimport WMTSTileGrid from \"ol/tilegrid/WMTS\";\n\n/** @internal */\nexport interface BkgTopPlusOpenProps {\n /**\n * The name of the requesting layer.\n * @default \"web\"\n */\n layer?: \"web\" | \"web_grau\" | \"web_light\";\n}\n\n/**\n * Layer source for BKG TopPlus Open.\n *\n * Used for @open-pioneer unit tests: not part of the public interface.\n *\n * @see https://gdz.bkg.bund.de/index.php/default/wmts-topplusopen-wmts-topplus-open.html\n *\n * @internal\n */\nexport class BkgTopPlusOpen extends WMTS {\n constructor(options?: BkgTopPlusOpenProps) {\n const topLeftCorner = [-3803165.98427299, 8805908.08284866];\n\n /**\n * Resolutions taken from AdV WMTS-Profil\n * @see https://www.adv-online.de/AdV-Produkte/Standards-und-Produktblaetter/AdV-Profile/\n */\n const resolutions = [\n 4891.96981025128, // AdV-Level 0 (1:17471320.7508974)\n 2445.98490512564, // AdV-Level 1 (1:8735660.37544872)\n 1222.99245256282, // AdV-Level 2 (1:4367830.18772436)\n 611.49622628141, // AdV-Level 3 (1:2183915.09386218)\n 305.748113140705, // AdV-Level 4 (1:1091957.54693109)\n 152.874056570353, // AdV-Level 5 (1:545978.773465545)\n 76.4370282851763, // AdV-Level 6 (1:272989,386732772)\n 38.2185141425881, // AdV-Level 7 (1:136494,693366386)\n 19.1092570712941, // AdV-Level 8 (1:68247,3466831931)\n 9.55462853564703, // AdV-Level 9 (1:34123,6733415966)\n 4.77731426782352, // AdV-Level 10 (1:17061,8366707983)\n 2.38865713391176, // AdV-Level 11 (1:8530,91833539914)\n 1.19432856695588, // AdV-Level 12 (1:4265,45916769957)\n 0.59716428347794 // AdV-Level 13 (1:2132,72958384978)\n ];\n\n /**\n * The length of matrixIds needs to match the length of the resolutions array\n * @see https://openlayers.org/en/latest/apidoc/module-ol_tilegrid_WMTS-WMTSTileGrid.html\n */\n const matrixIds = new Array(resolutions.length);\n for (let i = 0; i < resolutions.length; i++) {\n matrixIds[i] = i;\n }\n\n const layer = options?.layer ?? \"web\";\n\n super({\n url: `https://sgx.geodatenzentrum.de/wmts_topplus_open/tile/1.0.0/${layer}/{Style}/{TileMatrixSet}/{TileMatrix}/{TileRow}/{TileCol}.png`,\n layer: layer,\n matrixSet: \"EU_EPSG_25832_TOPPLUS\",\n format: \"image/png\",\n projection: \"EPSG:25832\",\n requestEncoding: \"REST\",\n tileGrid: new WMTSTileGrid({\n origin: topLeftCorner,\n resolutions: resolutions,\n matrixIds: matrixIds\n }),\n style: \"default\",\n attributions: `Kartendarstellung und Präsentationsgraphiken: © Bundesamt für Kartographie und Geodäsie ${new Date().getFullYear()}, <a href=\"https://sg.geodatenzentrum.de/web_public/gdz/datenquellen/Datenquellen_TopPlusOpen.html\" target=\"_blank\">Datenquellen</a>`\n });\n }\n}\n"],"names":[],"mappings":";;;AAuBO,MAAM,uBAAuB,IAAK,CAAA;AAAA,EACrC,YAAY,OAA+B,EAAA;AACvC,IAAM,MAAA,aAAA,GAAgB,CAAC,CAAA,kBAAA,EAAmB,kBAAgB,CAAA,CAAA;AAM1D,IAAA,MAAM,WAAc,GAAA;AAAA,MAChB,gBAAA;AAAA;AAAA,MACA,gBAAA;AAAA;AAAA,MACA,gBAAA;AAAA;AAAA,MACA,eAAA;AAAA;AAAA,MACA,gBAAA;AAAA;AAAA,MACA,gBAAA;AAAA;AAAA,MACA,gBAAA;AAAA;AAAA,MACA,gBAAA;AAAA;AAAA,MACA,gBAAA;AAAA;AAAA,MACA,gBAAA;AAAA;AAAA,MACA,gBAAA;AAAA;AAAA,MACA,gBAAA;AAAA;AAAA,MACA,gBAAA;AAAA;AAAA,MACA,gBAAA;AAAA;AAAA,KACJ,CAAA;AAMA,IAAA,MAAM,SAAY,GAAA,IAAI,KAAM,CAAA,WAAA,CAAY,MAAM,CAAA,CAAA;AAC9C,IAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,GAAA,WAAA,CAAY,QAAQ,CAAK,EAAA,EAAA;AACzC,MAAA,SAAA,CAAU,CAAC,CAAI,GAAA,CAAA,CAAA;AAAA,KACnB;AAEA,IAAM,MAAA,KAAA,GAAQ,SAAS,KAAS,IAAA,KAAA,CAAA;AAEhC,IAAM,KAAA,CAAA;AAAA,MACF,GAAA,EAAK,+DAA+D,KAAK,CAAA,6DAAA,CAAA;AAAA,MACzE,KAAA;AAAA,MACA,SAAW,EAAA,uBAAA;AAAA,MACX,MAAQ,EAAA,WAAA;AAAA,MACR,UAAY,EAAA,YAAA;AAAA,MACZ,eAAiB,EAAA,MAAA;AAAA,MACjB,QAAA,EAAU,IAAI,YAAa,CAAA;AAAA,QACvB,MAAQ,EAAA,aAAA;AAAA,QACR,WAAA;AAAA,QACA,SAAA;AAAA,OACH,CAAA;AAAA,MACD,KAAO,EAAA,SAAA;AAAA,MACP,cAAc,CAA2F,oGAAA,EAAA,iBAAA,IAAI,IAAK,EAAA,EAAE,aAAa,CAAA,oIAAA,CAAA;AAAA,KACpI,CAAA,CAAA;AAAA,GACL;AACJ;;;;"}
@@ -7,6 +7,7 @@ const LOG = createLogger("map:AbstractLayer");
7
7
  class AbstractLayer extends AbstractLayerBase {
8
8
  #olLayer;
9
9
  #isBaseLayer;
10
+ #healthCheck;
10
11
  #visible;
11
12
  #loadState;
12
13
  #stateWatchResource;
@@ -14,16 +15,9 @@ class AbstractLayer extends AbstractLayerBase {
14
15
  super(config);
15
16
  this.#olLayer = config.olLayer;
16
17
  this.#isBaseLayer = config.isBaseLayer ?? false;
18
+ this.#healthCheck = config.healthCheck;
17
19
  this.#visible = config.visible ?? true;
18
- const { initial: initialState, resource: stateWatchResource } = watchLoadState(
19
- this.#olLayer,
20
- (state) => {
21
- this.#loadState = state;
22
- this.__emitChangeEvent("changed:loadState");
23
- }
24
- );
25
- this.#loadState = initialState;
26
- this.#stateWatchResource = stateWatchResource;
20
+ this.#loadState = getSourceState(getSource(this.#olLayer));
27
21
  }
28
22
  get visible() {
29
23
  return this.#visible;
@@ -50,6 +44,15 @@ class AbstractLayer extends AbstractLayerBase {
50
44
  */
51
45
  __attach(map) {
52
46
  super.__attachToMap(map);
47
+ const { initial: initialState, resource: stateWatchResource } = watchLoadState(
48
+ this,
49
+ this.#healthCheck,
50
+ (state) => {
51
+ this.#setLoadState(state);
52
+ }
53
+ );
54
+ this.#stateWatchResource = stateWatchResource;
55
+ this.#setLoadState(initialState);
53
56
  }
54
57
  setVisible(newVisibility) {
55
58
  if (this.isBaseLayer) {
@@ -71,8 +74,15 @@ class AbstractLayer extends AbstractLayerBase {
71
74
  }
72
75
  changed && this.__emitChangeEvent("changed:visible");
73
76
  }
77
+ #setLoadState(loadState) {
78
+ if (loadState !== this.#loadState) {
79
+ this.#loadState = loadState;
80
+ this.__emitChangeEvent("changed:loadState");
81
+ }
82
+ }
74
83
  }
75
- function watchLoadState(olLayer, onChange) {
84
+ function watchLoadState(layer, healthCheck, onChange) {
85
+ const olLayer = layer.olLayer;
76
86
  if (!(olLayer instanceof OlLayer)) {
77
87
  return {
78
88
  initial: "loaded",
@@ -82,10 +92,19 @@ function watchLoadState(olLayer, onChange) {
82
92
  }
83
93
  };
84
94
  }
85
- let currentSource = olLayer?.getSource();
86
- let currentLoadState = mapState(currentSource?.getState());
95
+ let currentSource = getSource(olLayer);
96
+ const currentOlLayerState = getSourceState(currentSource);
97
+ let currentLoadState = currentOlLayerState;
98
+ let currentHealthState = "loading";
99
+ if (currentOlLayerState !== "error") {
100
+ doHealthCheck(layer, healthCheck).then((state) => {
101
+ currentHealthState = state;
102
+ updateState();
103
+ });
104
+ }
87
105
  const updateState = () => {
88
- const nextLoadState = mapState(currentSource?.getState());
106
+ const olLayerState = getSourceState(currentSource);
107
+ const nextLoadState = currentHealthState === "error" ? "error" : olLayerState;
89
108
  if (currentLoadState !== nextLoadState) {
90
109
  currentLoadState = nextLoadState;
91
110
  onChange(currentLoadState);
@@ -98,7 +117,7 @@ function watchLoadState(olLayer, onChange) {
98
117
  const sourceHandle = olLayer.on("change:source", () => {
99
118
  stateHandle && unByKey(stateHandle);
100
119
  stateHandle = void 0;
101
- currentSource = olLayer?.getSource();
120
+ currentSource = getSource(olLayer);
102
121
  stateHandle = currentSource?.on("change", () => {
103
122
  updateState();
104
123
  });
@@ -114,7 +133,47 @@ function watchLoadState(olLayer, onChange) {
114
133
  }
115
134
  };
116
135
  }
117
- function mapState(state) {
136
+ async function doHealthCheck(layer, healthCheck) {
137
+ if (healthCheck == null) {
138
+ return "loaded";
139
+ }
140
+ let healthCheckFn;
141
+ if (typeof healthCheck === "function") {
142
+ healthCheckFn = healthCheck;
143
+ } else if (typeof healthCheck === "string") {
144
+ healthCheckFn = async () => {
145
+ const httpService = layer.map.__sharedDependencies.httpService;
146
+ const response = await httpService.fetch(healthCheck);
147
+ if (response.ok) {
148
+ return "loaded";
149
+ }
150
+ LOG.warn(
151
+ `Health check failed for layer '${layer.id}' (http status ${response.status})`
152
+ );
153
+ return "error";
154
+ };
155
+ } else {
156
+ LOG.error(
157
+ `Unexpected object for 'healthCheck' parameter of layer '${layer.id}'`,
158
+ healthCheck
159
+ );
160
+ return "error";
161
+ }
162
+ try {
163
+ return await healthCheckFn(layer);
164
+ } catch (e) {
165
+ LOG.warn(`Health check failed for layer '${layer.id}'`, e);
166
+ return "error";
167
+ }
168
+ }
169
+ function getSource(olLayer) {
170
+ if (!(olLayer instanceof OlLayer)) {
171
+ return void 0;
172
+ }
173
+ return olLayer?.getSource() ?? void 0;
174
+ }
175
+ function getSourceState(olSource) {
176
+ const state = olSource?.getState();
118
177
  switch (state) {
119
178
  case void 0:
120
179
  return "loaded";