@open-pioneer/map 1.5.0-dev.20260911123645 → 1.5.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 (49) hide show
  1. package/CHANGELOG.md +529 -520
  2. package/LayerFactory.js.map +1 -1
  3. package/MapRegistry.js.map +1 -1
  4. package/README.md +37 -1
  5. package/_virtual/hooks.js.map +1 -1
  6. package/_virtual/source-info.js.map +1 -1
  7. package/layers/AbstractLayer.js.map +1 -1
  8. package/layers/AbstractLayerBase.js.map +1 -1
  9. package/layers/GroupLayer.js.map +1 -1
  10. package/layers/SimpleLayer.js.map +1 -1
  11. package/layers/WMSLayer.js.map +1 -1
  12. package/layers/WMTSLayer.js.map +1 -1
  13. package/layers/group/GroupLayerCollection.js.map +1 -1
  14. package/layers/shared/SublayersCollection.js.map +1 -1
  15. package/layers/shared/getRecursiveLayers.js.map +1 -1
  16. package/layers/shared/internals.js.map +1 -1
  17. package/layers/unions.js.map +1 -1
  18. package/layers/wms/WMSSublayer.js.map +1 -1
  19. package/layers/wms/getAttributions.js.map +1 -1
  20. package/layers/wms/getLegendUrl.js.map +1 -1
  21. package/layers/wmts/getAttributions.js.map +1 -1
  22. package/layers/wmts/getLegendUrl.js.map +1 -1
  23. package/model/Highlights.js.map +1 -1
  24. package/model/LayerCollection.js.map +1 -1
  25. package/model/MapAttributions.js.map +1 -1
  26. package/model/MapModel.d.ts +2 -1
  27. package/model/MapModel.js +16 -12
  28. package/model/MapModel.js.map +1 -1
  29. package/model/Overlays.js.map +1 -1
  30. package/model/createMapModel.js +10 -22
  31. package/model/createMapModel.js.map +1 -1
  32. package/model/getGeometries.js.map +1 -1
  33. package/package.json +8 -8
  34. package/ui/DefaultMapProvider.js.map +1 -1
  35. package/ui/MapAnchor.js.map +1 -1
  36. package/ui/MapContainer.js +3 -2
  37. package/ui/MapContainer.js.map +1 -1
  38. package/ui/MapContainerContext.js.map +1 -1
  39. package/ui/OverlaysRenderer.js.map +1 -1
  40. package/ui/computeMapAnchorStyles.js.map +1 -1
  41. package/ui/hooks/useMapModel.js.map +1 -1
  42. package/ui/styles.css +0 -1
  43. package/ui/styles.css.map +1 -1
  44. package/utils/InternalConstructorTag.js.map +1 -1
  45. package/utils/fetch.js.map +1 -1
  46. package/utils/geometry-utils.js.map +1 -1
  47. package/utils/ol-test-support.js.map +1 -1
  48. package/utils/projections.js.map +1 -1
  49. package/utils/sanitize.js.map +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"MapAttributions.js","sources":["MapAttributions.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\n\nimport { computed, effect, reactive, ReadonlyReactive } from \"@conterra/reactivity-core\";\nimport { destroyResources, Resource, shallowEqual } from \"@open-pioneer/core\";\nimport { PackageIntl } from \"@open-pioneer/runtime\";\nimport Attribution from \"ol/control/Attribution\";\nimport OlMap, { FrameState } from \"ol/Map\";\nimport { sanitizeHtml } from \"../utils/sanitize\";\nimport { AttributionItem } from \"./MapModel\";\n\nexport class MapAttributions {\n #olMap: OlMap;\n #intl: ReadonlyReactive<PackageIntl>;\n\n /**\n * When default rendering of attributions is active, we simply display this control on the map (otherwise: hidden).\n *\n * The control is always active (even if invisible) because we re-use its rendering code to extract the attribution items.\n * There is no real API to extract the attributions from OpenLayers, and we don't want to re-implement that logic right now.\n * We will see if that approach remains stable.\n */\n #control: Attribution;\n\n #attributionStrings = reactive<string[]>([], { equal: shallowEqual });\n\n // Attribution strings wrapped in objects, for forward compat.\n #attributionItems = computed<AttributionItem[]>(() =>\n this.#attributionStrings.value.map((attribution) => ({\n text: attribution\n }))\n );\n\n #resources: Resource[] = [];\n\n constructor(options: {\n olMap: OlMap;\n /** false: not rendered */\n showControl: boolean;\n intl: ReadonlyReactive<PackageIntl>;\n }) {\n this.#olMap = options.olMap;\n this.#intl = options.intl;\n\n const control = (this.#control = new Attribution({\n collapsible: false,\n target: options.showControl ? undefined : createDummyTargetNode()\n }));\n interceptAttributions(\n control,\n // Called by the attributions widgets as a side effect.\n // NOTE: this is currently called very often (~ every map render).\n (attributions) => {\n this.#attributionStrings.value = attributions;\n }\n );\n\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n const element = (control as any).element as HTMLElement | undefined;\n if (element) {\n element.role = \"region\";\n this.#resources.push(\n effect(() => {\n element.ariaLabel = this.#intl.value.formatMessage({ id: \"attribution.label\" });\n })\n );\n }\n\n this.#olMap.addControl(control);\n }\n\n destroy() {\n this.#olMap.removeControl(this.#control);\n destroyResources(this.#resources);\n this.#control.dispose();\n }\n\n get attributionItems(): AttributionItem[] {\n return this.#attributionItems.value;\n }\n}\n\n// Overrides the OpenLayers widget to sanitize HTML attributions and to intercept the computed array of strings.\n// Note that this depends on OpenLayers internals that may change between versions.\nfunction interceptAttributions(attr: Attribution, onUpdate: (attributions: string[]) => void) {\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-function-type\n const originalCollectSourceAttributions = (attr as any).collectSourceAttributions_ as Function;\n if (!originalCollectSourceAttributions) {\n throw new Error(\"Internal error: failed to override attributions widget\");\n }\n\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n (attr as any).collectSourceAttributions_ = (frameState: FrameState) => {\n const rawAttributions = originalCollectSourceAttributions.call(\n attr,\n frameState\n ) as string[];\n if (!Array.isArray(rawAttributions)) {\n throw new Error(\"Internal error: unexpected attributions result (should be an array)\");\n }\n const sanitizedAttributions = rawAttributions.map((a) => sanitizeHtml(a));\n onUpdate(sanitizedAttributions);\n return sanitizedAttributions;\n };\n}\n\nfunction createDummyTargetNode() {\n const node = document.createElement(\"div\");\n node.style.display = \"none\";\n node.className = \"map-attribution-dummy-target\";\n return node;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"MapAttributions.js","sources":["MapAttributions.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\n\nimport { computed, effect, reactive, ReadonlyReactive } from \"@conterra/reactivity-core\";\nimport { destroyResources, Resource, shallowEqual } from \"@open-pioneer/core\";\nimport { PackageIntl } from \"@open-pioneer/runtime\";\nimport Attribution from \"ol/control/Attribution\";\nimport OlMap, { FrameState } from \"ol/Map\";\nimport { sanitizeHtml } from \"../utils/sanitize\";\nimport { AttributionItem } from \"./MapModel\";\n\nexport class MapAttributions {\n #olMap: OlMap;\n #intl: ReadonlyReactive<PackageIntl>;\n\n /**\n * When default rendering of attributions is active, we simply display this control on the map (otherwise: hidden).\n *\n * The control is always active (even if invisible) because we re-use its rendering code to extract the attribution items.\n * There is no real API to extract the attributions from OpenLayers, and we don't want to re-implement that logic right now.\n * We will see if that approach remains stable.\n */\n #control: Attribution;\n\n #attributionStrings = reactive<string[]>([], { equal: shallowEqual });\n\n // Attribution strings wrapped in objects, for forward compat.\n #attributionItems = computed<AttributionItem[]>(() =>\n this.#attributionStrings.value.map((attribution) => ({\n text: attribution\n }))\n );\n\n #resources: Resource[] = [];\n\n constructor(options: {\n olMap: OlMap;\n /** false: not rendered */\n showControl: boolean;\n intl: ReadonlyReactive<PackageIntl>;\n }) {\n this.#olMap = options.olMap;\n this.#intl = options.intl;\n\n const control = (this.#control = new Attribution({\n collapsible: false,\n target: options.showControl ? undefined : createDummyTargetNode()\n }));\n interceptAttributions(\n control,\n // Called by the attributions widgets as a side effect.\n // NOTE: this is currently called very often (~ every map render).\n (attributions) => {\n this.#attributionStrings.value = attributions;\n }\n );\n\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n const element = (control as any).element as HTMLElement | undefined;\n if (element) {\n element.role = \"region\";\n this.#resources.push(\n effect(() => {\n element.ariaLabel = this.#intl.value.formatMessage({ id: \"attribution.label\" });\n })\n );\n }\n\n this.#olMap.addControl(control);\n }\n\n destroy() {\n this.#olMap.removeControl(this.#control);\n destroyResources(this.#resources);\n this.#control.dispose();\n }\n\n get attributionItems(): AttributionItem[] {\n return this.#attributionItems.value;\n }\n}\n\n// Overrides the OpenLayers widget to sanitize HTML attributions and to intercept the computed array of strings.\n// Note that this depends on OpenLayers internals that may change between versions.\nfunction interceptAttributions(attr: Attribution, onUpdate: (attributions: string[]) => void) {\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-function-type\n const originalCollectSourceAttributions = (attr as any).collectSourceAttributions_ as Function;\n if (!originalCollectSourceAttributions) {\n throw new Error(\"Internal error: failed to override attributions widget\");\n }\n\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n (attr as any).collectSourceAttributions_ = (frameState: FrameState) => {\n const rawAttributions = originalCollectSourceAttributions.call(\n attr,\n frameState\n ) as string[];\n if (!Array.isArray(rawAttributions)) {\n throw new Error(\"Internal error: unexpected attributions result (should be an array)\");\n }\n const sanitizedAttributions = rawAttributions.map((a) => sanitizeHtml(a));\n onUpdate(sanitizedAttributions);\n return sanitizedAttributions;\n };\n}\n\nfunction createDummyTargetNode() {\n const node = document.createElement(\"div\");\n node.style.display = \"none\";\n node.className = \"map-attribution-dummy-target\";\n return node;\n}\n"],"names":[],"mappings":"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"}
@@ -12,7 +12,7 @@ import { BaseFeature } from "../utils/BaseFeature";
12
12
  import { InternalConstructorTag } from "../utils/InternalConstructorTag";
13
13
  import { Highlight, HighlightOptions, Highlights, HighlightZoomOptions } from "./Highlights";
14
14
  import { LayerCollection } from "./LayerCollection";
15
- import { ExtentConfig } from "./MapConfig";
15
+ import { ExtentConfig, InitialPositionConfig } from "./MapConfig";
16
16
  import { Overlays } from "./Overlays";
17
17
  export declare const DISPLAY_STATUS: unique symbol;
18
18
  /**
@@ -86,6 +86,7 @@ export declare class MapModel {
86
86
  constructor(options: {
87
87
  id: string;
88
88
  olMap: OlMap;
89
+ initialPosition: InitialPositionConfig | undefined;
89
90
  initialExtent: ExtentConfig | undefined;
90
91
  showDefaultAttributions: boolean;
91
92
  currentIntl: ReadonlyReactive<PackageIntl>;
package/model/MapModel.js CHANGED
@@ -46,7 +46,7 @@ class MapModel {
46
46
  #viewBindings;
47
47
  #scale;
48
48
  #abortController = new AbortController();
49
- #displayStatus;
49
+ #displayStatus = reactive("waiting");
50
50
  #displayWaiter;
51
51
  /**
52
52
  * @internal
@@ -72,10 +72,10 @@ class MapModel {
72
72
  this.#layerDeps = {
73
73
  httpService: options.httpService
74
74
  };
75
- this.#displayStatus = "waiting";
76
- this.#initializeView().then(
75
+ this.#displayStatus.value = "waiting";
76
+ this.#initializeView(options.initialPosition).then(
77
77
  () => {
78
- this.#displayStatus = "ready";
78
+ this.#displayStatus.value = "ready";
79
79
  this.#displayWaiter?.resolve();
80
80
  this.#displayWaiter = void 0;
81
81
  },
@@ -83,7 +83,7 @@ class MapModel {
83
83
  if (!isAbortError(error)) {
84
84
  LOG.error(`Failed to initialize map`, error);
85
85
  }
86
- this.#displayStatus = "error";
86
+ this.#displayStatus.value = "error";
87
87
  this.#displayWaiter?.reject(new Error(`Failed to initialize map.`));
88
88
  this.#displayWaiter = void 0;
89
89
  }
@@ -145,7 +145,7 @@ class MapModel {
145
145
  * @internal
146
146
  */
147
147
  get [DISPLAY_STATUS]() {
148
- return this.#displayStatus;
148
+ return this.#displayStatus.value;
149
149
  }
150
150
  /**
151
151
  * The unique id of the map.
@@ -372,10 +372,10 @@ class MapModel {
372
372
  if (this.#isDestroyed) {
373
373
  return Promise.reject(new Error("Map model was destroyed."));
374
374
  }
375
- if (this.#displayStatus === "error") {
375
+ if (this.#displayStatus.value === "error") {
376
376
  return Promise.reject(new Error(`Failed to initialize map.`));
377
377
  }
378
- if (this.#displayStatus === "ready") {
378
+ if (this.#displayStatus.value === "ready") {
379
379
  return Promise.resolve();
380
380
  }
381
381
  return (this.#displayWaiter ??= createManualPromise()).promise;
@@ -387,7 +387,7 @@ class MapModel {
387
387
  * AbortError is thrown when cancelled via `this.#abortController`, for example
388
388
  * when the map model is destroyed before it has ever been displayed.
389
389
  */
390
- async #initializeView() {
390
+ async #initializeView(initialPosition) {
391
391
  try {
392
392
  await waitForMapSize(this.olMap, this.#abortController.signal);
393
393
  } catch (e) {
@@ -410,6 +410,10 @@ class MapModel {
410
410
  view.setCenter(olCenter);
411
411
  view.setResolution(resolution);
412
412
  } else {
413
+ if (initialPosition) {
414
+ view.setZoom(initialPosition.zoom);
415
+ view.setCenter([initialPosition.center.x, initialPosition.center.y]);
416
+ }
413
417
  const olExtent = view.calculateExtent();
414
418
  const [xMin = 0, yMin = 0, xMax = 0, yMax = 0] = olExtent;
415
419
  const extent = { xMin, yMin, xMax, yMax };
@@ -435,21 +439,21 @@ class MapModel {
435
439
  function createViewBindings(view) {
436
440
  return {
437
441
  resolution: synchronized(
438
- () => view.getResolution(),
442
+ () => view.getResolution() ?? void 0,
439
443
  (cb) => {
440
444
  const key = view.on("change:resolution", cb);
441
445
  return () => unByKey(key);
442
446
  }
443
447
  ),
444
448
  center: synchronized(
445
- () => view.getCenter(),
449
+ () => view.getCenter() ?? void 0,
446
450
  (cb) => {
447
451
  const key = view.on("change:center", cb);
448
452
  return () => unByKey(key);
449
453
  }
450
454
  ),
451
455
  zoom: synchronized(
452
- () => view.getZoom(),
456
+ () => view.getZoom() ?? void 0,
453
457
  (cb) => {
454
458
  const key = view.on("change:resolution", cb);
455
459
  return () => unByKey(key);
@@ -1 +1 @@
1
- {"version":3,"file":"MapModel.js","sources":["MapModel.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\n\nimport { computed, reactive, ReadonlyReactive, synchronized } from \"@conterra/reactivity-core\";\nimport { emit, emitter, EventSource } from \"@conterra/reactivity-events\";\nimport {\n createAbortError,\n createLogger,\n createManualPromise,\n deprecated,\n isAbortError,\n ManualPromise\n} from \"@open-pioneer/core\";\nimport { HttpService } from \"@open-pioneer/http\";\nimport { PackageIntl } from \"@open-pioneer/runtime\";\nimport { Coordinate } from \"ol/coordinate\";\nimport { EventsKey } from \"ol/events\";\nimport { createEmpty, extend, getArea, getCenter } from \"ol/extent\";\nimport { Geometry } from \"ol/geom\";\nimport OlMap from \"ol/Map\";\nimport { unByKey } from \"ol/Observable\";\nimport { getPointResolution, Projection } from \"ol/proj\";\nimport OlView from \"ol/View\";\nimport { sourceId } from \"open-pioneer:source-info\";\nimport { LAYER_DEPS, LayerDependencies } from \"../layers/shared/internals\";\nimport { BaseFeature } from \"../utils/BaseFeature\";\nimport { calculateBufferedExtent } from \"../utils/geometry-utils\";\nimport {\n assertInternalConstructor,\n INTERNAL_CONSTRUCTOR_TAG,\n InternalConstructorTag\n} from \"../utils/InternalConstructorTag\";\nimport { getGeometries } from \"./getGeometries\";\nimport {\n DESTROY_HIGHLIGHTS,\n Highlight,\n HighlightOptions,\n Highlights,\n HighlightZoomOptions\n} from \"./Highlights\";\nimport { LayerCollection } from \"./LayerCollection\";\nimport { MapAttributions } from \"./MapAttributions\";\nimport { ExtentConfig } from \"./MapConfig\";\nimport { Overlays } from \"./Overlays\";\n\nconst LOG = createLogger(sourceId);\n\nconst DEFAULT_DPI = 25.4 / 0.28;\nconst INCHES_PER_METRE = 39.37;\n\nconst DEFAULT_OL_POINT_ZOOM_LEVEL = 17;\nconst DEFAULT_OL_MAX_ZOOM_LEVEL = 20;\nconst DEFAULT_VIEW_PADDING = { top: 50, right: 20, bottom: 10, left: 20 };\n\nexport const DISPLAY_STATUS = Symbol(\"DISPLAY_STATUS\");\n\nconst deprecatedHighlights = deprecated({\n name: \"MapModel highlight function called\",\n packageName: \"@open-pioneer/map\",\n since: \"v1.3.0\",\n alternative: \"call methods of myMapModel.highlights instead\"\n});\n\n/**\n * Options supported when calling {@link MapModel.zoom}.\n *\n * @group Map Model\n **/\nexport interface ZoomOptions {\n /**\n * The zoom-level used if there is no valid extend (such as for single points).\n */\n pointZoom?: number;\n\n /**\n * The maximum zoom-level for multiple points, line or polygon results.\n */\n maxZoom?: number;\n\n /**\n * The view padding to make all features visible.\n */\n viewPadding?: MapPadding;\n\n /**\n * The buffer factor around the extent of the zoomed features. E.g. a value of 1.1 will add\n * 10% to specify the size increase of the extent's width and height.\n */\n buffer?: number;\n}\n\n/**\n * Represents an object in the map.\n *\n * @group Map Model\n */\nexport type DisplayTarget = BaseFeature | Geometry;\n\n/**\n * Map padding, all values are pixels.\n *\n * See https://openlayers.org/en/latest/apidoc/module-ol_View-View.html#padding\n *\n * @group Map Model\n */\nexport interface MapPadding {\n left?: number;\n right?: number;\n top?: number;\n bottom?: number;\n}\n\n/**\n * An item that should be displayed as part of the attributions for the map.\n *\n * @group MapModel\n */\nexport interface AttributionItem {\n /**\n * The attribution's text.\n *\n * Note that this property contains raw HTML tags.\n * The HTML content has been sanitized, so it is safe to display in the user interface.\n */\n text: string;\n}\n\ntype DisplayStatus = \"waiting\" | \"ready\" | \"error\";\n\n/**\n * Represents a map.\n *\n * @group Map Model\n */\nexport class MapModel {\n readonly #id: string;\n readonly #olMap: OlMap;\n readonly #olView: ReadonlyReactive<OlView>;\n readonly #attributions: MapAttributions;\n readonly #layers = new LayerCollection(this, INTERNAL_CONSTRUCTOR_TAG);\n readonly #highlights: Highlights;\n readonly #tooltips: Overlays;\n readonly #layerDeps: LayerDependencies;\n readonly #destroyed = emitter();\n\n #loadStartEventHandler: EventsKey | undefined;\n #loadEndEventHandler: EventsKey | undefined;\n readonly #olLoading = reactive(false);\n\n #isDestroyed = false;\n readonly #container: ReadonlyReactive<HTMLElement | undefined>;\n readonly #initialExtent = reactive<ExtentConfig>();\n readonly #viewBindings: ReadonlyReactive<ViewBindings>;\n readonly #scale: ReadonlyReactive<number | undefined>;\n\n readonly #abortController = new AbortController();\n #displayStatus: DisplayStatus;\n #displayWaiter: ManualPromise<void> | undefined;\n\n /**\n * @internal\n */\n constructor(\n options: {\n id: string;\n olMap: OlMap;\n initialExtent: ExtentConfig | undefined;\n showDefaultAttributions: boolean;\n currentIntl: ReadonlyReactive<PackageIntl>;\n httpService: HttpService;\n },\n tag: InternalConstructorTag\n ) {\n assertInternalConstructor(tag);\n\n this.#id = options.id;\n this.#olMap = options.olMap;\n this.#attributions = new MapAttributions({\n intl: options.currentIntl,\n olMap: this.#olMap,\n showControl: options.showDefaultAttributions\n });\n\n this.#olView = synchronized(\n () => this.#olMap.getView(),\n (cb) => {\n const key = this.#olMap.on(\"change:view\", cb);\n return () => unByKey(key);\n }\n );\n\n // NOTE: As early as possible (before any async actions) so we don't miss any events.\n this.#watchLoadingState();\n\n this.#initialExtent.value = options.initialExtent;\n this.#layerDeps = {\n httpService: options.httpService\n };\n\n this.#displayStatus = \"waiting\";\n this.#initializeView().then(\n () => {\n this.#displayStatus = \"ready\";\n this.#displayWaiter?.resolve();\n this.#displayWaiter = undefined;\n },\n (error) => {\n if (!isAbortError(error)) {\n LOG.error(`Failed to initialize map`, error);\n }\n\n this.#displayStatus = \"error\";\n this.#displayWaiter?.reject(new Error(`Failed to initialize map.`));\n this.#displayWaiter = undefined;\n }\n );\n\n this.#container = synchronized(\n () => this.#olMap.getTargetElement() ?? undefined,\n (cb) => {\n const key = this.#olMap.on(\"change:target\", cb);\n return () => unByKey(key);\n }\n );\n\n this.#viewBindings = computed(() => createViewBindings(this.#olView.value));\n this.#scale = computed(() => {\n const { projection, resolution, center } = this;\n if (projection == null || resolution == null || center == null) {\n return undefined;\n }\n\n /**\n * Returns the appropriate scale for the given resolution and units, see OpenLayers function getScaleForResolution()\n * https://github.com/openlayers/openlayers/blob/7fa9df03431e9e1bc517e6c414565d9f848a3132/src/ol/control/ScaleLine.js#L454C3-L454C24\n */\n const pointResolution = getPointResolution(projection, resolution, center, \"m\"); //point resolution in meter per pixel\n const scale = Math.round(pointResolution * INCHES_PER_METRE * DEFAULT_DPI);\n return scale;\n });\n\n // expects fully constructed mapModel\n this.#highlights = new Highlights(this, this.#layerDeps);\n this.#tooltips = new Overlays(this);\n }\n\n /**\n * Destroys this objects, including all layers, highlights and the OL map itself.\n */\n destroy() {\n if (this.#isDestroyed) {\n return;\n }\n\n this.#isDestroyed = true;\n try {\n emit(this.#destroyed);\n } catch (e) {\n LOG.warn(`Unexpected error from event listener during map model destruction:`, e);\n }\n\n this.#loadStartEventHandler && unByKey(this.#loadStartEventHandler);\n this.#loadStartEventHandler = undefined;\n this.#loadEndEventHandler && unByKey(this.#loadEndEventHandler);\n this.#loadEndEventHandler = undefined;\n\n this.#abortController.abort();\n this.#displayWaiter?.reject(new Error(\"Map model was destroyed.\"));\n this.#layers.destroy();\n this.#highlights[DESTROY_HIGHLIGHTS]();\n this.#attributions.destroy();\n this.#olMap.dispose();\n }\n\n /**\n * Emitted when the map model is destroyed.\n */\n get destroyed(): EventSource<void> {\n return this.#destroyed;\n }\n\n /**\n * Returns the map's current display status.\n * This is `waiting` during initialization and `error` or `ready` when done.\n *\n * @internal\n */\n get [DISPLAY_STATUS](): DisplayStatus {\n return this.#displayStatus;\n }\n\n /**\n * The unique id of the map.\n */\n get id(): string {\n return this.#id;\n }\n\n /**\n * The initial map extent.\n *\n * May be undefined before the map is shown.\n * This is guaranteed to be initialized if the promise returned by {@link whenDisplayed} has resolved.\n */\n get initialExtent(): ExtentConfig | undefined {\n return this.#initialExtent.value;\n }\n\n /**\n * Returns the current projection of the map (reactive).\n */\n get projection(): Projection {\n return this.#viewBindings.value.projection;\n }\n\n /**\n * Returns the current center of the map.\n * Same as `olView.getCenter()`, but reactive.\n */\n get center(): Coordinate | undefined {\n return this.#viewBindings.value.center.value;\n }\n\n /**\n * Returns the current resolution of the map.\n * Same as `olView.getResolution()`, but reactive.\n */\n get resolution(): number | undefined {\n return this.#viewBindings.value.resolution.value;\n }\n\n /**\n * Returns the current zoom level of the map.\n * Same as `olView.getZoom()`, but reactive.\n */\n get zoomLevel(): number | undefined {\n return this.#viewBindings.value.zoom.value;\n }\n\n /**\n * Returns the current rotation of the map.\n * Same as `olView.getRotation()`, but reactive.\n */\n get rotation(): number | undefined {\n return this.#viewBindings.value.rotation.value;\n }\n\n /**\n * Returns the current scale of the map.\n *\n * The scale is a value derived from the current `center`, `resolution` and `projection` of the map.\n * The scale will change when the map is zoomed in our out, but depending on the projection, it may also\n * change when the map is _panned_.\n *\n * > NOTE: Technically, this is the _denominator_ of the current scale.\n * > In order to display it, use a format like `1:${scale}`.\n */\n get scale(): number | undefined {\n return this.#scale.value;\n }\n\n /**\n * Returns true if the map is currently loading.\n *\n * This is based on the OpenLayers events `loadstart` and `loadend`,\n * see [Documentation](https://openlayers.org/en/latest/apidoc/module-ol_MapEvent-MapEvent.html#event:loadstart).\n */\n get loading(): boolean {\n return this.#olLoading.value;\n }\n\n /**\n * Contains all known layers of this map.\n *\n * Note that not all layers in this collection may be active in the OpenLayers map.\n * Also note that not all layers in the OpenLayers map may be contained in this collection.\n */\n get layers(): LayerCollection {\n return this.#layers;\n }\n\n /**\n * The container in which the map is currently being rendered.\n * This is the same as the target element of the underlying OpenLayers map.\n *\n * May be undefined if the map is not being rendered at the moment.\n * May change at runtime.\n */\n get container(): HTMLElement | undefined {\n return this.#container.value;\n }\n\n /**\n * Returns attributions for the current content of the map.\n */\n get attributionItems(): AttributionItem[] {\n return this.#attributions.attributionItems;\n }\n\n /**\n * The raw OpenLayers map.\n */\n get olMap(): OlMap {\n return this.#olMap;\n }\n\n /**\n * Returns the current view of the OpenLayers map.\n */\n get olView(): OlView {\n return this.#olView.value;\n }\n\n /**\n * TODO: Can be removed once the LayerFactory is the only supported way of constructing a layer.\n *\n * @internal\n */\n get [LAYER_DEPS](): LayerDependencies {\n return this.#layerDeps;\n }\n\n /**\n * Create and receive map overlays\n */\n get overlays(): Overlays {\n return this.#tooltips;\n }\n\n /**\n * Create, receive and zoom to map highlights\n */\n get highlights(): Highlights {\n return this.#highlights;\n }\n\n /**\n * Changes the current scale of the map to the given value.\n *\n * Internally, this computes a new zoom level / resolution based on the scale\n * and the current center.\n * The new resolution is then applied to the current `olView`.\n *\n * See also {@link scale}.\n */\n setScale(newScale: number): void {\n const view = this.olView;\n const projection = this.projection;\n const center = this.center;\n if (!center) {\n return;\n }\n\n const mpu = projection.getMetersPerUnit() ?? 1;\n const resolution = INCHES_PER_METRE * DEFAULT_DPI * mpu;\n const pointResolution = newScale / getPointResolution(projection, resolution, center);\n view.setResolution(pointResolution);\n }\n\n /**\n * Zooms to the given targets.\n */\n zoom(displayTargets: DisplayTarget[], options?: ZoomOptions | undefined): void {\n const olView = this.olView;\n const geometries = getGeometries(displayTargets);\n if (geometries.length === 0) {\n return;\n }\n\n let extent = createEmpty();\n for (const geometry of geometries) {\n extent = extend(extent, geometry.getExtent());\n }\n\n const bufferParameter = options?.buffer;\n if (typeof bufferParameter === \"number\") {\n extent = calculateBufferedExtent(extent, bufferParameter);\n }\n\n const center = getCenter(extent);\n const isPoint = getArea(extent) === 0;\n const zoomLevel = isPoint\n ? (options?.pointZoom ?? DEFAULT_OL_POINT_ZOOM_LEVEL)\n : (options?.maxZoom ?? DEFAULT_OL_MAX_ZOOM_LEVEL);\n if (center && center.length) {\n olView.setCenter(center);\n }\n\n const {\n top = 0,\n right = 0,\n bottom = 0,\n left = 0\n } = options?.viewPadding ?? DEFAULT_VIEW_PADDING;\n const padding = [top, right, bottom, left];\n\n if (extent) {\n olView.fit(extent, { maxZoom: zoomLevel, padding });\n } else if (zoomLevel) {\n olView.setZoom(zoomLevel);\n }\n }\n\n /**\n * Creates a highlight at the given targets.\n *\n * A highlight is a temporary graphic on the map that calls attention to a point or an area.\n *\n * Call `destroy()` on the returned highlight object to remove the highlight.\n *\n * @deprecated Highlight functions will be removed in a future major release; call {@link Highlights.add} instead.\n */\n highlight(geometries: DisplayTarget[], options?: HighlightOptions | undefined): Highlight {\n deprecatedHighlights();\n return this.#highlights.add(geometries, options);\n }\n\n /**\n * Creates a highlight and zooms to the given targets.\n *\n * See also {@link highlight} and {@link zoom}.\n *\n * @deprecated Highlight functions will be removed in a future major release; call {@link Highlights.addAndZoom} instead.\n */\n highlightAndZoom(geometries: DisplayTarget[], options?: HighlightZoomOptions): Highlight {\n deprecatedHighlights();\n return this.#highlights.addAndZoom(geometries, options ?? {});\n }\n\n /**\n * Removes any existing highlights from the map.\n *\n * @deprecated Highlight functions wil be removed in a future major release; call {@link Highlights.clear} instead.\n */\n removeHighlights(): void {\n deprecatedHighlights();\n this.#highlights.clear();\n }\n\n /**\n * Returns a promise that resolves when the map has mounted in the DOM.\n */\n whenDisplayed(): Promise<void> {\n if (this.#isDestroyed) {\n return Promise.reject(new Error(\"Map model was destroyed.\"));\n }\n if (this.#displayStatus === \"error\") {\n return Promise.reject(new Error(`Failed to initialize map.`));\n }\n if (this.#displayStatus === \"ready\") {\n return Promise.resolve();\n }\n return (this.#displayWaiter ??= createManualPromise()).promise;\n }\n\n /**\n * Waits for the map to be displayed and then initializes the view (if necessary).\n *\n * May simply resolve when done, or throw an error when a problem occurs.\n * AbortError is thrown when cancelled via `this.#abortController`, for example\n * when the map model is destroyed before it has ever been displayed.\n */\n async #initializeView(): Promise<void> {\n try {\n await waitForMapSize(this.olMap, this.#abortController.signal); // may throw on cancel\n } catch (e) {\n if (isAbortError(e)) {\n throw e;\n }\n throw new Error(`Failed to wait for the map to be displayed.`, { cause: e });\n }\n\n try {\n const olMap = this.#olMap;\n const view = olMap.getView();\n\n if (this.#initialExtent.value) {\n // Initial extent was set from the outside. We simply ensure that it gets displayed by the map.\n const extent = this.#initialExtent.value;\n const olExtent = [extent.xMin, extent.yMin, extent.xMax, extent.yMax];\n\n const olCenter = getCenter(olExtent);\n const resolution = view.getResolutionForExtent(olExtent);\n LOG.debug(`Applying initial extent`, extent);\n LOG.debug(` Computed center:`, olCenter);\n LOG.debug(` Computed resolution:`, resolution);\n\n view.setCenter(olCenter);\n view.setResolution(resolution);\n } else {\n // Initial extent was NOT set from the outside.\n // We detect whatever the view is displaying and consider it to be the initial extent.\n const olExtent = view.calculateExtent();\n const [xMin = 0, yMin = 0, xMax = 0, yMax = 0] = olExtent;\n const extent: ExtentConfig = { xMin, yMin, xMax, yMax };\n LOG.debug(`Detected initial extent`, extent);\n\n this.#initialExtent.value = extent;\n }\n } catch (e) {\n throw new Error(`Failed to apply the initial extent.`, { cause: e });\n }\n }\n\n /**\n * Subscribes to the OpenLayers loading state.\n */\n #watchLoadingState() {\n this.#loadStartEventHandler = this.#olMap.on(\"loadstart\", () => {\n this.#olLoading.value = true;\n });\n this.#loadEndEventHandler = this.#olMap.on(\"loadend\", () => {\n this.#olLoading.value = false;\n });\n }\n}\n\ninterface ViewBindings {\n resolution: ReadonlyReactive<number | undefined>;\n center: ReadonlyReactive<Coordinate | undefined>;\n zoom: ReadonlyReactive<number | undefined>;\n rotation: ReadonlyReactive<number | undefined>;\n projection: Projection; // not reactive (change view to change projection)\n}\n\nfunction createViewBindings(view: OlView): ViewBindings {\n return {\n resolution: synchronized(\n () => view.getResolution(),\n (cb) => {\n const key = view.on(\"change:resolution\", cb);\n return () => unByKey(key);\n }\n ),\n center: synchronized(\n () => view.getCenter(),\n (cb) => {\n const key = view.on(\"change:center\", cb);\n return () => unByKey(key);\n }\n ),\n zoom: synchronized(\n () => view.getZoom(),\n (cb) => {\n const key = view.on(\"change:resolution\", cb);\n return () => unByKey(key);\n }\n ),\n rotation: synchronized(\n () => view.getRotation(),\n (cb) => {\n const key = view.on(\"change:rotation\", cb);\n return () => unByKey(key);\n }\n ),\n projection: view.getProjection()\n };\n}\n\nfunction waitForMapSize(olMap: OlMap, signal: AbortSignal): Promise<void> {\n const promise = new Promise<void>((resolve, reject) => {\n let eventKey: EventsKey | undefined;\n\n function checkSize() {\n const currentSize = olMap.getSize() ?? [];\n const [width = 0, height = 0] = currentSize;\n if (currentSize && width > 0 && height > 0) {\n finish();\n }\n }\n\n function onAbort() {\n finish(createAbortError());\n }\n\n function finish(error?: Error | undefined) {\n if (eventKey) {\n unByKey(eventKey);\n eventKey = undefined;\n }\n signal.removeEventListener(\"abort\", onAbort);\n\n if (error) {\n reject(error);\n } else {\n resolve(wait(25)); // Give the map some time to render\n }\n }\n\n if (signal.aborted) {\n finish(createAbortError());\n return;\n }\n\n signal.addEventListener(\"abort\", onAbort);\n eventKey = olMap.on(\"change:size\", checkSize);\n });\n return promise;\n}\n\nfunction wait(milliseconds: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, milliseconds));\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"MapModel.js","sources":["MapModel.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\n\nimport { computed, reactive, ReadonlyReactive, synchronized } from \"@conterra/reactivity-core\";\nimport { emit, emitter, EventSource } from \"@conterra/reactivity-events\";\nimport {\n createAbortError,\n createLogger,\n createManualPromise,\n deprecated,\n isAbortError,\n ManualPromise\n} from \"@open-pioneer/core\";\nimport { HttpService } from \"@open-pioneer/http\";\nimport { PackageIntl } from \"@open-pioneer/runtime\";\nimport { Coordinate } from \"ol/coordinate\";\nimport { EventsKey } from \"ol/events\";\nimport { createEmpty, extend, getArea, getCenter } from \"ol/extent\";\nimport { Geometry } from \"ol/geom\";\nimport OlMap from \"ol/Map\";\nimport { unByKey } from \"ol/Observable\";\nimport { getPointResolution, Projection } from \"ol/proj\";\nimport OlView from \"ol/View\";\nimport { sourceId } from \"open-pioneer:source-info\";\nimport { LAYER_DEPS, LayerDependencies } from \"../layers/shared/internals\";\nimport { BaseFeature } from \"../utils/BaseFeature\";\nimport { calculateBufferedExtent } from \"../utils/geometry-utils\";\nimport {\n assertInternalConstructor,\n INTERNAL_CONSTRUCTOR_TAG,\n InternalConstructorTag\n} from \"../utils/InternalConstructorTag\";\nimport { getGeometries } from \"./getGeometries\";\nimport {\n DESTROY_HIGHLIGHTS,\n Highlight,\n HighlightOptions,\n Highlights,\n HighlightZoomOptions\n} from \"./Highlights\";\nimport { LayerCollection } from \"./LayerCollection\";\nimport { MapAttributions } from \"./MapAttributions\";\nimport { ExtentConfig, InitialPositionConfig } from \"./MapConfig\";\nimport { Overlays } from \"./Overlays\";\n\nconst LOG = createLogger(sourceId);\n\nconst DEFAULT_DPI = 25.4 / 0.28;\nconst INCHES_PER_METRE = 39.37;\n\nconst DEFAULT_OL_POINT_ZOOM_LEVEL = 17;\nconst DEFAULT_OL_MAX_ZOOM_LEVEL = 20;\nconst DEFAULT_VIEW_PADDING = { top: 50, right: 20, bottom: 10, left: 20 };\n\nexport const DISPLAY_STATUS = Symbol(\"DISPLAY_STATUS\");\n\nconst deprecatedHighlights = deprecated({\n name: \"MapModel highlight function called\",\n packageName: \"@open-pioneer/map\",\n since: \"v1.3.0\",\n alternative: \"call methods of myMapModel.highlights instead\"\n});\n\n/**\n * Options supported when calling {@link MapModel.zoom}.\n *\n * @group Map Model\n **/\nexport interface ZoomOptions {\n /**\n * The zoom-level used if there is no valid extend (such as for single points).\n */\n pointZoom?: number;\n\n /**\n * The maximum zoom-level for multiple points, line or polygon results.\n */\n maxZoom?: number;\n\n /**\n * The view padding to make all features visible.\n */\n viewPadding?: MapPadding;\n\n /**\n * The buffer factor around the extent of the zoomed features. E.g. a value of 1.1 will add\n * 10% to specify the size increase of the extent's width and height.\n */\n buffer?: number;\n}\n\n/**\n * Represents an object in the map.\n *\n * @group Map Model\n */\nexport type DisplayTarget = BaseFeature | Geometry;\n\n/**\n * Map padding, all values are pixels.\n *\n * See https://openlayers.org/en/latest/apidoc/module-ol_View-View.html#padding\n *\n * @group Map Model\n */\nexport interface MapPadding {\n left?: number;\n right?: number;\n top?: number;\n bottom?: number;\n}\n\n/**\n * An item that should be displayed as part of the attributions for the map.\n *\n * @group MapModel\n */\nexport interface AttributionItem {\n /**\n * The attribution's text.\n *\n * Note that this property contains raw HTML tags.\n * The HTML content has been sanitized, so it is safe to display in the user interface.\n */\n text: string;\n}\n\ntype DisplayStatus = \"waiting\" | \"ready\" | \"error\";\n\n/**\n * Represents a map.\n *\n * @group Map Model\n */\nexport class MapModel {\n readonly #id: string;\n readonly #olMap: OlMap;\n readonly #olView: ReadonlyReactive<OlView>;\n readonly #attributions: MapAttributions;\n readonly #layers = new LayerCollection(this, INTERNAL_CONSTRUCTOR_TAG);\n readonly #highlights: Highlights;\n readonly #tooltips: Overlays;\n readonly #layerDeps: LayerDependencies;\n readonly #destroyed = emitter();\n\n #loadStartEventHandler: EventsKey | undefined;\n #loadEndEventHandler: EventsKey | undefined;\n readonly #olLoading = reactive(false);\n\n #isDestroyed = false;\n readonly #container: ReadonlyReactive<HTMLElement | undefined>;\n readonly #initialExtent = reactive<ExtentConfig>();\n readonly #viewBindings: ReadonlyReactive<ViewBindings>;\n readonly #scale: ReadonlyReactive<number | undefined>;\n\n readonly #abortController = new AbortController();\n #displayStatus = reactive<DisplayStatus>(\"waiting\");\n #displayWaiter: ManualPromise<void> | undefined;\n\n /**\n * @internal\n */\n constructor(\n options: {\n id: string;\n olMap: OlMap;\n initialPosition: InitialPositionConfig | undefined;\n initialExtent: ExtentConfig | undefined;\n showDefaultAttributions: boolean;\n currentIntl: ReadonlyReactive<PackageIntl>;\n httpService: HttpService;\n },\n tag: InternalConstructorTag\n ) {\n assertInternalConstructor(tag);\n\n this.#id = options.id;\n this.#olMap = options.olMap;\n this.#attributions = new MapAttributions({\n intl: options.currentIntl,\n olMap: this.#olMap,\n showControl: options.showDefaultAttributions\n });\n\n this.#olView = synchronized(\n () => this.#olMap.getView(),\n (cb) => {\n const key = this.#olMap.on(\"change:view\", cb);\n return () => unByKey(key);\n }\n );\n\n // NOTE: As early as possible (before any async actions) so we don't miss any events.\n this.#watchLoadingState();\n\n this.#initialExtent.value = options.initialExtent;\n this.#layerDeps = {\n httpService: options.httpService\n };\n\n this.#displayStatus.value = \"waiting\";\n this.#initializeView(options.initialPosition).then(\n () => {\n this.#displayStatus.value = \"ready\";\n this.#displayWaiter?.resolve();\n this.#displayWaiter = undefined;\n },\n (error) => {\n if (!isAbortError(error)) {\n LOG.error(`Failed to initialize map`, error);\n }\n\n this.#displayStatus.value = \"error\";\n this.#displayWaiter?.reject(new Error(`Failed to initialize map.`));\n this.#displayWaiter = undefined;\n }\n );\n\n this.#container = synchronized(\n () => this.#olMap.getTargetElement() ?? undefined,\n (cb) => {\n const key = this.#olMap.on(\"change:target\", cb);\n return () => unByKey(key);\n }\n );\n\n this.#viewBindings = computed(() => createViewBindings(this.#olView.value));\n this.#scale = computed(() => {\n const { projection, resolution, center } = this;\n if (projection == null || resolution == null || center == null) {\n return undefined;\n }\n\n /**\n * Returns the appropriate scale for the given resolution and units, see OpenLayers function getScaleForResolution()\n * https://github.com/openlayers/openlayers/blob/7fa9df03431e9e1bc517e6c414565d9f848a3132/src/ol/control/ScaleLine.js#L454C3-L454C24\n */\n const pointResolution = getPointResolution(projection, resolution, center, \"m\"); //point resolution in meter per pixel\n const scale = Math.round(pointResolution * INCHES_PER_METRE * DEFAULT_DPI);\n return scale;\n });\n\n // expects fully constructed mapModel\n this.#highlights = new Highlights(this, this.#layerDeps);\n this.#tooltips = new Overlays(this);\n }\n\n /**\n * Destroys this objects, including all layers, highlights and the OL map itself.\n */\n destroy() {\n if (this.#isDestroyed) {\n return;\n }\n\n this.#isDestroyed = true;\n try {\n emit(this.#destroyed);\n } catch (e) {\n LOG.warn(`Unexpected error from event listener during map model destruction:`, e);\n }\n\n this.#loadStartEventHandler && unByKey(this.#loadStartEventHandler);\n this.#loadStartEventHandler = undefined;\n this.#loadEndEventHandler && unByKey(this.#loadEndEventHandler);\n this.#loadEndEventHandler = undefined;\n\n this.#abortController.abort();\n this.#displayWaiter?.reject(new Error(\"Map model was destroyed.\"));\n this.#layers.destroy();\n this.#highlights[DESTROY_HIGHLIGHTS]();\n this.#attributions.destroy();\n this.#olMap.dispose();\n }\n\n /**\n * Emitted when the map model is destroyed.\n */\n get destroyed(): EventSource<void> {\n return this.#destroyed;\n }\n\n /**\n * Returns the map's current display status.\n * This is `waiting` during initialization and `error` or `ready` when done.\n *\n * @internal\n */\n get [DISPLAY_STATUS](): DisplayStatus {\n return this.#displayStatus.value;\n }\n\n /**\n * The unique id of the map.\n */\n get id(): string {\n return this.#id;\n }\n\n /**\n * The initial map extent.\n *\n * May be undefined before the map is shown.\n * This is guaranteed to be initialized if the promise returned by {@link whenDisplayed} has resolved.\n */\n get initialExtent(): ExtentConfig | undefined {\n return this.#initialExtent.value;\n }\n\n /**\n * Returns the current projection of the map (reactive).\n */\n get projection(): Projection {\n return this.#viewBindings.value.projection;\n }\n\n /**\n * Returns the current center of the map.\n * Same as `olView.getCenter()`, but reactive.\n */\n get center(): Coordinate | undefined {\n return this.#viewBindings.value.center.value;\n }\n\n /**\n * Returns the current resolution of the map.\n * Same as `olView.getResolution()`, but reactive.\n */\n get resolution(): number | undefined {\n return this.#viewBindings.value.resolution.value;\n }\n\n /**\n * Returns the current zoom level of the map.\n * Same as `olView.getZoom()`, but reactive.\n */\n get zoomLevel(): number | undefined {\n return this.#viewBindings.value.zoom.value;\n }\n\n /**\n * Returns the current rotation of the map.\n * Same as `olView.getRotation()`, but reactive.\n */\n get rotation(): number | undefined {\n return this.#viewBindings.value.rotation.value;\n }\n\n /**\n * Returns the current scale of the map.\n *\n * The scale is a value derived from the current `center`, `resolution` and `projection` of the map.\n * The scale will change when the map is zoomed in our out, but depending on the projection, it may also\n * change when the map is _panned_.\n *\n * > NOTE: Technically, this is the _denominator_ of the current scale.\n * > In order to display it, use a format like `1:${scale}`.\n */\n get scale(): number | undefined {\n return this.#scale.value;\n }\n\n /**\n * Returns true if the map is currently loading.\n *\n * This is based on the OpenLayers events `loadstart` and `loadend`,\n * see [Documentation](https://openlayers.org/en/latest/apidoc/module-ol_MapEvent-MapEvent.html#event:loadstart).\n */\n get loading(): boolean {\n return this.#olLoading.value;\n }\n\n /**\n * Contains all known layers of this map.\n *\n * Note that not all layers in this collection may be active in the OpenLayers map.\n * Also note that not all layers in the OpenLayers map may be contained in this collection.\n */\n get layers(): LayerCollection {\n return this.#layers;\n }\n\n /**\n * The container in which the map is currently being rendered.\n * This is the same as the target element of the underlying OpenLayers map.\n *\n * May be undefined if the map is not being rendered at the moment.\n * May change at runtime.\n */\n get container(): HTMLElement | undefined {\n return this.#container.value;\n }\n\n /**\n * Returns attributions for the current content of the map.\n */\n get attributionItems(): AttributionItem[] {\n return this.#attributions.attributionItems;\n }\n\n /**\n * The raw OpenLayers map.\n */\n get olMap(): OlMap {\n return this.#olMap;\n }\n\n /**\n * Returns the current view of the OpenLayers map.\n */\n get olView(): OlView {\n return this.#olView.value;\n }\n\n /**\n * TODO: Can be removed once the LayerFactory is the only supported way of constructing a layer.\n *\n * @internal\n */\n get [LAYER_DEPS](): LayerDependencies {\n return this.#layerDeps;\n }\n\n /**\n * Create and receive map overlays\n */\n get overlays(): Overlays {\n return this.#tooltips;\n }\n\n /**\n * Create, receive and zoom to map highlights\n */\n get highlights(): Highlights {\n return this.#highlights;\n }\n\n /**\n * Changes the current scale of the map to the given value.\n *\n * Internally, this computes a new zoom level / resolution based on the scale\n * and the current center.\n * The new resolution is then applied to the current `olView`.\n *\n * See also {@link scale}.\n */\n setScale(newScale: number): void {\n const view = this.olView;\n const projection = this.projection;\n const center = this.center;\n if (!center) {\n return;\n }\n\n const mpu = projection.getMetersPerUnit() ?? 1;\n const resolution = INCHES_PER_METRE * DEFAULT_DPI * mpu;\n const pointResolution = newScale / getPointResolution(projection, resolution, center);\n view.setResolution(pointResolution);\n }\n\n /**\n * Zooms to the given targets.\n */\n zoom(displayTargets: DisplayTarget[], options?: ZoomOptions | undefined): void {\n const olView = this.olView;\n const geometries = getGeometries(displayTargets);\n if (geometries.length === 0) {\n return;\n }\n\n let extent = createEmpty();\n for (const geometry of geometries) {\n extent = extend(extent, geometry.getExtent());\n }\n\n const bufferParameter = options?.buffer;\n if (typeof bufferParameter === \"number\") {\n extent = calculateBufferedExtent(extent, bufferParameter);\n }\n\n const center = getCenter(extent);\n const isPoint = getArea(extent) === 0;\n const zoomLevel = isPoint\n ? (options?.pointZoom ?? DEFAULT_OL_POINT_ZOOM_LEVEL)\n : (options?.maxZoom ?? DEFAULT_OL_MAX_ZOOM_LEVEL);\n if (center && center.length) {\n olView.setCenter(center);\n }\n\n const {\n top = 0,\n right = 0,\n bottom = 0,\n left = 0\n } = options?.viewPadding ?? DEFAULT_VIEW_PADDING;\n const padding = [top, right, bottom, left];\n\n if (extent) {\n olView.fit(extent, { maxZoom: zoomLevel, padding });\n } else if (zoomLevel) {\n olView.setZoom(zoomLevel);\n }\n }\n\n /**\n * Creates a highlight at the given targets.\n *\n * A highlight is a temporary graphic on the map that calls attention to a point or an area.\n *\n * Call `destroy()` on the returned highlight object to remove the highlight.\n *\n * @deprecated Highlight functions will be removed in a future major release; call {@link Highlights.add} instead.\n */\n highlight(geometries: DisplayTarget[], options?: HighlightOptions | undefined): Highlight {\n deprecatedHighlights();\n return this.#highlights.add(geometries, options);\n }\n\n /**\n * Creates a highlight and zooms to the given targets.\n *\n * See also {@link highlight} and {@link zoom}.\n *\n * @deprecated Highlight functions will be removed in a future major release; call {@link Highlights.addAndZoom} instead.\n */\n highlightAndZoom(geometries: DisplayTarget[], options?: HighlightZoomOptions): Highlight {\n deprecatedHighlights();\n return this.#highlights.addAndZoom(geometries, options ?? {});\n }\n\n /**\n * Removes any existing highlights from the map.\n *\n * @deprecated Highlight functions wil be removed in a future major release; call {@link Highlights.clear} instead.\n */\n removeHighlights(): void {\n deprecatedHighlights();\n this.#highlights.clear();\n }\n\n /**\n * Returns a promise that resolves when the map has mounted in the DOM.\n */\n whenDisplayed(): Promise<void> {\n if (this.#isDestroyed) {\n return Promise.reject(new Error(\"Map model was destroyed.\"));\n }\n if (this.#displayStatus.value === \"error\") {\n return Promise.reject(new Error(`Failed to initialize map.`));\n }\n if (this.#displayStatus.value === \"ready\") {\n return Promise.resolve();\n }\n return (this.#displayWaiter ??= createManualPromise()).promise;\n }\n\n /**\n * Waits for the map to be displayed and then initializes the view (if necessary).\n *\n * May simply resolve when done, or throw an error when a problem occurs.\n * AbortError is thrown when cancelled via `this.#abortController`, for example\n * when the map model is destroyed before it has ever been displayed.\n */\n async #initializeView(initialPosition: InitialPositionConfig | undefined): Promise<void> {\n try {\n await waitForMapSize(this.olMap, this.#abortController.signal); // may throw on cancel\n } catch (e) {\n if (isAbortError(e)) {\n throw e;\n }\n throw new Error(`Failed to wait for the map to be displayed.`, { cause: e });\n }\n\n try {\n const olMap = this.#olMap;\n const view = olMap.getView();\n\n if (this.#initialExtent.value) {\n // Initial extent was set from the outside. We simply ensure that it gets displayed by the map.\n const extent = this.#initialExtent.value;\n const olExtent = [extent.xMin, extent.yMin, extent.xMax, extent.yMax];\n\n const olCenter = getCenter(olExtent);\n const resolution = view.getResolutionForExtent(olExtent);\n LOG.debug(`Applying initial extent`, extent);\n LOG.debug(` Computed center:`, olCenter);\n LOG.debug(` Computed resolution:`, resolution);\n\n view.setCenter(olCenter);\n view.setResolution(resolution);\n } else {\n if (initialPosition) {\n view.setZoom(initialPosition.zoom);\n view.setCenter([initialPosition.center.x, initialPosition.center.y]);\n }\n\n // Initial extent was NOT set from the outside.\n // We detect whatever the view is displaying and consider it to be the initial extent.\n const olExtent = view.calculateExtent();\n const [xMin = 0, yMin = 0, xMax = 0, yMax = 0] = olExtent;\n const extent: ExtentConfig = { xMin, yMin, xMax, yMax };\n LOG.debug(`Detected initial extent`, extent);\n\n this.#initialExtent.value = extent;\n }\n } catch (e) {\n throw new Error(`Failed to apply the initial extent.`, { cause: e });\n }\n }\n\n /**\n * Subscribes to the OpenLayers loading state.\n */\n #watchLoadingState() {\n this.#loadStartEventHandler = this.#olMap.on(\"loadstart\", () => {\n this.#olLoading.value = true;\n });\n this.#loadEndEventHandler = this.#olMap.on(\"loadend\", () => {\n this.#olLoading.value = false;\n });\n }\n}\n\ninterface ViewBindings {\n resolution: ReadonlyReactive<number | undefined>;\n center: ReadonlyReactive<Coordinate | undefined>;\n zoom: ReadonlyReactive<number | undefined>;\n rotation: ReadonlyReactive<number | undefined>;\n projection: Projection; // not reactive (change view to change projection)\n}\n\nfunction createViewBindings(view: OlView): ViewBindings {\n return {\n resolution: synchronized(\n () => view.getResolution() ?? undefined,\n (cb) => {\n const key = view.on(\"change:resolution\", cb);\n return () => unByKey(key);\n }\n ),\n center: synchronized(\n () => view.getCenter() ?? undefined,\n (cb) => {\n const key = view.on(\"change:center\", cb);\n return () => unByKey(key);\n }\n ),\n zoom: synchronized(\n () => view.getZoom() ?? undefined,\n (cb) => {\n const key = view.on(\"change:resolution\", cb);\n return () => unByKey(key);\n }\n ),\n rotation: synchronized(\n () => view.getRotation(),\n (cb) => {\n const key = view.on(\"change:rotation\", cb);\n return () => unByKey(key);\n }\n ),\n projection: view.getProjection()\n };\n}\n\nfunction waitForMapSize(olMap: OlMap, signal: AbortSignal): Promise<void> {\n const promise = new Promise<void>((resolve, reject) => {\n let eventKey: EventsKey | undefined;\n\n function checkSize() {\n const currentSize = olMap.getSize() ?? [];\n const [width = 0, height = 0] = currentSize;\n if (currentSize && width > 0 && height > 0) {\n finish();\n }\n }\n\n function onAbort() {\n finish(createAbortError());\n }\n\n function finish(error?: Error | undefined) {\n if (eventKey) {\n unByKey(eventKey);\n eventKey = undefined;\n }\n signal.removeEventListener(\"abort\", onAbort);\n\n if (error) {\n reject(error);\n } else {\n resolve(wait(25)); // Give the map some time to render\n }\n }\n\n if (signal.aborted) {\n finish(createAbortError());\n return;\n }\n\n signal.addEventListener(\"abort\", onAbort);\n eventKey = olMap.on(\"change:size\", checkSize);\n });\n return promise;\n}\n\nfunction wait(milliseconds: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, milliseconds));\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"Overlays.js","sources":["Overlays.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\n\nimport {\n batch,\n reactive,\n Reactive,\n reactiveSet,\n synchronized,\n watchValue\n} from \"@conterra/reactivity-core\";\nimport { createLogger, destroyResources, Resource } from \"@open-pioneer/core\";\nimport { Map as OlMap, Overlay as OlOverlay } from \"ol\";\nimport { Coordinate } from \"ol/coordinate\";\nimport { EventsKey } from \"ol/events\";\nimport { unByKey } from \"ol/Observable\";\nimport { Options } from \"ol/Overlay\";\nimport { sourceId } from \"open-pioneer:source-info\";\nimport { ReactNode } from \"react\";\nimport { v4 as uuid4v } from \"uuid\";\nimport { INTERNAL_CONSTRUCTOR_TAG, InternalConstructorTag } from \"../utils/InternalConstructorTag\";\nimport { MapModel } from \"./MapModel\";\n\nexport const REGISTER_OVERLAY = Symbol(\"REGISTER_OVERLAY\");\nexport const UNREGISTER_OVERLAY = Symbol(\"UNREGISTER_OVERLAY\");\n\nconst LOG = createLogger(sourceId);\n\n/**\n * Manages active overlays on the map.\n *\n * @group Map Model\n */\nexport class Overlays {\n #olMap: OlMap;\n #overlays = reactiveSet<Overlay>();\n\n constructor(map: MapModel) {\n this.#olMap = map.olMap;\n }\n\n [REGISTER_OVERLAY](overlay: Overlay) {\n if (this.#overlays.has(overlay)) {\n throw new Error(\"Internal error: overlay is already registered\");\n }\n this.#overlays.add(overlay);\n this.#olMap.addOverlay(overlay.olOverlay);\n }\n\n [UNREGISTER_OVERLAY](overlay: Overlay) {\n if (!this.#overlays.has(overlay)) {\n throw new Error(\"Internal error: overlay was not registered\");\n }\n this.#overlays.delete(overlay);\n this.#olMap.removeOverlay(overlay.olOverlay);\n }\n\n /**\n * Add new overlay to the map. Returns the newly created overlay instance.\n */\n add(options: OverlayOptions): Overlay {\n const newModel = new Overlay(INTERNAL_CONSTRUCTOR_TAG, options, this);\n return newModel;\n }\n\n /**\n * Returns the list of all current overlays.\n */\n getAll(): Overlay[] {\n return Array.from(this.#overlays);\n }\n\n /**\n * Destroys all overlays.\n */\n clear(): void {\n for (const overlay of this.#overlays) {\n overlay.destroy();\n }\n }\n}\n\n/**\n * Options that define the initial state of an overlay.\n *\n * @group Map Model\n */\nexport interface OverlayOptions {\n /**\n * Optional, readonly tag that helps identifying the overlay instance.\n */\n tag?: string;\n\n /**\n * Displayed content of the overlay.\n *\n * @see {@link Overlay.setContent}.\n */\n content?: ReactNode;\n\n /**\n * CSS classes of the HTML element that wraps the overlay's content.\n */\n className?: string;\n\n /**\n * Role of the HTML element that wraps the overlay's content.\n */\n ariaRole?: string;\n\n /**\n * Configures the position of the overlay.\n * The overlay is not rendered if position is `undefined` (the default).\n *\n * See {@link OverlayPosition} for all supported position options.\n *\n * The following shorthands are available:\n * - A plain `Coordinate` array can be used to specify a static coordinate on the map.\n * - `undefined` hides the overlay.\n * - `\"follow-pointer\"` can be used as a shorthand to follow the user's cursor.\n *\n * @see {@link Overlay.setPosition} to reconfigure the position.\n * @see {@link Overlay.currentCoordinate} to retrieve the actual position on the map.\n */\n position?: Coordinate | \"follow-pointer\" | OverlayPosition;\n\n /**\n * Positioning of an overlay relative to its coordinates on the map.\n *\n * @see {@link Overlay.setPositioning}\n */\n positioning?: OverlayPositioning;\n\n /**\n * Offsets in _pixels_ relative to the overlay`s coordinates on the map.\n * The first element in the array is the horizontal offset.\n *\n * @see {@link Overlay.setOffset}\n */\n offset?: number[];\n\n /**\n * Determines if event propagation to the map viewport should be stopped.\n *\n * By default `stopEvent` is `true`.\n */\n stopEvent?: boolean;\n\n /**\n * Raw OpenLayers overlay properties. `OlOverlayOptions` override corresponding `OverlayProperties`, except for id and element.\n *\n * **warning** Using OpenLayers options can create inconsistencies that lead to errors.\n * The OpenLayers API can change with updates of OpenLayers.\n */\n advanced?: OlOverlayOptions;\n}\n\n/**\n * The configured position of an overlay.\n *\n * @group Map Model\n */\nexport type OverlayPosition =\n /** Explicit (static) coordinates on the map. */\n | OverlayPositionCoordinate\n /** Update coordinates based on pointer movements on the map, useful for tooltips. */\n | OverlayPositionFollowPointer;\n\n/**\n * Automatically positions the overlay on the mouse cursor's coordinates.\n *\n * This can be used, for example, to implement tooltips for map interactions.\n *\n * @group Map Model\n */\nexport interface OverlayPositionFollowPointer {\n kind: \"follow-pointer\";\n\n /**\n * The initial coordinates.\n *\n * Use `undefined` (the default) to hide until the first mouse event on the map.\n */\n initial?: Coordinate;\n}\n\n/**\n * Places the overlay at the given coordinates.\n *\n * @group Map Model\n */\nexport interface OverlayPositionCoordinate {\n kind: \"coordinate\";\n\n /**\n * The explicit coordinates of the overlay on the map.\n *\n * Using `undefined` hides the overlay.\n */\n coordinate?: Coordinate;\n}\n\n/**\n * Positioning of an overlay relative to its coordinates on the map.\n *\n * @group Map Model\n */\nexport type OverlayPositioning =\n | \"bottom-left\"\n | \"bottom-center\"\n | \"bottom-right\"\n | \"center-left\"\n | \"center-center\"\n | \"center-right\"\n | \"top-left\"\n | \"top-center\"\n | \"top-right\";\n\n/** @group Map Model */\nexport interface OlOverlayOptions extends Omit<Partial<Options>, \"id\" | \"element\"> {}\n\n/**\n * An overlay is an UI element that is displayed over the map.\n *\n * Overlays are tied to coordinates on the map and not to a position on the screen.\n * The overlay renders a react node at the specified coordinates.\n *\n * @group Map Model\n */\nexport class Overlay {\n /**\n * Unique, readonly id of the overlay.\n *\n * Automatically assigned when the overlay is created. Use the `tag` property for custom identifiers.\n */\n readonly id: string;\n\n /**\n * Optional, readonly tag that helps identifying the overlay instance.\n */\n readonly tag: string | undefined;\n\n /**\n * Raw, corresponding OpenLayers overlay object.\n *\n * **warning** Manipulation of the OpenLayers object can create inconsistencies that lead to errors. The OpenLayers API can change with updates of OpenLayers.\n *\n * @see https://openlayers.org/en/latest/apidoc/module-ol_Overlay-Overlay.html\n */\n readonly olOverlay: OlOverlay;\n\n #parent: Overlays;\n #isDestroyed = reactive(false);\n #position = reactive<OverlayPosition>({ kind: \"coordinate\" });\n #content: Reactive<ReactNode>;\n #overlayDiv: HTMLDivElement;\n #resources: Resource[] = [];\n\n #coordinate = synchronized(\n () => this.olOverlay.getPosition(),\n (cb) => {\n const key = this.olOverlay.on(\"change:position\", cb);\n return () => unByKey(key);\n }\n );\n #positioning = synchronized(\n () => this.olOverlay.getPositioning(),\n (cb) => {\n const key = this.olOverlay.on(\"change:positioning\", cb);\n return () => unByKey(key);\n }\n );\n #offset = synchronized(\n () => this.olOverlay.getOffset(),\n (cb) => {\n const key = this.olOverlay.on(\"change:offset\", cb);\n return () => unByKey(key);\n }\n );\n\n constructor(internalTag: InternalConstructorTag, options: OverlayOptions, parent: Overlays) {\n if (internalTag !== INTERNAL_CONSTRUCTOR_TAG) {\n throw new Error(\"The overlay constructor is private.\");\n }\n const {\n className,\n ariaRole,\n position,\n tag,\n content,\n offset,\n positioning,\n stopEvent,\n advanced\n } = options;\n this.id = uuid4v();\n this.tag = tag;\n this.#overlayDiv = createElement(ariaRole, className);\n\n this.olOverlay = new OlOverlay({\n element: this.#overlayDiv,\n id: this.id,\n offset,\n positioning,\n stopEvent,\n //simply override with advanced OL Options if set\n ...advanced\n });\n this.#parent = parent;\n this.#content = reactive(content);\n this.setPosition(position);\n\n parent[REGISTER_OVERLAY](this);\n\n this.#resources.push(\n // Update coordinate based on pointer movements when configured.\n // Automatically subscribes and unsubscribes on changes.\n watchValue(\n () => this.#position.value?.kind === \"follow-pointer\",\n (followPointer) => {\n if (!followPointer) {\n return;\n }\n\n // NOTE: If this turns out to be unstable we can also transport the map model reference here\n // to get our olMap.\n const olMap = this.olOverlay.getMap();\n if (!olMap) {\n LOG.error(\n `Overlay ${this.olOverlay.getId()} is not registered with a map.`\n );\n return;\n }\n\n const pointerMoveKey: EventsKey = olMap.on(\"pointermove\", (e) => {\n this.olOverlay.setPosition(e.coordinate);\n });\n return () => unByKey(pointerMoveKey);\n },\n { immediate: true, dispatch: \"sync\" }\n )\n );\n }\n\n /**\n * Destroys the overlay and removes it from the map.\n * An overlay that is destroyed cannot be added to the map again.\n */\n destroy(): void {\n if (this.isDestroyed) {\n return;\n }\n\n batch(() => {\n this.#isDestroyed.value = true;\n this.#parent[UNREGISTER_OVERLAY](this);\n this.olOverlay.dispose();\n destroyResources(this.#resources);\n });\n }\n\n /**\n * Indicates if the overlay instance has been destroyed.\n */\n get isDestroyed(): boolean {\n return this.#isDestroyed.value;\n }\n\n /**\n * Current coordinates of the overlay on the map.\n *\n * The coordinates on the map are configured via {@link OverlayOptions.position} or {@link setPosition}.\n *\n * - If configured with static coordinates (i.e. `position.kind === \"coordinate\"`), this is\n * the same as `position.coordinate`.\n * - If configured with `\"follow-pointer\"` position, this is the result of the user's pointer movements.\n */\n get currentCoordinate(): Coordinate | undefined {\n return this.#coordinate.value;\n }\n\n /**\n * The content of the overlay that is currently rendered.\n */\n get content(): ReactNode {\n return this.#content.value;\n }\n\n /**\n * The HTML element that that wraps the overlay's content.\n */\n get element(): HTMLElement {\n return this.#overlayDiv;\n }\n\n /**\n * Offset in _pixels_ relative to the overlay`s coordinates.\n *\n * The first element in the array is the horizontal offset.\n */\n get offset(): number[] {\n return this.#offset.value;\n }\n\n /**\n * The configured position of the overlay on the map.\n *\n * See also {@link currentCoordinate} to get the coordinate\n * that are the result of this configuration.\n *\n * > NOTE: The return value of the getter may not be the same\n * > as the input to the setter (or constructor) due to normalization.\n */\n get position(): OverlayPosition {\n return this.#position.value;\n }\n\n /**\n * Positioning of an overlay relative to its coordinates on the map.\n */\n get positioning(): OverlayPositioning {\n return this.#positioning.value;\n }\n\n /**\n * Set new content that is rendered on the overlay.\n */\n setContent(content: ReactNode): void {\n this.#content.value = content;\n }\n\n /**\n * Set the position of the overlay.\n *\n * This controls the coordinates of the map.\n * The overlay is not rendered if the coordinates are `undefined`.\n *\n * See also {@link currentCoordinate} to get the coordinates\n * that are the result of this configuration.\n *\n * @see {@link OverlayPosition}\n */\n setPosition(position: OverlayOptions[\"position\"]) {\n const normalized = normalizePosition(position);\n\n let newCoordinate: Coordinate | undefined;\n if (normalized) {\n if (normalized.kind === \"coordinate\") {\n newCoordinate = normalized.coordinate;\n } else {\n newCoordinate = normalized.initial;\n // mouse event handler will update this on its own\n }\n }\n\n batch(() => {\n this.#position.value = normalized;\n this.olOverlay.setPosition(newCoordinate);\n });\n }\n\n /**\n * Set offset in _pixels_ relative to the overlay`s coordinates on the map.\n * The first element in the array is the horizontal offset.\n */\n setOffset(offset: number[]) {\n this.olOverlay.setOffset(offset);\n }\n\n /**\n * Set positioning of an overlay relative to its coordinates on the map.\n */\n setPositioning(positioning: OverlayPositioning) {\n this.olOverlay.setPositioning(positioning);\n }\n}\n\nfunction normalizePosition(position: OverlayOptions[\"position\"]): OverlayPosition {\n if (!position || Array.isArray(position)) {\n return { kind: \"coordinate\", coordinate: position };\n }\n if (position === \"follow-pointer\") {\n return { kind: \"follow-pointer\" };\n }\n if (typeof position !== \"object\") {\n throw new Error(\"Unexpected position: \" + position);\n }\n return position;\n}\n\nfunction createElement(ariaRole: string | undefined, classNameProp: string | undefined) {\n const overlayDiv = document.createElement(\"div\");\n if (ariaRole) {\n overlayDiv.role = ariaRole;\n }\n\n let className = \"map-overlay\";\n if (classNameProp) {\n className += ` ${classNameProp}`;\n }\n overlayDiv.className = className;\n return overlayDiv;\n}\n"],"names":["uuid4v","OlOverlay"],"mappings":"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"}
1
+ {"version":3,"file":"Overlays.js","sources":["Overlays.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\n\nimport {\n batch,\n reactive,\n Reactive,\n reactiveSet,\n synchronized,\n watchValue\n} from \"@conterra/reactivity-core\";\nimport { createLogger, destroyResources, Resource } from \"@open-pioneer/core\";\nimport { Map as OlMap, Overlay as OlOverlay } from \"ol\";\nimport { Coordinate } from \"ol/coordinate\";\nimport { EventsKey } from \"ol/events\";\nimport { unByKey } from \"ol/Observable\";\nimport { Options } from \"ol/Overlay\";\nimport { sourceId } from \"open-pioneer:source-info\";\nimport { ReactNode } from \"react\";\nimport { v4 as uuid4v } from \"uuid\";\nimport { INTERNAL_CONSTRUCTOR_TAG, InternalConstructorTag } from \"../utils/InternalConstructorTag\";\nimport { MapModel } from \"./MapModel\";\n\nexport const REGISTER_OVERLAY = Symbol(\"REGISTER_OVERLAY\");\nexport const UNREGISTER_OVERLAY = Symbol(\"UNREGISTER_OVERLAY\");\n\nconst LOG = createLogger(sourceId);\n\n/**\n * Manages active overlays on the map.\n *\n * @group Map Model\n */\nexport class Overlays {\n #olMap: OlMap;\n #overlays = reactiveSet<Overlay>();\n\n constructor(map: MapModel) {\n this.#olMap = map.olMap;\n }\n\n [REGISTER_OVERLAY](overlay: Overlay) {\n if (this.#overlays.has(overlay)) {\n throw new Error(\"Internal error: overlay is already registered\");\n }\n this.#overlays.add(overlay);\n this.#olMap.addOverlay(overlay.olOverlay);\n }\n\n [UNREGISTER_OVERLAY](overlay: Overlay) {\n if (!this.#overlays.has(overlay)) {\n throw new Error(\"Internal error: overlay was not registered\");\n }\n this.#overlays.delete(overlay);\n this.#olMap.removeOverlay(overlay.olOverlay);\n }\n\n /**\n * Add new overlay to the map. Returns the newly created overlay instance.\n */\n add(options: OverlayOptions): Overlay {\n const newModel = new Overlay(INTERNAL_CONSTRUCTOR_TAG, options, this);\n return newModel;\n }\n\n /**\n * Returns the list of all current overlays.\n */\n getAll(): Overlay[] {\n return Array.from(this.#overlays);\n }\n\n /**\n * Destroys all overlays.\n */\n clear(): void {\n for (const overlay of this.#overlays) {\n overlay.destroy();\n }\n }\n}\n\n/**\n * Options that define the initial state of an overlay.\n *\n * @group Map Model\n */\nexport interface OverlayOptions {\n /**\n * Optional, readonly tag that helps identifying the overlay instance.\n */\n tag?: string;\n\n /**\n * Displayed content of the overlay.\n *\n * @see {@link Overlay.setContent}.\n */\n content?: ReactNode;\n\n /**\n * CSS classes of the HTML element that wraps the overlay's content.\n */\n className?: string;\n\n /**\n * Role of the HTML element that wraps the overlay's content.\n */\n ariaRole?: string;\n\n /**\n * Configures the position of the overlay.\n * The overlay is not rendered if position is `undefined` (the default).\n *\n * See {@link OverlayPosition} for all supported position options.\n *\n * The following shorthands are available:\n * - A plain `Coordinate` array can be used to specify a static coordinate on the map.\n * - `undefined` hides the overlay.\n * - `\"follow-pointer\"` can be used as a shorthand to follow the user's cursor.\n *\n * @see {@link Overlay.setPosition} to reconfigure the position.\n * @see {@link Overlay.currentCoordinate} to retrieve the actual position on the map.\n */\n position?: Coordinate | \"follow-pointer\" | OverlayPosition;\n\n /**\n * Positioning of an overlay relative to its coordinates on the map.\n *\n * @see {@link Overlay.setPositioning}\n */\n positioning?: OverlayPositioning;\n\n /**\n * Offsets in _pixels_ relative to the overlay`s coordinates on the map.\n * The first element in the array is the horizontal offset.\n *\n * @see {@link Overlay.setOffset}\n */\n offset?: number[];\n\n /**\n * Determines if event propagation to the map viewport should be stopped.\n *\n * By default `stopEvent` is `true`.\n */\n stopEvent?: boolean;\n\n /**\n * Raw OpenLayers overlay properties. `OlOverlayOptions` override corresponding `OverlayProperties`, except for id and element.\n *\n * **warning** Using OpenLayers options can create inconsistencies that lead to errors.\n * The OpenLayers API can change with updates of OpenLayers.\n */\n advanced?: OlOverlayOptions;\n}\n\n/**\n * The configured position of an overlay.\n *\n * @group Map Model\n */\nexport type OverlayPosition =\n /** Explicit (static) coordinates on the map. */\n | OverlayPositionCoordinate\n /** Update coordinates based on pointer movements on the map, useful for tooltips. */\n | OverlayPositionFollowPointer;\n\n/**\n * Automatically positions the overlay on the mouse cursor's coordinates.\n *\n * This can be used, for example, to implement tooltips for map interactions.\n *\n * @group Map Model\n */\nexport interface OverlayPositionFollowPointer {\n kind: \"follow-pointer\";\n\n /**\n * The initial coordinates.\n *\n * Use `undefined` (the default) to hide until the first mouse event on the map.\n */\n initial?: Coordinate;\n}\n\n/**\n * Places the overlay at the given coordinates.\n *\n * @group Map Model\n */\nexport interface OverlayPositionCoordinate {\n kind: \"coordinate\";\n\n /**\n * The explicit coordinates of the overlay on the map.\n *\n * Using `undefined` hides the overlay.\n */\n coordinate?: Coordinate;\n}\n\n/**\n * Positioning of an overlay relative to its coordinates on the map.\n *\n * @group Map Model\n */\nexport type OverlayPositioning =\n | \"bottom-left\"\n | \"bottom-center\"\n | \"bottom-right\"\n | \"center-left\"\n | \"center-center\"\n | \"center-right\"\n | \"top-left\"\n | \"top-center\"\n | \"top-right\";\n\n/** @group Map Model */\nexport interface OlOverlayOptions extends Omit<Partial<Options>, \"id\" | \"element\"> {}\n\n/**\n * An overlay is an UI element that is displayed over the map.\n *\n * Overlays are tied to coordinates on the map and not to a position on the screen.\n * The overlay renders a react node at the specified coordinates.\n *\n * @group Map Model\n */\nexport class Overlay {\n /**\n * Unique, readonly id of the overlay.\n *\n * Automatically assigned when the overlay is created. Use the `tag` property for custom identifiers.\n */\n readonly id: string;\n\n /**\n * Optional, readonly tag that helps identifying the overlay instance.\n */\n readonly tag: string | undefined;\n\n /**\n * Raw, corresponding OpenLayers overlay object.\n *\n * **warning** Manipulation of the OpenLayers object can create inconsistencies that lead to errors. The OpenLayers API can change with updates of OpenLayers.\n *\n * @see https://openlayers.org/en/latest/apidoc/module-ol_Overlay-Overlay.html\n */\n readonly olOverlay: OlOverlay;\n\n #parent: Overlays;\n #isDestroyed = reactive(false);\n #position = reactive<OverlayPosition>({ kind: \"coordinate\" });\n #content: Reactive<ReactNode>;\n #overlayDiv: HTMLDivElement;\n #resources: Resource[] = [];\n\n #coordinate = synchronized(\n () => this.olOverlay.getPosition(),\n (cb) => {\n const key = this.olOverlay.on(\"change:position\", cb);\n return () => unByKey(key);\n }\n );\n #positioning = synchronized(\n () => this.olOverlay.getPositioning(),\n (cb) => {\n const key = this.olOverlay.on(\"change:positioning\", cb);\n return () => unByKey(key);\n }\n );\n #offset = synchronized(\n () => this.olOverlay.getOffset(),\n (cb) => {\n const key = this.olOverlay.on(\"change:offset\", cb);\n return () => unByKey(key);\n }\n );\n\n constructor(internalTag: InternalConstructorTag, options: OverlayOptions, parent: Overlays) {\n if (internalTag !== INTERNAL_CONSTRUCTOR_TAG) {\n throw new Error(\"The overlay constructor is private.\");\n }\n const {\n className,\n ariaRole,\n position,\n tag,\n content,\n offset,\n positioning,\n stopEvent,\n advanced\n } = options;\n this.id = uuid4v();\n this.tag = tag;\n this.#overlayDiv = createElement(ariaRole, className);\n\n this.olOverlay = new OlOverlay({\n element: this.#overlayDiv,\n id: this.id,\n offset,\n positioning,\n stopEvent,\n //simply override with advanced OL Options if set\n ...advanced\n });\n this.#parent = parent;\n this.#content = reactive(content);\n this.setPosition(position);\n\n parent[REGISTER_OVERLAY](this);\n\n this.#resources.push(\n // Update coordinate based on pointer movements when configured.\n // Automatically subscribes and unsubscribes on changes.\n watchValue(\n () => this.#position.value?.kind === \"follow-pointer\",\n (followPointer) => {\n if (!followPointer) {\n return;\n }\n\n // NOTE: If this turns out to be unstable we can also transport the map model reference here\n // to get our olMap.\n const olMap = this.olOverlay.getMap();\n if (!olMap) {\n LOG.error(\n `Overlay ${this.olOverlay.getId()} is not registered with a map.`\n );\n return;\n }\n\n const pointerMoveKey: EventsKey = olMap.on(\"pointermove\", (e) => {\n this.olOverlay.setPosition(e.coordinate);\n });\n return () => unByKey(pointerMoveKey);\n },\n { immediate: true, dispatch: \"sync\" }\n )\n );\n }\n\n /**\n * Destroys the overlay and removes it from the map.\n * An overlay that is destroyed cannot be added to the map again.\n */\n destroy(): void {\n if (this.isDestroyed) {\n return;\n }\n\n batch(() => {\n this.#isDestroyed.value = true;\n this.#parent[UNREGISTER_OVERLAY](this);\n this.olOverlay.dispose();\n destroyResources(this.#resources);\n });\n }\n\n /**\n * Indicates if the overlay instance has been destroyed.\n */\n get isDestroyed(): boolean {\n return this.#isDestroyed.value;\n }\n\n /**\n * Current coordinates of the overlay on the map.\n *\n * The coordinates on the map are configured via {@link OverlayOptions.position} or {@link setPosition}.\n *\n * - If configured with static coordinates (i.e. `position.kind === \"coordinate\"`), this is\n * the same as `position.coordinate`.\n * - If configured with `\"follow-pointer\"` position, this is the result of the user's pointer movements.\n */\n get currentCoordinate(): Coordinate | undefined {\n return this.#coordinate.value;\n }\n\n /**\n * The content of the overlay that is currently rendered.\n */\n get content(): ReactNode {\n return this.#content.value;\n }\n\n /**\n * The HTML element that that wraps the overlay's content.\n */\n get element(): HTMLElement {\n return this.#overlayDiv;\n }\n\n /**\n * Offset in _pixels_ relative to the overlay`s coordinates.\n *\n * The first element in the array is the horizontal offset.\n */\n get offset(): number[] {\n return this.#offset.value;\n }\n\n /**\n * The configured position of the overlay on the map.\n *\n * See also {@link currentCoordinate} to get the coordinate\n * that are the result of this configuration.\n *\n * > NOTE: The return value of the getter may not be the same\n * > as the input to the setter (or constructor) due to normalization.\n */\n get position(): OverlayPosition {\n return this.#position.value;\n }\n\n /**\n * Positioning of an overlay relative to its coordinates on the map.\n */\n get positioning(): OverlayPositioning {\n return this.#positioning.value;\n }\n\n /**\n * Set new content that is rendered on the overlay.\n */\n setContent(content: ReactNode): void {\n this.#content.value = content;\n }\n\n /**\n * Set the position of the overlay.\n *\n * This controls the coordinates of the map.\n * The overlay is not rendered if the coordinates are `undefined`.\n *\n * See also {@link currentCoordinate} to get the coordinates\n * that are the result of this configuration.\n *\n * @see {@link OverlayPosition}\n */\n setPosition(position: OverlayOptions[\"position\"]) {\n const normalized = normalizePosition(position);\n\n let newCoordinate: Coordinate | undefined;\n if (normalized) {\n if (normalized.kind === \"coordinate\") {\n newCoordinate = normalized.coordinate;\n } else {\n newCoordinate = normalized.initial;\n // mouse event handler will update this on its own\n }\n }\n\n batch(() => {\n this.#position.value = normalized;\n this.olOverlay.setPosition(newCoordinate);\n });\n }\n\n /**\n * Set offset in _pixels_ relative to the overlay`s coordinates on the map.\n * The first element in the array is the horizontal offset.\n */\n setOffset(offset: number[]) {\n this.olOverlay.setOffset(offset);\n }\n\n /**\n * Set positioning of an overlay relative to its coordinates on the map.\n */\n setPositioning(positioning: OverlayPositioning) {\n this.olOverlay.setPositioning(positioning);\n }\n}\n\nfunction normalizePosition(position: OverlayOptions[\"position\"]): OverlayPosition {\n if (!position || Array.isArray(position)) {\n return { kind: \"coordinate\", coordinate: position };\n }\n if (position === \"follow-pointer\") {\n return { kind: \"follow-pointer\" };\n }\n if (typeof position !== \"object\") {\n throw new Error(\"Unexpected position: \" + position);\n }\n return position;\n}\n\nfunction createElement(ariaRole: string | undefined, classNameProp: string | undefined) {\n const overlayDiv = document.createElement(\"div\");\n if (ariaRole) {\n overlayDiv.role = ariaRole;\n }\n\n let className = \"map-overlay\";\n if (classNameProp) {\n className += ` ${classNameProp}`;\n }\n overlayDiv.className = className;\n return overlayDiv;\n}\n"],"names":["uuid4v","OlOverlay"],"mappings":"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"}
@@ -20,9 +20,11 @@ registerProjections({
20
20
  });
21
21
  const LOG = createLogger(sourceId);
22
22
  async function createMapModel(mapId, mapConfig, currentIntl, httpService) {
23
- return await new MapModelFactory(mapId, mapConfig, currentIntl, httpService).createMapModel();
23
+ const builder = new MapModelBuilder(mapId, mapConfig, currentIntl, httpService);
24
+ const mapModel = await builder.buildMapModel();
25
+ return mapModel;
24
26
  }
25
- class MapModelFactory {
27
+ class MapModelBuilder {
26
28
  #mapId;
27
29
  #mapConfig;
28
30
  #currentIntl;
@@ -33,7 +35,7 @@ class MapModelFactory {
33
35
  this.#currentIntl = currentIntl;
34
36
  this.#httpService = httpService;
35
37
  }
36
- async createMapModel() {
38
+ async buildMapModel() {
37
39
  const mapId = this.#mapId;
38
40
  const mapConfig = this.#mapConfig;
39
41
  const { view: viewOption, ...rawOlOptions } = mapConfig.advanced ?? {};
@@ -59,7 +61,7 @@ class MapModelFactory {
59
61
  const view = await viewOption ?? {};
60
62
  this.#initializeViewOptions(view);
61
63
  mapOptions.view = view instanceof View ? view : new View(view);
62
- if (!mapOptions.layers && !mapConfig.layers) {
64
+ if (!mapOptions.layers && !mapConfig.layers && !mapConfig.baseLayers && !mapConfig.topmostLayers) {
63
65
  mapOptions.layers = [
64
66
  new TileLayer({
65
67
  source: new OSM()
@@ -68,8 +70,9 @@ class MapModelFactory {
68
70
  }
69
71
  const initialView = mapConfig.initialView;
70
72
  const initialExtent = initialView?.kind === "extent" ? initialView.extent : void 0;
73
+ const initialPosition = initialView?.kind === "position" ? initialView : void 0;
71
74
  LOG.debug(`Constructing OpenLayers map with options`, mapOptions);
72
- if (import.meta.env.VITEST) {
75
+ if (import.meta.env.VITEST && !globalThis.__vitest_browser__) {
73
76
  patchOpenLayersClassesForTesting();
74
77
  }
75
78
  const olMap = new OlMap(mapOptions);
@@ -78,6 +81,7 @@ class MapModelFactory {
78
81
  id: mapId,
79
82
  olMap,
80
83
  initialExtent,
84
+ initialPosition,
81
85
  showDefaultAttributions,
82
86
  currentIntl: this.#currentIntl,
83
87
  httpService: this.#httpService
@@ -150,23 +154,7 @@ Use ViewOptions instead of a View instance.`
150
154
  }
151
155
  const projection = view.projection = this.#initializeProjection(mapConfig.projection);
152
156
  const initialView = mapConfig.initialView;
153
- if (initialView) {
154
- switch (initialView.kind) {
155
- case "position":
156
- view.zoom = initialView.zoom;
157
- view.center = [initialView.center.x, initialView.center.y];
158
- break;
159
- case "extent": {
160
- const extent = initialView.extent;
161
- view.zoom = 0;
162
- view.center = [
163
- extent.xMin + (extent.xMax - extent.xMin) / 2,
164
- extent.yMin + (extent.yMax - extent.yMin) / 2
165
- ];
166
- break;
167
- }
168
- }
169
- } else {
157
+ if (!initialView) {
170
158
  this.#setViewDefaults(view, projection);
171
159
  }
172
160
  }
@@ -1 +1 @@
1
- {"version":3,"file":"createMapModel.js","sources":["createMapModel.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 { createLogger } from \"@open-pioneer/core\";\nimport { HttpService } from \"@open-pioneer/http\";\nimport { PackageIntl } from \"@open-pioneer/runtime\";\nimport { MapBrowserEvent } from \"ol\";\nimport { getCenter } from \"ol/extent\";\nimport { DragZoom, defaults as defaultInteractions } from \"ol/interaction\";\nimport TileLayer from \"ol/layer/Tile\";\nimport OlMap, { MapOptions } from \"ol/Map\";\nimport { Projection, get as getProjection } from \"ol/proj\";\nimport OSM from \"ol/source/OSM\";\nimport View, { ViewOptions } from \"ol/View\";\nimport { sourceId } from \"open-pioneer:source-info\";\nimport { Layer } from \"..\";\nimport { DECLARED_AS_BASE_LAYER } from \"../layers/shared/internals\";\nimport { INTERNAL_CONSTRUCTOR_TAG } from \"../utils/InternalConstructorTag\";\nimport { patchOpenLayersClassesForTesting } from \"../utils/ol-test-support\";\nimport { registerProjections } from \"../utils/projections\";\nimport { MapConfig } from \"./MapConfig\";\nimport { MapModel } from \"./MapModel\";\n\n/**\n * Register custom projection to the global proj4js definitions. User can select `EPSG:25832`\n * and `EPSG:25833` from the predefined projections without calling `registerProjections`.\n */\nregisterProjections({\n \"EPSG:25832\":\n \"+proj=utm +zone=32 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs\",\n \"EPSG:25833\":\n \"+proj=utm +zone=33 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs\"\n});\nconst LOG = createLogger(sourceId);\n\nexport async function createMapModel(\n mapId: string,\n mapConfig: MapConfig,\n currentIntl: ReadonlyReactive<PackageIntl>,\n httpService: HttpService\n): Promise<MapModel> {\n return await new MapModelFactory(mapId, mapConfig, currentIntl, httpService).createMapModel();\n}\n\nclass MapModelFactory {\n #mapId: string;\n #mapConfig: MapConfig;\n #currentIntl: ReadonlyReactive<PackageIntl>;\n #httpService: HttpService;\n\n constructor(\n mapId: string,\n mapConfig: MapConfig,\n currentIntl: ReadonlyReactive<PackageIntl>,\n httpService: HttpService\n ) {\n this.#mapId = mapId;\n this.#mapConfig = mapConfig;\n this.#currentIntl = currentIntl;\n this.#httpService = httpService;\n }\n\n async createMapModel() {\n const mapId = this.#mapId;\n const mapConfig = this.#mapConfig;\n const { view: viewOption, ...rawOlOptions } = mapConfig.advanced ?? {};\n const showDefaultAttributions =\n mapConfig.showAttributions ?? (rawOlOptions.controls ? false : true);\n\n const mapOptions: MapOptions = {\n ...rawOlOptions\n };\n if (!mapOptions.controls) {\n mapOptions.controls = [];\n }\n if (!mapOptions.interactions) {\n const shiftCtrlKeysOnly = (\n mapBrowserEvent: MapBrowserEvent<KeyboardEvent | WheelEvent | PointerEvent>\n ) => {\n const originalEvent = mapBrowserEvent.originalEvent;\n return (originalEvent.metaKey || originalEvent.ctrlKey) && originalEvent.shiftKey;\n };\n\n // setting altShiftDragRotate to false disables or excludes DragRotate interaction\n mapOptions.interactions = defaultInteractions({\n dragPan: true,\n altShiftDragRotate: false,\n pinchRotate: false,\n mouseWheelZoom: true\n }).extend([new DragZoom({ out: true, condition: shiftCtrlKeysOnly })]);\n }\n\n const view = (await viewOption) ?? {};\n this.#initializeViewOptions(view);\n mapOptions.view = view instanceof View ? view : new View(view);\n\n if (!mapOptions.layers && !mapConfig.layers) {\n mapOptions.layers = [\n new TileLayer({\n source: new OSM()\n })\n ];\n }\n\n const initialView = mapConfig.initialView;\n const initialExtent = initialView?.kind === \"extent\" ? initialView.extent : undefined;\n\n LOG.debug(`Constructing OpenLayers map with options`, mapOptions);\n\n if (import.meta.env.VITEST) {\n patchOpenLayersClassesForTesting();\n }\n\n const olMap = new OlMap(mapOptions);\n const mapModel = new MapModel(\n {\n id: mapId,\n olMap,\n initialExtent,\n showDefaultAttributions,\n currentIntl: this.#currentIntl,\n httpService: this.#httpService\n },\n INTERNAL_CONSTRUCTOR_TAG\n );\n\n return batch(() => {\n try {\n this.#assertUniqueLayerPlacement(mapConfig);\n if (mapConfig.layers) {\n for (const layerConfig of mapConfig.layers) {\n if (mapConfig.baseLayers && layerConfig[DECLARED_AS_BASE_LAYER] != null) {\n LOG.warn(\n `Prefer to configure base layer '${layerConfig.title ?? layerConfig.id}' in the 'MapConfig.baseLayers' property instead of using the 'LayerConfig.isBaseLayer' property.`\n );\n }\n\n mapModel.layers.addLayer(layerConfig);\n }\n }\n if (mapConfig.baseLayers) {\n for (const layerConfig of mapConfig.baseLayers) {\n if (layerConfig[DECLARED_AS_BASE_LAYER] != null) {\n if (layerConfig[DECLARED_AS_BASE_LAYER]) {\n LOG.warn(\n `Base layer ${layerConfig.title ?? layerConfig.id} is already configured in the 'MapConfig.baseLayers' property. The 'LayerConfig.isBaseLayer' property can be omitted.`\n );\n } else {\n LOG.warn(\n `Base layer ${layerConfig.title ?? layerConfig.id} is configured in the 'MapConfig.baseLayers' property but 'LayerConfig.isBaseLayer' property is explicitly set to false. This layer will be treated as a base layer. Prefer using only the 'MapConfig.baseLayers' property for base layers.`\n );\n }\n }\n\n mapModel.layers.addLayer(layerConfig, { at: \"base\" });\n }\n }\n if (mapConfig.topmostLayers) {\n for (const layerConfig of mapConfig.topmostLayers) {\n if (layerConfig[DECLARED_AS_BASE_LAYER] != null) {\n LOG.warn(\n `Topmost layer ${layerConfig.title ?? layerConfig.id} is configured in the 'MapConfig.topmostLayers'. The 'LayerConfig.isBaseLayer' property can be omitted.`\n );\n }\n\n mapModel.layers.addLayer(layerConfig, { at: \"topmost\" });\n }\n }\n return mapModel;\n } catch (e) {\n mapModel.destroy();\n throw e;\n }\n });\n }\n\n #initializeViewOptions(view: View | ViewOptions) {\n const mapId = this.#mapId;\n const mapConfig = this.#mapConfig;\n if (view instanceof View) {\n const warn = (prop: string) => {\n LOG.warn(\n `The advanced configuration for map id '${mapId}' has provided a fully constructed view instance: ${prop} cannot be applied.\\n` +\n `Use ViewOptions instead of a View instance.`\n );\n };\n\n if (mapConfig.projection != null) {\n warn(\"projection\");\n }\n if (mapConfig.initialView != null) {\n warn(\"initialView\");\n }\n return;\n }\n\n const projection = (view.projection = this.#initializeProjection(mapConfig.projection));\n const initialView = mapConfig.initialView;\n if (initialView) {\n switch (initialView.kind) {\n case \"position\":\n view.zoom = initialView.zoom;\n view.center = [initialView.center.x, initialView.center.y];\n break;\n case \"extent\": {\n /*\n OpenLayers does not support configuration of the initial map extent.\n The only relevant options here are center, zoom (and resolution).\n We must set those values because otherwise OpenLayers will not initialize layer sources.\n\n The actual initial extent is applied once tha map has loaded and its size is known.\n */\n const extent = initialView.extent;\n view.zoom = 0;\n view.center = [\n extent.xMin + (extent.xMax - extent.xMin) / 2,\n extent.yMin + (extent.yMax - extent.yMin) / 2\n ];\n break;\n }\n }\n } else {\n this.#setViewDefaults(view, projection);\n }\n }\n\n #setViewDefaults(view: ViewOptions, projection: Projection) {\n if (view.center == null) {\n const extent = projection.getExtent(); // can be null\n if (!extent) {\n LOG.warn(\n `Cannot set default center coordinate because the current projection has no associated extent.\\n` +\n `Try to configure 'initialView' explicity.`\n );\n } else {\n view.center = getCenter(extent);\n }\n }\n\n if (view.zoom == null || view.resolution == null) {\n view.zoom = 0;\n }\n }\n\n #initializeProjection(projectionOption: MapConfig[\"projection\"]) {\n if (projectionOption == null) {\n // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion\n return getProjection(\"EPSG:3857\")!; // default OpenLayers projection\n }\n\n const projection = getProjection(projectionOption);\n if (!projection) {\n throw new Error(`Failed to retrieve projection for code '${projectionOption}'.`);\n }\n return projection;\n }\n\n #assertUniqueLayerPlacement(mapConfig: MapConfig) {\n type GroupName = \"baseLayers\" | \"layers\" | \"topmostLayers\";\n\n const groups = new Map<GroupName, Layer[] | undefined>([\n [\"baseLayers\", mapConfig.baseLayers],\n [\"layers\", mapConfig.layers],\n [\"topmostLayers\", mapConfig.topmostLayers]\n ]);\n const groupByLayer = new WeakMap<Layer, GroupName>();\n\n for (const [groupName, layers] of groups) {\n if (!layers) {\n continue;\n }\n\n for (const layer of layers) {\n const previousGroup = groupByLayer.get(layer);\n if (previousGroup != null) {\n throw new Error(\n `Layer '${layer.title ?? layer.id}' is configured in both '${previousGroup}' and '${groupName}'. ` +\n `A layer may only appear in one layer list.`\n );\n }\n groupByLayer.set(layer, groupName);\n }\n }\n }\n}\n"],"names":["defaultInteractions","getProjection"],"mappings":";;;;;;;;;;;;;;;;AA4BA,mBAAA,CAAoB;AAAA,EAChB,YAAA,EACI,oFAAA;AAAA,EACJ,YAAA,EACI;AACR,CAAC,CAAA;AACD,MAAM,GAAA,GAAM,aAAa,QAAQ,CAAA;AAEjC,eAAsB,cAAA,CAClB,KAAA,EACA,SAAA,EACA,WAAA,EACA,WAAA,EACiB;AACjB,EAAA,OAAO,MAAM,IAAI,eAAA,CAAgB,KAAA,EAAO,WAAW,WAAA,EAAa,WAAW,EAAE,cAAA,EAAe;AAChG;AAEA,MAAM,eAAA,CAAgB;AAAA,EAClB,MAAA;AAAA,EACA,UAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EAEA,WAAA,CACI,KAAA,EACA,SAAA,EACA,WAAA,EACA,WAAA,EACF;AACE,IAAA,IAAA,CAAK,MAAA,GAAS,KAAA;AACd,IAAA,IAAA,CAAK,UAAA,GAAa,SAAA;AAClB,IAAA,IAAA,CAAK,YAAA,GAAe,WAAA;AACpB,IAAA,IAAA,CAAK,YAAA,GAAe,WAAA;AAAA,EACxB;AAAA,EAEA,MAAM,cAAA,GAAiB;AACnB,IAAA,MAAM,QAAQ,IAAA,CAAK,MAAA;AACnB,IAAA,MAAM,YAAY,IAAA,CAAK,UAAA;AACvB,IAAA,MAAM,EAAE,MAAM,UAAA,EAAY,GAAG,cAAa,GAAI,SAAA,CAAU,YAAY,EAAC;AACrE,IAAA,MAAM,uBAAA,GACF,SAAA,CAAU,gBAAA,KAAqB,YAAA,CAAa,WAAW,KAAA,GAAQ,IAAA,CAAA;AAEnE,IAAA,MAAM,UAAA,GAAyB;AAAA,MAC3B,GAAG;AAAA,KACP;AACA,IAAA,IAAI,CAAC,WAAW,QAAA,EAAU;AACtB,MAAA,UAAA,CAAW,WAAW,EAAC;AAAA,IAC3B;AACA,IAAA,IAAI,CAAC,WAAW,YAAA,EAAc;AAC1B,MAAA,MAAM,iBAAA,GAAoB,CACtB,eAAA,KACC;AACD,QAAA,MAAM,gBAAgB,eAAA,CAAgB,aAAA;AACtC,QAAA,OAAA,CAAQ,aAAA,CAAc,OAAA,IAAW,aAAA,CAAc,OAAA,KAAY,aAAA,CAAc,QAAA;AAAA,MAC7E,CAAA;AAGA,MAAA,UAAA,CAAW,eAAeA,QAAA,CAAoB;AAAA,QAC1C,OAAA,EAAS,IAAA;AAAA,QACT,kBAAA,EAAoB,KAAA;AAAA,QACpB,WAAA,EAAa,KAAA;AAAA,QACb,cAAA,EAAgB;AAAA,OACnB,CAAA,CAAE,MAAA,CAAO,CAAC,IAAI,QAAA,CAAS,EAAE,GAAA,EAAK,IAAA,EAAM,SAAA,EAAW,iBAAA,EAAmB,CAAC,CAAC,CAAA;AAAA,IACzE;AAEA,IAAA,MAAM,IAAA,GAAQ,MAAM,UAAA,IAAe,EAAC;AACpC,IAAA,IAAA,CAAK,uBAAuB,IAAI,CAAA;AAChC,IAAA,UAAA,CAAW,OAAO,IAAA,YAAgB,IAAA,GAAO,IAAA,GAAO,IAAI,KAAK,IAAI,CAAA;AAE7D,IAAA,IAAI,CAAC,UAAA,CAAW,MAAA,IAAU,CAAC,UAAU,MAAA,EAAQ;AACzC,MAAA,UAAA,CAAW,MAAA,GAAS;AAAA,QAChB,IAAI,SAAA,CAAU;AAAA,UACV,MAAA,EAAQ,IAAI,GAAA;AAAI,SACnB;AAAA,OACL;AAAA,IACJ;AAEA,IAAA,MAAM,cAAc,SAAA,CAAU,WAAA;AAC9B,IAAA,MAAM,aAAA,GAAgB,WAAA,EAAa,IAAA,KAAS,QAAA,GAAW,YAAY,MAAA,GAAS,MAAA;AAE5E,IAAA,GAAA,CAAI,KAAA,CAAM,4CAA4C,UAAU,CAAA;AAEhE,IAAA,IAAI,MAAA,CAAA,IAAA,CAAY,IAAI,MAAA,EAAQ;AACxB,MAAA,gCAAA,EAAiC;AAAA,IACrC;AAEA,IAAA,MAAM,KAAA,GAAQ,IAAI,KAAA,CAAM,UAAU,CAAA;AAClC,IAAA,MAAM,WAAW,IAAI,QAAA;AAAA,MACjB;AAAA,QACI,EAAA,EAAI,KAAA;AAAA,QACJ,KAAA;AAAA,QACA,aAAA;AAAA,QACA,uBAAA;AAAA,QACA,aAAa,IAAA,CAAK,YAAA;AAAA,QAClB,aAAa,IAAA,CAAK;AAAA,OACtB;AAAA,MACA;AAAA,KACJ;AAEA,IAAA,OAAO,MAAM,MAAM;AACf,MAAA,IAAI;AACA,QAAA,IAAA,CAAK,4BAA4B,SAAS,CAAA;AAC1C,QAAA,IAAI,UAAU,MAAA,EAAQ;AAClB,UAAA,KAAA,MAAW,WAAA,IAAe,UAAU,MAAA,EAAQ;AACxC,YAAA,IAAI,SAAA,CAAU,UAAA,IAAc,WAAA,CAAY,sBAAsB,KAAK,IAAA,EAAM;AACrE,cAAA,GAAA,CAAI,IAAA;AAAA,gBACA,CAAA,gCAAA,EAAmC,WAAA,CAAY,KAAA,IAAS,WAAA,CAAY,EAAE,CAAA,iGAAA;AAAA,eAC1E;AAAA,YACJ;AAEA,YAAA,QAAA,CAAS,MAAA,CAAO,SAAS,WAAW,CAAA;AAAA,UACxC;AAAA,QACJ;AACA,QAAA,IAAI,UAAU,UAAA,EAAY;AACtB,UAAA,KAAA,MAAW,WAAA,IAAe,UAAU,UAAA,EAAY;AAC5C,YAAA,IAAI,WAAA,CAAY,sBAAsB,CAAA,IAAK,IAAA,EAAM;AAC7C,cAAA,IAAI,WAAA,CAAY,sBAAsB,CAAA,EAAG;AACrC,gBAAA,GAAA,CAAI,IAAA;AAAA,kBACA,CAAA,WAAA,EAAc,WAAA,CAAY,KAAA,IAAS,WAAA,CAAY,EAAE,CAAA,qHAAA;AAAA,iBACrD;AAAA,cACJ,CAAA,MAAO;AACH,gBAAA,GAAA,CAAI,IAAA;AAAA,kBACA,CAAA,WAAA,EAAc,WAAA,CAAY,KAAA,IAAS,WAAA,CAAY,EAAE,CAAA,2OAAA;AAAA,iBACrD;AAAA,cACJ;AAAA,YACJ;AAEA,YAAA,QAAA,CAAS,OAAO,QAAA,CAAS,WAAA,EAAa,EAAE,EAAA,EAAI,QAAQ,CAAA;AAAA,UACxD;AAAA,QACJ;AACA,QAAA,IAAI,UAAU,aAAA,EAAe;AACzB,UAAA,KAAA,MAAW,WAAA,IAAe,UAAU,aAAA,EAAe;AAC/C,YAAA,IAAI,WAAA,CAAY,sBAAsB,CAAA,IAAK,IAAA,EAAM;AAC7C,cAAA,GAAA,CAAI,IAAA;AAAA,gBACA,CAAA,cAAA,EAAiB,WAAA,CAAY,KAAA,IAAS,WAAA,CAAY,EAAE,CAAA,uGAAA;AAAA,eACxD;AAAA,YACJ;AAEA,YAAA,QAAA,CAAS,OAAO,QAAA,CAAS,WAAA,EAAa,EAAE,EAAA,EAAI,WAAW,CAAA;AAAA,UAC3D;AAAA,QACJ;AACA,QAAA,OAAO,QAAA;AAAA,MACX,SAAS,CAAA,EAAG;AACR,QAAA,QAAA,CAAS,OAAA,EAAQ;AACjB,QAAA,MAAM,CAAA;AAAA,MACV;AAAA,IACJ,CAAC,CAAA;AAAA,EACL;AAAA,EAEA,uBAAuB,IAAA,EAA0B;AAC7C,IAAA,MAAM,QAAQ,IAAA,CAAK,MAAA;AACnB,IAAA,MAAM,YAAY,IAAA,CAAK,UAAA;AACvB,IAAA,IAAI,gBAAgB,IAAA,EAAM;AACtB,MAAA,MAAM,IAAA,GAAO,CAAC,IAAA,KAAiB;AAC3B,QAAA,GAAA,CAAI,IAAA;AAAA,UACA,CAAA,uCAAA,EAA0C,KAAK,CAAA,kDAAA,EAAqD,IAAI,CAAA;AAAA,2CAAA;AAAA,SAE5G;AAAA,MACJ,CAAA;AAEA,MAAA,IAAI,SAAA,CAAU,cAAc,IAAA,EAAM;AAC9B,QAAA,IAAA,CAAK,YAAY,CAAA;AAAA,MACrB;AACA,MAAA,IAAI,SAAA,CAAU,eAAe,IAAA,EAAM;AAC/B,QAAA,IAAA,CAAK,aAAa,CAAA;AAAA,MACtB;AACA,MAAA;AAAA,IACJ;AAEA,IAAA,MAAM,aAAc,IAAA,CAAK,UAAA,GAAa,IAAA,CAAK,qBAAA,CAAsB,UAAU,UAAU,CAAA;AACrF,IAAA,MAAM,cAAc,SAAA,CAAU,WAAA;AAC9B,IAAA,IAAI,WAAA,EAAa;AACb,MAAA,QAAQ,YAAY,IAAA;AAAM,QACtB,KAAK,UAAA;AACD,UAAA,IAAA,CAAK,OAAO,WAAA,CAAY,IAAA;AACxB,UAAA,IAAA,CAAK,SAAS,CAAC,WAAA,CAAY,OAAO,CAAA,EAAG,WAAA,CAAY,OAAO,CAAC,CAAA;AACzD,UAAA;AAAA,QACJ,KAAK,QAAA,EAAU;AAQX,UAAA,MAAM,SAAS,WAAA,CAAY,MAAA;AAC3B,UAAA,IAAA,CAAK,IAAA,GAAO,CAAA;AACZ,UAAA,IAAA,CAAK,MAAA,GAAS;AAAA,YACV,MAAA,CAAO,IAAA,GAAA,CAAQ,MAAA,CAAO,IAAA,GAAO,OAAO,IAAA,IAAQ,CAAA;AAAA,YAC5C,MAAA,CAAO,IAAA,GAAA,CAAQ,MAAA,CAAO,IAAA,GAAO,OAAO,IAAA,IAAQ;AAAA,WAChD;AACA,UAAA;AAAA,QACJ;AAAA;AACJ,IACJ,CAAA,MAAO;AACH,MAAA,IAAA,CAAK,gBAAA,CAAiB,MAAM,UAAU,CAAA;AAAA,IAC1C;AAAA,EACJ;AAAA,EAEA,gBAAA,CAAiB,MAAmB,UAAA,EAAwB;AACxD,IAAA,IAAI,IAAA,CAAK,UAAU,IAAA,EAAM;AACrB,MAAA,MAAM,MAAA,GAAS,WAAW,SAAA,EAAU;AACpC,MAAA,IAAI,CAAC,MAAA,EAAQ;AACT,QAAA,GAAA,CAAI,IAAA;AAAA,UACA,CAAA;AAAA,yCAAA;AAAA,SAEJ;AAAA,MACJ,CAAA,MAAO;AACH,QAAA,IAAA,CAAK,MAAA,GAAS,UAAU,MAAM,CAAA;AAAA,MAClC;AAAA,IACJ;AAEA,IAAA,IAAI,IAAA,CAAK,IAAA,IAAQ,IAAA,IAAQ,IAAA,CAAK,cAAc,IAAA,EAAM;AAC9C,MAAA,IAAA,CAAK,IAAA,GAAO,CAAA;AAAA,IAChB;AAAA,EACJ;AAAA,EAEA,sBAAsB,gBAAA,EAA2C;AAC7D,IAAA,IAAI,oBAAoB,IAAA,EAAM;AAE1B,MAAA,OAAOC,IAAc,WAAW,CAAA;AAAA,IACpC;AAEA,IAAA,MAAM,UAAA,GAAaA,IAAc,gBAAgB,CAAA;AACjD,IAAA,IAAI,CAAC,UAAA,EAAY;AACb,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,wCAAA,EAA2C,gBAAgB,CAAA,EAAA,CAAI,CAAA;AAAA,IACnF;AACA,IAAA,OAAO,UAAA;AAAA,EACX;AAAA,EAEA,4BAA4B,SAAA,EAAsB;AAG9C,IAAA,MAAM,MAAA,uBAAa,GAAA,CAAoC;AAAA,MACnD,CAAC,YAAA,EAAc,SAAA,CAAU,UAAU,CAAA;AAAA,MACnC,CAAC,QAAA,EAAU,SAAA,CAAU,MAAM,CAAA;AAAA,MAC3B,CAAC,eAAA,EAAiB,SAAA,CAAU,aAAa;AAAA,KAC5C,CAAA;AACD,IAAA,MAAM,YAAA,uBAAmB,OAAA,EAA0B;AAEnD,IAAA,KAAA,MAAW,CAAC,SAAA,EAAW,MAAM,CAAA,IAAK,MAAA,EAAQ;AACtC,MAAA,IAAI,CAAC,MAAA,EAAQ;AACT,QAAA;AAAA,MACJ;AAEA,MAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AACxB,QAAA,MAAM,aAAA,GAAgB,YAAA,CAAa,GAAA,CAAI,KAAK,CAAA;AAC5C,QAAA,IAAI,iBAAiB,IAAA,EAAM;AACvB,UAAA,MAAM,IAAI,KAAA;AAAA,YACN,CAAA,OAAA,EAAU,MAAM,KAAA,IAAS,KAAA,CAAM,EAAE,CAAA,yBAAA,EAA4B,aAAa,UAAU,SAAS,CAAA,6CAAA;AAAA,WAEjG;AAAA,QACJ;AACA,QAAA,YAAA,CAAa,GAAA,CAAI,OAAO,SAAS,CAAA;AAAA,MACrC;AAAA,IACJ;AAAA,EACJ;AACJ;;;;"}
1
+ {"version":3,"file":"createMapModel.js","sources":["createMapModel.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 { createLogger } from \"@open-pioneer/core\";\nimport { HttpService } from \"@open-pioneer/http\";\nimport { PackageIntl } from \"@open-pioneer/runtime\";\nimport { MapBrowserEvent } from \"ol\";\nimport { getCenter } from \"ol/extent\";\nimport { DragZoom, defaults as defaultInteractions } from \"ol/interaction\";\nimport TileLayer from \"ol/layer/Tile\";\nimport OlMap, { MapOptions } from \"ol/Map\";\nimport { Projection, get as getProjection } from \"ol/proj\";\nimport OSM from \"ol/source/OSM\";\nimport View, { ViewOptions } from \"ol/View\";\nimport { sourceId } from \"open-pioneer:source-info\";\nimport { Layer } from \"..\";\nimport { DECLARED_AS_BASE_LAYER } from \"../layers/shared/internals\";\nimport { INTERNAL_CONSTRUCTOR_TAG } from \"../utils/InternalConstructorTag\";\nimport { patchOpenLayersClassesForTesting } from \"../utils/ol-test-support\";\nimport { registerProjections } from \"../utils/projections\";\nimport { MapConfig } from \"./MapConfig\";\nimport { MapModel } from \"./MapModel\";\n\n/**\n * Register custom projection to the global proj4js definitions. User can select `EPSG:25832`\n * and `EPSG:25833` from the predefined projections without calling `registerProjections`.\n */\nregisterProjections({\n \"EPSG:25832\":\n \"+proj=utm +zone=32 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs\",\n \"EPSG:25833\":\n \"+proj=utm +zone=33 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs\"\n});\nconst LOG = createLogger(sourceId);\n\nexport async function createMapModel(\n mapId: string,\n mapConfig: MapConfig,\n currentIntl: ReadonlyReactive<PackageIntl>,\n httpService: HttpService\n): Promise<MapModel> {\n const builder = new MapModelBuilder(mapId, mapConfig, currentIntl, httpService);\n const mapModel = await builder.buildMapModel();\n return mapModel;\n}\n\nclass MapModelBuilder {\n #mapId: string;\n #mapConfig: MapConfig;\n #currentIntl: ReadonlyReactive<PackageIntl>;\n #httpService: HttpService;\n\n constructor(\n mapId: string,\n mapConfig: MapConfig,\n currentIntl: ReadonlyReactive<PackageIntl>,\n httpService: HttpService\n ) {\n this.#mapId = mapId;\n this.#mapConfig = mapConfig;\n this.#currentIntl = currentIntl;\n this.#httpService = httpService;\n }\n\n async buildMapModel() {\n const mapId = this.#mapId;\n const mapConfig = this.#mapConfig;\n const { view: viewOption, ...rawOlOptions } = mapConfig.advanced ?? {};\n const showDefaultAttributions =\n mapConfig.showAttributions ?? (rawOlOptions.controls ? false : true);\n\n const mapOptions: MapOptions = {\n ...rawOlOptions\n };\n if (!mapOptions.controls) {\n mapOptions.controls = [];\n }\n if (!mapOptions.interactions) {\n const shiftCtrlKeysOnly = (\n mapBrowserEvent: MapBrowserEvent<KeyboardEvent | WheelEvent | PointerEvent>\n ) => {\n const originalEvent = mapBrowserEvent.originalEvent;\n return (originalEvent.metaKey || originalEvent.ctrlKey) && originalEvent.shiftKey;\n };\n\n // setting altShiftDragRotate to false disables or excludes DragRotate interaction\n mapOptions.interactions = defaultInteractions({\n dragPan: true,\n altShiftDragRotate: false,\n pinchRotate: false,\n mouseWheelZoom: true\n }).extend([new DragZoom({ out: true, condition: shiftCtrlKeysOnly })]);\n }\n\n const view = (await viewOption) ?? {};\n this.#initializeViewOptions(view);\n mapOptions.view = view instanceof View ? view : new View(view);\n\n if (\n !mapOptions.layers &&\n !mapConfig.layers &&\n !mapConfig.baseLayers &&\n !mapConfig.topmostLayers\n ) {\n mapOptions.layers = [\n new TileLayer({\n source: new OSM()\n })\n ];\n }\n\n const initialView = mapConfig.initialView;\n const initialExtent = initialView?.kind === \"extent\" ? initialView.extent : undefined;\n const initialPosition = initialView?.kind === \"position\" ? initialView : undefined;\n\n LOG.debug(`Constructing OpenLayers map with options`, mapOptions);\n\n // Only patch for unit tests (within node). Vitest's browser mode runs like in production.\n // oxlint-disable-next-line typescript/no-explicit-any\n if (import.meta.env.VITEST && !(globalThis as any).__vitest_browser__) {\n patchOpenLayersClassesForTesting();\n }\n\n const olMap = new OlMap(mapOptions);\n const mapModel = new MapModel(\n {\n id: mapId,\n olMap,\n initialExtent,\n initialPosition,\n showDefaultAttributions,\n currentIntl: this.#currentIntl,\n httpService: this.#httpService\n },\n INTERNAL_CONSTRUCTOR_TAG\n );\n\n return batch(() => {\n try {\n this.#assertUniqueLayerPlacement(mapConfig);\n if (mapConfig.layers) {\n for (const layerConfig of mapConfig.layers) {\n if (mapConfig.baseLayers && layerConfig[DECLARED_AS_BASE_LAYER] != null) {\n LOG.warn(\n `Prefer to configure base layer '${layerConfig.title ?? layerConfig.id}' in the 'MapConfig.baseLayers' property instead of using the 'LayerConfig.isBaseLayer' property.`\n );\n }\n\n mapModel.layers.addLayer(layerConfig);\n }\n }\n if (mapConfig.baseLayers) {\n for (const layerConfig of mapConfig.baseLayers) {\n if (layerConfig[DECLARED_AS_BASE_LAYER] != null) {\n if (layerConfig[DECLARED_AS_BASE_LAYER]) {\n LOG.warn(\n `Base layer ${layerConfig.title ?? layerConfig.id} is already configured in the 'MapConfig.baseLayers' property. The 'LayerConfig.isBaseLayer' property can be omitted.`\n );\n } else {\n LOG.warn(\n `Base layer ${layerConfig.title ?? layerConfig.id} is configured in the 'MapConfig.baseLayers' property but 'LayerConfig.isBaseLayer' property is explicitly set to false. This layer will be treated as a base layer. Prefer using only the 'MapConfig.baseLayers' property for base layers.`\n );\n }\n }\n\n mapModel.layers.addLayer(layerConfig, { at: \"base\" });\n }\n }\n if (mapConfig.topmostLayers) {\n for (const layerConfig of mapConfig.topmostLayers) {\n if (layerConfig[DECLARED_AS_BASE_LAYER] != null) {\n LOG.warn(\n `Topmost layer ${layerConfig.title ?? layerConfig.id} is configured in the 'MapConfig.topmostLayers'. The 'LayerConfig.isBaseLayer' property can be omitted.`\n );\n }\n\n mapModel.layers.addLayer(layerConfig, { at: \"topmost\" });\n }\n }\n return mapModel;\n } catch (e) {\n mapModel.destroy();\n throw e;\n }\n });\n }\n\n #initializeViewOptions(view: View | ViewOptions) {\n const mapId = this.#mapId;\n const mapConfig = this.#mapConfig;\n if (view instanceof View) {\n const warn = (prop: string) => {\n LOG.warn(\n `The advanced configuration for map id '${mapId}' has provided a fully constructed view instance: ${prop} cannot be applied.\\n` +\n `Use ViewOptions instead of a View instance.`\n );\n };\n\n if (mapConfig.projection != null) {\n warn(\"projection\");\n }\n if (mapConfig.initialView != null) {\n warn(\"initialView\");\n }\n return;\n }\n\n const projection = (view.projection = this.#initializeProjection(mapConfig.projection));\n const initialView = mapConfig.initialView;\n if (!initialView) {\n this.#setViewDefaults(view, projection);\n }\n }\n\n #setViewDefaults(view: ViewOptions, projection: Projection) {\n if (view.center == null) {\n const extent = projection.getExtent(); // can be null\n if (!extent) {\n LOG.warn(\n `Cannot set default center coordinate because the current projection has no associated extent.\\n` +\n `Try to configure 'initialView' explicity.`\n );\n } else {\n view.center = getCenter(extent);\n }\n }\n\n if (view.zoom == null || view.resolution == null) {\n view.zoom = 0;\n }\n }\n\n #initializeProjection(projectionOption: MapConfig[\"projection\"]) {\n if (projectionOption == null) {\n // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion\n return getProjection(\"EPSG:3857\")!; // default OpenLayers projection\n }\n\n const projection = getProjection(projectionOption);\n if (!projection) {\n throw new Error(`Failed to retrieve projection for code '${projectionOption}'.`);\n }\n return projection;\n }\n\n #assertUniqueLayerPlacement(mapConfig: MapConfig) {\n type GroupName = \"baseLayers\" | \"layers\" | \"topmostLayers\";\n\n const groups = new Map<GroupName, Layer[] | undefined>([\n [\"baseLayers\", mapConfig.baseLayers],\n [\"layers\", mapConfig.layers],\n [\"topmostLayers\", mapConfig.topmostLayers]\n ]);\n const groupByLayer = new WeakMap<Layer, GroupName>();\n\n for (const [groupName, layers] of groups) {\n if (!layers) {\n continue;\n }\n\n for (const layer of layers) {\n const previousGroup = groupByLayer.get(layer);\n if (previousGroup != null) {\n throw new Error(\n `Layer '${layer.title ?? layer.id}' is configured in both '${previousGroup}' and '${groupName}'. ` +\n `A layer may only appear in one layer list.`\n );\n }\n groupByLayer.set(layer, groupName);\n }\n }\n }\n}\n"],"names":["defaultInteractions","getProjection"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"getGeometries.js","sources":["getGeometries.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\n\nimport { Geometry } from \"ol/geom\";\nimport { DisplayTarget } from \"./MapModel\";\n\nexport function getGeometries(geoObjects: DisplayTarget[]): Geometry[] {\n const geometries: Geometry[] = [];\n geoObjects.forEach((item) => {\n if (\"getType\" in item) geometries.push(item);\n if (\"geometry\" in item && item.geometry) geometries.push(item.geometry);\n });\n return geometries;\n}\n"],"names":[],"mappings":"AAMO,SAAS,cAAc,UAAA,EAAyC;AACnE,EAAA,MAAM,aAAyB,EAAC;AAChC,EAAA,UAAA,CAAW,OAAA,CAAQ,CAAC,IAAA,KAAS;AACzB,IAAA,IAAI,SAAA,IAAa,IAAA,EAAM,UAAA,CAAW,IAAA,CAAK,IAAI,CAAA;AAC3C,IAAA,IAAI,cAAc,IAAA,IAAQ,IAAA,CAAK,UAAU,UAAA,CAAW,IAAA,CAAK,KAAK,QAAQ,CAAA;AAAA,EAC1E,CAAC,CAAA;AACD,EAAA,OAAO,UAAA;AACX;;;;"}
1
+ {"version":3,"file":"getGeometries.js","sources":["getGeometries.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\n\nimport { Geometry } from \"ol/geom\";\nimport { DisplayTarget } from \"./MapModel\";\n\nexport function getGeometries(geoObjects: DisplayTarget[]): Geometry[] {\n const geometries: Geometry[] = [];\n geoObjects.forEach((item) => {\n if (\"getType\" in item) geometries.push(item);\n if (\"geometry\" in item && item.geometry) geometries.push(item.geometry);\n });\n return geometries;\n}\n"],"names":[],"mappings":"AAMO,SAAS,cAAc,UAAA,EAAyC;AACnE,EAAA,MAAM,aAAyB,EAAC;AAChC,EAAA,UAAA,CAAW,OAAA,CAAQ,CAAC,IAAA,KAAS;AACzB,IAAA,IAAI,SAAA,IAAa,IAAA,EAAM,UAAA,CAAW,IAAA,CAAK,IAAI,CAAA;AAC3C,IAAA,IAAI,cAAc,IAAA,IAAQ,IAAA,CAAK,UAAU,UAAA,CAAW,IAAA,CAAK,KAAK,QAAQ,CAAA;AAAA,EAC1E,CAAC,CAAA;AACD,EAAA,OAAO,UAAA;AACX;;"}