UNPKG

hslayers-ng

Version:
1 lines 65.1 kB
{"version":3,"file":"hslayers-ng-services-map.mjs","sources":["../../../projects/hslayers/services/map/map.service.ts","../../../projects/hslayers/services/map/hslayers-ng-services-map.ts"],"sourcesContent":["/* eslint-disable no-eq-null */\nimport {Injectable, Renderer2, RendererFactory2, inject} from '@angular/core';\nimport {filter} from 'rxjs';\n\nimport ImageWrapper from 'ol/Image';\nimport RenderFeature from 'ol/render/Feature';\nimport proj4 from 'proj4';\nimport {\n Cluster,\n ImageArcGISRest,\n ImageWMS,\n OSM,\n Source,\n ImageStatic as Static,\n TileArcGISRest,\n TileImage,\n TileWMS,\n Vector as VectorSource,\n WMTS,\n XYZ,\n} from 'ol/source';\nimport {Control, ScaleLine, defaults as controlDefaults} from 'ol/control';\nimport {\n DoubleClickZoom,\n DragPan,\n DragRotate,\n DragZoom,\n KeyboardPan,\n KeyboardZoom,\n MouseWheelZoom,\n PinchRotate,\n PinchZoom,\n} from 'ol/interaction';\nimport {Extent} from 'ol/extent';\nimport {Feature, ImageTile, Kinetic, Map, MapBrowserEvent, View} from 'ol';\nimport {Geometry} from 'ol/geom';\nimport {Group, Layer, Tile, Vector as VectorLayer} from 'ol/layer';\nimport {Projection, transform, transformExtent} from 'ol/proj';\nimport {platformModifierKeyOnly as platformModifierKeyOnlyCondition} from 'ol/events/condition';\nimport {register} from 'ol/proj/proj4';\n\nimport {BoundingBoxObject} from 'hslayers-ng/types';\nimport {HsCommonLaymanService} from 'hslayers-ng/common/layman';\nimport {HsConfig} from 'hslayers-ng/config';\nimport {HsEventBusService} from 'hslayers-ng/services/event-bus';\nimport {HsLanguageService} from 'hslayers-ng/services/language';\nimport {HsLayoutService} from 'hslayers-ng/services/layout';\nimport {HsLogService} from 'hslayers-ng/services/log';\nimport {HsQueuesService} from 'hslayers-ng/services/queues';\nimport {\n getDimensions,\n getEnableProxy,\n getFromComposition,\n getRemovable,\n getTitle,\n} from 'hslayers-ng/common/extensions';\nimport {HsProxyService, instOf} from 'hslayers-ng/services/utils';\n\nexport enum DuplicateHandling {\n AddDuplicate = 0,\n IgnoreNew = 1,\n RemoveOriginal = 2,\n}\n\ntype VectorAndSource = {\n source: VectorSource | Cluster<Feature>;\n layer: VectorLayer<VectorSource<Feature>>;\n};\n\n@Injectable({\n providedIn: 'root',\n})\nexport class HsMapService {\n hsConfig = inject(HsConfig);\n hsLayoutService = inject(HsLayoutService);\n private hsLog = inject(HsLogService);\n hsEventBusService = inject(HsEventBusService);\n hsLanguageService = inject(HsLanguageService);\n private hsQueuesService = inject(HsQueuesService);\n private hsCommonLaymanService = inject(HsCommonLaymanService);\n private rendererFactory = inject(RendererFactory2);\n private hsProxyService = inject(HsProxyService);\n\n map: Map;\n mapElement?: any;\n renderer?: Renderer2;\n featureLayerMapping: {\n [key: string]: VectorAndSource[];\n } = {};\n /* This is a hacky solution so map would always have some layer. \n Otherwise some weird rendering problems appear in multi-apps mode */\n placeholderOsm: Layer<Source>;\n defaultDesktopControls: any;\n visibleLayersInUrl?: string[];\n permalink?: string = '';\n externalCompositionId?: string = '';\n //timer variable for extent change event\n timer = null;\n puremap: any;\n /**\n * Duration of added interactions animation. (400 ms used, default in OpenLayers is 250 ms)\n * @default 400\n */\n duration = 400;\n visible: boolean;\n /**\n * Copy of the default_view for map resetting purposes\n */\n originalView: {center: number[]; zoom: number; rotation: number};\n /**\n * Keeps track of zoomWithModifier listener so it's not registered multiple times when using router\n */\n zoomWithModifierListener;\n\n constructor() {\n /**\n * Set pure map\n */\n this.hsLayoutService._puremapApp\n .pipe(filter((v) => v))\n .subscribe((value) => {\n this.hsConfig.componentsEnabled.guiOverlay = false;\n this.removeAllInteractions();\n this.removeAllControls();\n this.hsLayoutService.updSidebarVisible(false);\n });\n }\n\n /**\n * Returns the associated layer for feature.\n * This is used in query-vector.service to get the layer of clicked\n * feature when features are listed in info panel.\n * @param feature - Feature selected\n * @returns VectorLayer\n */\n getLayerForFeature(\n feature: Feature<Geometry>,\n ): VectorLayer<VectorSource<Feature>> {\n if (typeof feature.getId() == 'undefined') {\n feature.setId(crypto.randomUUID());\n }\n const fid = feature.getId();\n if (this.featureLayerMapping[fid]?.length > 0) {\n return this.refineLayerSearch(this.featureLayerMapping[fid], feature);\n }\n const layersFound: VectorAndSource[] = [];\n const layersToLookFor = [];\n this.getVectorLayers(layersToLookFor);\n for (const obj of layersToLookFor) {\n let found = false;\n if (obj.source.getFeatureById) {\n //For ordinary vector layers we can search by ID\n found = obj.source.getFeatureById(fid);\n } else {\n //For cluster layers we need to loop through features\n found = this.findFeatureByInst(obj, feature) !== undefined;\n }\n if (found) {\n layersFound.push(obj);\n //break; Tempting to use break, but if multiple layers contain features with same id we won't find them all.\n }\n }\n if (layersFound && !this.featureLayerMapping[fid]) {\n //TODO: Will have to delete the mapping at some point when layer is cleared or feature removed\n this.featureLayerMapping[fid] = layersFound;\n }\n return this.refineLayerSearch(layersFound, feature);\n }\n\n /**\n * When multiple layers contain feature with the same ID do a full search by feature instance instead.\n * @param array - Cached array of layers for a given feature ID\n * @param feature - Instance of feature\n * @returns Layer\n */\n refineLayerSearch(\n array: VectorAndSource[],\n feature: Feature<Geometry>,\n ): VectorLayer<VectorSource<Feature>> {\n array = array.filter((entry) => entry.layer.getVisible());\n if (array.length > 1) {\n return array.find(\n (entry) => this.findFeatureByInst(entry, feature) !== undefined,\n )?.layer;\n }\n if (array.length == 1) {\n return array[0].layer;\n }\n }\n\n /**\n * Search for feature in layer by looping through feature list. getFeatureById is more efficient, but is not always available\n * @param obj - dictionary entry for layer and its vector source (ordinary vector source, source of each Group layers child or underlying source for cluster layer)\n * @param feature - Feature instance\n * @returns Feature\n */\n findFeatureByInst(\n obj: VectorAndSource,\n feature: Feature<Geometry>,\n ): Feature<Geometry> {\n return obj.source.getFeatures().find((layer_feature) => {\n return layer_feature === feature;\n });\n }\n\n /**\n * Get vector layers from the map, mentioned in the layersToLookFor array\n * @param layersToLookFor - Layers requested\n */\n getVectorLayers(layersToLookFor: VectorAndSource[]): void {\n const check = (layer) => {\n const source = layer.getSource();\n if (instOf(source, Cluster)) {\n layersToLookFor.push({\n layer,\n source,\n });\n layersToLookFor.push({\n layer,\n source: source.getSource(),\n });\n } else if (instOf(source, VectorSource)) {\n layersToLookFor.push({\n layer,\n source,\n });\n }\n };\n this.map.getLayers().forEach((layer) => {\n if (instOf(layer, Group)) {\n (layer as Group).getLayers().forEach(check);\n } else {\n check(layer);\n }\n });\n }\n\n /**\n * Get geometry feature by its ID.\n * Used in hslayers-cesium.\n * @param fid - Feature ID\n * @returns Feature\n */\n getFeatureById(fid: string): Feature<Geometry> | RenderFeature[] {\n if (this.featureLayerMapping[fid]) {\n if (this.featureLayerMapping[fid].length > 1) {\n this.hsLog.warn(`Multiple layers exist for feature id ${fid}`);\n } else {\n return this.featureLayerMapping[fid][0].source.getFeatureById(fid);\n }\n } else {\n const layersToLookFor: {\n source: VectorSource | Cluster<Feature>;\n layer: any;\n }[] = [];\n this.getVectorLayers(layersToLookFor);\n const obj = layersToLookFor.find((obj) => obj.source.getFeatureById(fid));\n if (obj) {\n return obj.source.getFeatureById(fid);\n }\n }\n }\n\n /**\n * Create default view button inside the map html element\n * @param defaultDesktopControls - Default controls\n */\n async createDefaultViewButton(): Promise<void> {\n const rendered = this.renderer;\n const button = rendered.createElement('button');\n button.addEventListener(\n 'click',\n (e) => {\n this.setDefaultView(e);\n },\n false,\n );\n\n const icon = rendered.createElement('i');\n rendered.addClass(icon, 'fa-solid');\n rendered.addClass(icon, 'fa-earth-europe');\n\n const element = rendered.createElement('div');\n rendered.addClass(element, 'hs-defaultView');\n rendered.addClass(element, 'ol-unselectable');\n rendered.addClass(element, 'ol-control');\n rendered.setAttribute(\n element,\n 'title',\n await this.hsLanguageService.awaitTranslation(\n 'MAP.zoomToInitialWindow',\n undefined,\n ),\n );\n\n rendered.appendChild(button, icon);\n rendered.appendChild(element, button);\n const defaultViewControl = new Control({\n element,\n });\n this.map.addControl(defaultViewControl);\n }\n\n /**\n * Set map to default view\n * @param e - Mouse click event\n */\n setDefaultView = function (e): void {\n let viewToSet;\n if (!this.hsConfig.default_view) {\n viewToSet = this.createPlaceholderView();\n } else {\n viewToSet = this.hsConfig.default_view;\n }\n const center = viewToSet?.getCenter();\n this.map.getView().setCenter(center);\n const zoom = viewToSet?.getZoom();\n this.map.getView().setZoom(zoom);\n };\n\n /**\n * @param e - Map or view change\n */\n extentChanged(e) {\n if (this.timer !== null) {\n clearTimeout(this.timer);\n }\n this.timer = setTimeout(() => {\n this.hsEventBusService.mapExtentChanges.next({\n map: e.target,\n event: e.type,\n extent: this.map.getView().calculateExtent(this.map.getSize()),\n });\n }, 500);\n }\n\n /**\n * Initialization function for HSLayers map object.\n * Initialize map with basic interaction, scale line and watcher for map view changes.\n * When default controller is used, it's called automatically, otherwise it must be called before other modules dependent on map object are loaded.\n * @param mapElement - Map html element\n */\n init(mapElement: HTMLElement): void {\n let map: Map;\n if (this.map) {\n map = this.map;\n map.setTarget(mapElement);\n } else {\n this.defaultDesktopControls = controlDefaults({\n rotate: false,\n attributionOptions: {\n collapsible: true,\n collapsed: true,\n },\n });\n this.defaultDesktopControls.push(new ScaleLine());\n this.placeholderOsm = new Tile({\n source: new OSM(),\n visible: true,\n properties: {\n title: 'OpenStreetMap',\n base: true,\n removable: true,\n },\n });\n map = new Map({\n controls: this.defaultDesktopControls,\n layers: [this.placeholderOsm],\n target: mapElement,\n interactions: [],\n view: this.hsConfig.default_view ?? this.createPlaceholderView(),\n });\n this.renderer = this.rendererFactory.createRenderer(null, null);\n this.mapElement = mapElement;\n this.map = map;\n this.featureLayerMapping = {};\n this.permalink = this?.permalink;\n this.externalCompositionId = this?.externalCompositionId;\n\n const view = map.getView();\n this.originalView = {\n center: view.getCenter(),\n zoom: view.getZoom(),\n rotation: view.getRotation(),\n };\n\n view.on('change:center', (e) => {\n this.extentChanged(e);\n });\n view.on('change:resolution', (e) => {\n this.extentChanged(e);\n });\n\n map.on('moveend', (e) => {\n this.extentChanged(e);\n });\n\n if (\n this.hsConfig.componentsEnabled?.defaultViewButton &&\n this.hsConfig.componentsEnabled?.guiOverlay != false\n ) {\n this.createDefaultViewButton();\n }\n }\n\n const interactions = {\n 'DoubleClickZoom': new DoubleClickZoom({\n duration: this.duration,\n }),\n 'KeyboardPan': new KeyboardPan({\n pixelDelta: 256,\n }),\n 'KeyboardZoom': new KeyboardZoom({\n duration: this.duration,\n }),\n 'MouseWheelZoom': new MouseWheelZoom({\n condition: (browserEvent): boolean => {\n if (this.hsConfig.componentsEnabled?.mapControls == false) {\n return false;\n }\n return this.hsConfig.zoomWithModifierKeyOnly\n ? platformModifierKeyOnlyCondition(browserEvent)\n : true;\n },\n duration: this.duration,\n }),\n 'PinchRotate': new PinchRotate(),\n 'PinchZoom': new PinchZoom({\n duration: this.duration,\n }),\n 'DragPan': new DragPan({\n kinetic: new Kinetic(-0.01, 0.1, 200),\n }),\n 'DragZoom': new DragZoom(),\n 'DragRotate': new DragRotate(),\n };\n\n if (this.hsConfig.mapInteractionsEnabled != false) {\n for (const value of Object.values(interactions).filter(\n (value) => !map.getInteractions().getArray().includes(value),\n )) {\n map.addInteraction(value);\n }\n }\n\n //this.map.addControl(new ol.control.ZoomSlider());\n // this.map.addControl(new ol.control.ScaleLine());\n\n // If the MouseWheelInteraction is set to behave only with CTRL pressed,\n // then also notify the user when he tries to zoom,\n // but the CTRL is not pressed\n if (\n this.hsConfig.zoomWithModifierKeyOnly &&\n this.hsConfig.mapInteractionsEnabled != false &&\n !this.zoomWithModifierListener\n ) {\n this.zoomWithModifierListener = map.on(\n 'wheel' as any,\n (e: MapBrowserEvent<any>) => {\n const renderer = this.renderer;\n //ctrlKey works for Win and Linux, metaKey for Mac\n if (\n !(e.originalEvent.ctrlKey || e.originalEvent.metaKey) &&\n !this.hsLayoutService.contentWrapper.querySelector(\n '.hs-zoom-info-dialog',\n )\n ) {\n //TODO: change the name of platform modifier key dynamically based on OS\n const platformModifierKey = 'CTRL/META';\n //Following styles would be better written as ng-styles...\n const html = renderer.createElement('div');\n renderer.setAttribute(\n html,\n 'class',\n 'alert alert-info mt-1 hs-zoom-info-dialog',\n );\n renderer.setAttribute(\n html,\n 'style',\n `position: absolute; right:15px; top:0.6em; z-index:101`,\n );\n const text = renderer.createText(\n `${this.hsLanguageService.getTranslation('MAP.zoomKeyModifier', {\n platformModifierKey: platformModifierKey,\n })}`,\n );\n renderer.appendChild(html, text);\n renderer.appendChild(\n this.hsLayoutService.contentWrapper.querySelector(\n '.hs-map-space',\n ),\n html,\n );\n setTimeout(() => {\n this.hsLayoutService.contentWrapper\n .querySelector('.hs-zoom-info-dialog')\n .remove();\n }, 4000);\n }\n },\n );\n }\n\n this.repopulateLayers(this.visibleLayersInUrl);\n\n proj4.defs(\n 'EPSG:3035',\n '+proj=laea +lat_0=52 +lon_0=10 +x_0=4321000 +y_0=3210000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs +axis=neu',\n );\n proj4.defs(\n 'http://www.opengis.net/gml/srs/epsg.xml#3035',\n proj4.defs('EPSG:3035'),\n );\n\n proj4.defs(\n 'EPSG:5514',\n '+proj=krovak +lat_0=49.5 +lon_0=24.83333333333333 +alpha=30.28813972222222 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=542.5,89.2,456.9,5.517,2.275,5.516,6.96 +units=m +no_defs',\n );\n proj4.defs(\n 'http://www.opengis.net/gml/srs/epsg.xml#5514',\n proj4.defs('EPSG:5514'),\n );\n\n proj4.defs(\n 'EPSG:4258',\n '+proj=longlat +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +no_defs',\n );\n proj4.defs(\n 'http://www.opengis.net/gml/srs/epsg.xml#4258',\n proj4.defs('EPSG:4258'),\n );\n\n proj4.defs(\n 'EPSG:32633',\n '+proj=utm +zone=33 +datum=WGS84 +units=m +no_defs +type=crs',\n );\n proj4.defs(\n 'http://www.opengis.net/gml/srs/epsg.xml#32633',\n proj4.defs('EPSG:32633'),\n );\n proj4.defs(\n 'EPSG:32634',\n '+proj=utm +zone=34 +datum=WGS84 +units=m +no_defs +type=crs',\n );\n proj4.defs(\n 'http://www.opengis.net/gml/srs/epsg.xml#32634',\n proj4.defs('EPSG:32634'),\n );\n\n proj4.defs(\n 'EPSG:3995',\n '+proj=stere +lat_0=90 +lat_ts=71 +lon_0=0 +k=1 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs',\n );\n proj4.defs(\n 'http://www.opengis.net/gml/srs/epsg.xml#3995',\n proj4.defs('EPSG:3995'),\n );\n proj4.defs(\n 'EPSG:3031',\n '+proj=stere +lat_0=-90 +lat_ts=-71 +lon_0=0 +k=1 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs',\n );\n proj4.defs(\n 'http://www.opengis.net/gml/srs/epsg.xml#3031',\n proj4.defs('EPSG:3031'),\n );\n\n proj4.defs(\n 'EPSG:4087',\n '+proj=eqc +lat_ts=0 +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs +type=crs',\n );\n proj4.defs(\n 'http://www.opengis.net/gml/srs/epsg.xml#4087',\n proj4.defs('EPSG:4087'),\n );\n register(proj4);\n\n if (this.hsConfig.componentsEnabled?.mapControls == false) {\n this.removeAllControls();\n }\n this.hsEventBusService.olMapLoads.next(map);\n }\n\n /**\n * Wait until the OL map is fully loaded\n * @returns OL map object\n */\n loaded(): Promise<Map> {\n return new Promise<Map>((resolve, reject) => {\n if (this.map) {\n resolve(this.map);\n return;\n }\n this.hsEventBusService.olMapLoads.subscribe((map) => {\n if (map) {\n resolve(map);\n }\n });\n });\n }\n\n /**\n * Find layer object by title of layer\n * @param title - Title of the layer (from layer creation)\n * @returns OL.layer object\n */\n findLayerByTitle(title: string) {\n const layers = this.getLayersArray();\n let tmp = null;\n for (const layer of layers) {\n if (getTitle(layer) == title) {\n tmp = layer;\n }\n }\n return tmp;\n }\n\n /**\n * Two layers are considered equal when they equal in the following properties:\n * * title\n * * type of source\n * * list of sublayers\n * * URL\n * * and when there are multiple URLs defined for a layer, there must be at least one matching URL for both the layers.\n * @param existingLayer - Layer 1. Usually the one which is already added to map\n * @param newLayer - Layer 2. Usually the one which will be added to map\n * @returns True if the layers are equal, false otherwise\n */\n layersEqual(existingLayer, newLayer): boolean {\n if (newLayer === 'undefined') {\n this.hsLog.warn(\n 'Checking duplicity for undefined layer. Why are we doing this?',\n );\n return true;\n }\n if (existingLayer.getSource === 'undefined') {\n return false;\n }\n if (newLayer.getSource === 'undefined') {\n return false;\n }\n const existingSource = existingLayer.getSource();\n const newSource = newLayer.getSource();\n const existingTitle = getTitle(existingLayer);\n const newTitle = getTitle(newLayer);\n const existingSourceType = typeof existingSource;\n const newSourceType = typeof newSource;\n const existingLAYERS =\n existingSource.getParams == null ? '' : existingSource.getParams().LAYERS;\n const newLAYERS =\n newSource.getParams == null ? '' : newSource.getParams().LAYERS;\n const existingUrl =\n existingSource.getUrl == null ? '' : existingSource.getUrl();\n const newUrl = newSource.getUrl == null ? '' : newSource.getUrl();\n const existingUrls =\n existingSource.getUrls == null ? '' : existingSource.getUrls();\n let newUrls = newSource.getUrls == null ? [''] : newSource.getUrls();\n newUrls = newUrls ? newUrls : [''];\n const urlsEqual =\n existingUrls == newUrls ||\n (newUrls.length > 0 && existingUrls.indexOf(newUrls[0]) > -1);\n return (\n existingTitle == newTitle &&\n existingSourceType == newSourceType &&\n existingLAYERS == newLAYERS &&\n existingUrl == newUrl &&\n urlsEqual\n );\n }\n\n /**\n * Checks if a layer with the same title already exists in the map\n * @param lyr - A layer to check\n * @returns True if layer is already present in the map, false otherwise\n */\n layerAlreadyExists(lyr: Layer): boolean {\n const duplicateLayers = this.getLayersArray().filter((existing) => {\n const equal = this.layersEqual(existing, lyr);\n return equal;\n });\n return duplicateLayers.length > 0;\n }\n\n /**\n * Remove any duplicate layer inside map layers array\n * @param lyr - A layer to check\n */\n removeDuplicate(lyr: Layer): void {\n this.getLayersArray()\n .filter((existing) => {\n const equal = this.layersEqual(existing, lyr);\n return equal;\n })\n .forEach((to_remove) => {\n this.map.getLayers().remove(to_remove);\n });\n }\n\n /**\n * Get layers array from the OL map object\n * @returns Layer array\n */\n getLayersArray(): Layer<Source>[] {\n return this.map.getLayers().getArray() as Layer<Source>[];\n }\n\n /**\n * Proxify layer based on its source object type and if it's tiled or not.\n * Each underlying OL source class has its own way to override imagery loading.\n * @param lyr - Layer which to proxify if needed\n */\n proxifyLayer(lyr: Layer<Source>): void {\n const source = lyr.getSource();\n if ([ImageWMS, ImageArcGISRest].some((typ) => instOf(source, typ))) {\n this.proxifyLayerLoader(lyr, false);\n }\n if (instOf(source, WMTS)) {\n (source as WMTS).setTileLoadFunction((i, s) =>\n this.simpleImageryProxy(i as ImageTile, s),\n );\n }\n if ([TileWMS, TileArcGISRest].some((typ) => instOf(source, typ))) {\n this.proxifyLayerLoader(lyr, true);\n }\n if (\n instOf(source, XYZ) &&\n !instOf(source, OSM) &&\n (source as XYZ).getUrls().every((url) => !url.includes('openstreetmap'))\n ) {\n this.proxifyLayerLoader(lyr, true);\n }\n\n if (instOf(source, Static)) {\n //NOTE: Using url_ is not nice, but don't see other way, because no setUrl or set('url'.. exists yet\n (source as any).url_ = this.hsProxyService.proxify(\n (source as Static).getUrl(),\n );\n }\n }\n\n /**\n * Checks if layer already exists in map and resolves based on duplicateHandling strategy\n * @returns True if layer should be processed (added to map etc.)\n */\n resolveDuplicateLayer(\n lyr: Layer<Source>,\n duplicateHandling?: DuplicateHandling,\n ): boolean {\n if (this.layerAlreadyExists(lyr)) {\n if (instOf(lyr.getSource(), OSM)) {\n duplicateHandling = DuplicateHandling.RemoveOriginal;\n }\n switch (duplicateHandling) {\n case DuplicateHandling.RemoveOriginal:\n /* if (getBase(lyr) == true) { //Removed so we could add OSM over the placeholderOsm \n return;\n } */\n this.removeDuplicate(lyr);\n return true;\n case DuplicateHandling.IgnoreNew:\n return false;\n case DuplicateHandling.AddDuplicate:\n default:\n return true;\n }\n }\n return true;\n }\n\n /**\n * Function to add layer to map which also checks if\n * the layer is not already present and also proxifies the layer if needed.\n * Generally for non vector layers it would be better to use this function than to add to OL map directly\n * and rely on layer manager service to do the proxification and also it's shorter than to use HsMapService.getMap().addLayer.\n *\n * @param lyr - Layer to add\n * @param duplicateHandling - How to handle duplicate layers (same class and title)\n * @param visibleOverride - Override the visibility using an array layer titles, which\n */\n addLayer(\n lyr: Layer<Source>,\n duplicateHandling?: DuplicateHandling,\n visibleOverride?: string[],\n ): void {\n const addLayer = this.resolveDuplicateLayer(lyr, duplicateHandling);\n if (addLayer) {\n if (visibleOverride) {\n lyr.setVisible(this.layerTitleInArray(lyr, visibleOverride));\n }\n const source = lyr.getSource();\n if (instOf(source, VectorSource)) {\n this.getVectorType(lyr);\n }\n this.proxifyLayer(lyr);\n lyr.on('change:source', (e) => {\n this.proxifyLayer(e.target as Layer<Source>);\n });\n this.map.addLayer(lyr);\n }\n }\n\n /**\n * Add all layers from app config (default_layers) to the map.\n * Only layers specified in visibilityOverrides parameter will get instantly visible.\n * @param visibilityOverrides - Override the visibility using an array layer titles, which\n * should be visible. Useful when the layer visibility is stored in a URL parameter\n */\n repopulateLayers(visibilityOverrides: string[]): void {\n try {\n if (this.hsConfig.default_layers) {\n const defaultLayers: Layer[] = this.hsConfig.default_layers.filter(\n (lyr) => lyr,\n );\n if (defaultLayers.length > 0) {\n this.map.removeLayer(this.placeholderOsm);\n }\n this.addLayersFromAppConfig(defaultLayers, visibilityOverrides);\n }\n } catch (error) {\n //TOAST?\n console.error('Error while trying to repopulate layers', error);\n }\n }\n\n /**\n * Add layers from app config - default_layers\n * While adding check if hs-composition URL param or defaultComposition is set, if so, filter config's layers by removable property\n * If permalink URL param is set, do not add any of config's layers.\n */\n addLayersFromAppConfig(layers: Layer[], visibilityOverrides: string[]): void {\n if (this.externalCompositionId) {\n layers = layers.filter((layer) => getRemovable(layer) === false);\n }\n if (!this.permalink) {\n layers.forEach((lyr: Layer<Source>) => {\n this.addLayer(lyr, DuplicateHandling.IgnoreNew, visibilityOverrides);\n });\n }\n }\n\n /**\n * Get map projection currently used in the map view\n * @returns Projection\n */\n getCurrentProj(): Projection {\n return this.map.getView().getProjection();\n }\n\n /**\n * For a vector layer with a vector source, determines if it includes points, lines and/or polygons and stores the information in hasPoint, hasLine, hasPoly properties of the source.\n * Get vector type from the layer selected\n * @param layer - Vector layer selected\n */\n getVectorType(layer): void {\n let src;\n if (layer.getSource().getSource) {\n src = layer.getSource().getSource();\n } else {\n src = layer.getSource();\n }\n src.hasLine = false;\n src.hasPoly = false;\n src.hasPoint = false;\n if (src.getFeatures().length > 0) {\n this.vectorSourceTypeComputer(src);\n } else {\n src.on('change', (evt) => {\n const source = evt.target;\n if (source.getState() === 'ready') {\n this.vectorSourceTypeComputer(source);\n }\n });\n }\n }\n\n /**\n * Check vector geometry types as found from vector source provided\n * @param src - Vector source\n */\n vectorSourceTypeComputer(src): void {\n src.getFeatures().forEach((f) => {\n if (f.getGeometry()) {\n switch (f.getGeometry().getType()) {\n case 'LineString':\n case 'MultiLineString':\n src.hasLine = true;\n break;\n case 'Polygon':\n case 'MultiPolygon':\n src.hasPoly = true;\n break;\n case 'Point':\n case 'MultiPoint':\n src.hasPoint = true;\n break;\n default:\n }\n }\n });\n if (src.hasLine || src.hasPoly || src.hasPoint) {\n src.styleAble = true;\n }\n }\n\n /**\n * Reset map to state configured in app config (reload all layers and set default view)\n */\n reset(): void {\n this.removeAllLayers();\n this.repopulateLayers(null);\n this.resetView();\n }\n\n /**\n * Reset map view to view configured in app config\n */\n resetView(): void {\n const view = this.map.getView();\n view.setCenter(this.originalView.center);\n view.setZoom(this.originalView.zoom);\n view.setRotation(this.originalView.rotation);\n }\n\n /**\n * Create a placeholder view\n * @returns Map view\n */\n createPlaceholderView(): View {\n return new View({\n center: transform([17.474129, 52.574], 'EPSG:4326', 'EPSG:3857'), //Latitude longitude to Spherical Mercator\n zoom: 4,\n });\n }\n\n /**\n * Checks if layer title is present in an array of layer titles.\n * Used to set visibility by URL parameter which contains visible layer titles\n * @param lyr - Layer for which to determine visibility\n * @param array - Layer title to check in.\n * @returns Detected visibility of layer\n */\n layerTitleInArray(lyr: Layer, array: string[]) {\n if (array && getTitle(lyr) != undefined) {\n return array.filter((title) => title == getTitle(lyr)).length > 0;\n }\n return lyr.getVisible();\n }\n\n /**\n * Get ol-layer canvas element from DOM\n * @returns DOM NodeListOf<HTMLCanvasElement>\n */\n getCanvases(): NodeListOf<HTMLCanvasElement> {\n return this.mapElement.querySelectorAll('.ol-layer canvas');\n }\n\n /**\n * Get ol-layer canvas element from DOM\n * @param type - Scale type (scaleline or scalebar)\n * @returns DOM element\n */\n getScaleLineElement(type: 'scaleline' | 'scalebar'): Element {\n switch (type) {\n case 'scalebar':\n return this.mapElement.querySelectorAll(\n '.ol-scale-bar.ol-unselectable',\n )?.[0];\n case 'scaleline':\n default:\n return this.mapElement.querySelectorAll(\n '.ol-scale-line.ol-unselectable',\n )?.[0];\n }\n }\n\n /**\n * Proxify layer loader to work with layers from other sources than app\n * @param lyr - Layer to proxify\n * @param tiled - Info if layer is tiled\n * @returns proxified URL\n */\n proxifyLayerLoader(lyr: Layer, tiled: boolean): string {\n const src = lyr.getSource();\n if (getEnableProxy(lyr) !== undefined && getEnableProxy(lyr) == false) {\n return;\n }\n if (tiled) {\n if (getDimensions(lyr)) {\n const tile_url_function =\n (src as TileImage).getTileUrlFunction() ||\n (src as any).tileUrlFunction();\n (src as TileImage).setTileUrlFunction((b, c, d) => {\n let url = tile_url_function.call(src, b, c, d);\n const dimensions = getDimensions(lyr);\n Object.keys(dimensions).forEach((dimension) => {\n url = url.replace(`{${dimension}}`, dimensions[dimension].value);\n });\n return url;\n });\n }\n (src as TileImage).setTileLoadFunction(async (tile: ImageTile, url) => {\n const que = this.hsQueuesService.ensureQueue('tileLoad', 6, 2500);\n que.push(async (cb) => {\n await this.simpleImageryProxy(tile, url);\n cb(null);\n });\n });\n } else {\n (src as ImageWMS | ImageArcGISRest).setImageLoadFunction(\n async (image, url) => {\n /**\n * No timeout for this que as non tiled images may in some cases take really long to load and thus\n * block all the rest of the functionality that depends on http requests for the whole duration\n */\n const que = this.hsQueuesService.ensureQueue('imageLoad', 4);\n que.push(async (cb) => {\n await this.simpleImageryProxy(image, url);\n cb(null);\n });\n },\n );\n }\n }\n\n /**\n * Proxify loader for any imagery layer, either tiled or not\n * @param image - Image or ImageTile as required by setImageLoadFunction() in ImageWMS, ImageArcGISRest and WMTS sources\n * @param src - Original (unproxified) source URL\n */\n async simpleImageryProxy(image: ImageWrapper | ImageTile, src: string) {\n return new Promise((resolve, reject) => {\n if (src.startsWith(this.hsConfig.proxyPrefix)) {\n (image.getImage() as HTMLImageElement).src = src;\n return;\n }\n const laymanEp = this.hsCommonLaymanService.layman();\n if (laymanEp && src.startsWith(laymanEp.url)) {\n this.laymanWmsLoadingFunction(image, src)\n .then((_) => {\n resolve(image);\n })\n .catch((e) => {\n resolve(image);\n });\n return;\n }\n (image.getImage() as HTMLImageElement).onload = function () {\n resolve(image);\n };\n\n (image.getImage() as HTMLImageElement).onerror = function () {\n resolve(image);\n };\n\n (image.getImage() as HTMLImageElement).onabort = function () {\n resolve(image);\n };\n\n (image.getImage() as HTMLImageElement).src =\n this.hsProxyService.proxify(src); //Previously urlDecodeComponent was called on src, but it breaks in firefox.\n });\n }\n\n /**\n * Create a loader function for Layman WMS layers specifically\n * @param image - ol/Image, the image requested via WMS source\n * @param src - Original (unproxified) source URL\n */\n laymanWmsLoadingFunction(\n image: ImageWrapper | ImageTile,\n src: string,\n ): Promise<any> {\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n xhr.withCredentials = true;\n xhr.responseType = 'arraybuffer';\n xhr.open('GET', src);\n xhr.addEventListener('loadend', function (evt) {\n const arrayBufferView = new Uint8Array(this.response);\n const blob = new Blob([arrayBufferView], {type: 'image/png'});\n const urlCreator = window.URL || window.webkitURL;\n const imageUrl = urlCreator.createObjectURL(blob);\n (image.getImage() as HTMLImageElement).src = imageUrl;\n resolve(image);\n });\n xhr.addEventListener('error', () => {\n reject(new Error('Failed to load image. Network error.'));\n });\n xhr.send();\n });\n }\n\n /**\n * Move map and zoom to specified coordinate/zoom level\n * @param x - X coordinate of new center\n * @param y - Y coordinate of new center\n * @param zoom - New zoom level\n */\n moveToAndZoom(x: number, y: number, zoom: number): void {\n const view = this.map.getView();\n view.setCenter([x, y]);\n view.setZoom(zoom);\n }\n\n /**\n * Get current map extent\n * @returns Extent\n */\n getMapExtent(): Extent {\n const mapSize = this.map.getSize();\n const mapExtent = mapSize\n ? this.map.getView().calculateExtent(mapSize)\n : [0, 0, 100, 100];\n return mapExtent;\n }\n\n /**\n * Get current map extent in WGS84 (EPSG:4326) projection\n * @returns Extent\n */\n getMapExtentInEpsg4326(): Extent {\n const bbox = transformExtent(\n this.getMapExtent(),\n this.getCurrentProj(),\n 'EPSG:4326',\n );\n return bbox;\n }\n\n /**\n * Fit extent into map view\n * @param extent - Extent provided\n */\n async fitExtent(extent: number[]): Promise<void> {\n const mapSize = this.map.getSize();\n if (!mapSize.every((p) => p > 0)) {\n this.hsLog.warn(\n 'Tried to fit extent but one of map dimensions were 0. Will wait a bit and try again!',\n );\n await new Promise((resolve) => setTimeout(resolve, 250));\n }\n this.map.getView().fit(extent, {size: mapSize});\n }\n\n /**\n * Get ol.Map object from service\n * @returns ol.Map\n */\n getMap(): Map {\n return this.map;\n }\n\n /**\n * Remove all map layers\n */\n removeAllLayers(): void {\n const to_be_removed = [];\n this.getLayersArray()\n .filter((layer) => getRemovable(layer as Layer<Source>) !== false)\n .forEach((lyr) => {\n to_be_removed.push(lyr);\n });\n while (to_be_removed.length > 0) {\n this.map.removeLayer(to_be_removed.shift());\n }\n }\n\n /**\n * Remove all removable layers no matter fromComposition param\n */\n removeCompositionLayers(force?: boolean): void {\n let to_be_removed = this.getLayersArray().filter(\n (lyr) => getRemovable(lyr) === undefined || getRemovable(lyr) == true,\n );\n if (!force) {\n to_be_removed = to_be_removed.filter((lyr) => {\n return getFromComposition(lyr);\n });\n }\n\n while (to_be_removed.length > 0) {\n this.map.removeLayer(to_be_removed.shift());\n }\n }\n\n /**\n * Remove all map controls\n */\n removeAllControls(): void {\n [...this.map.getControls().getArray()].forEach((control) => {\n this.map.removeControl(control);\n });\n this.hsConfig.componentsEnabled.mapControls = false;\n }\n\n /**\n * Remove all map interactions\n */\n removeAllInteractions(): void {\n this.map.getInteractions().forEach((interaction) => {\n this.map.removeInteraction(interaction);\n });\n this.hsConfig.mapInteractionsEnabled = false;\n }\n\n /**\n * Get current extent of map, transform it into EPSG:4326 and round coordinates to 2 decimals.\n * This is used mainly in compositions and sharing of map and the coordinates are not very precise.\n * @returns Extent coordinates. Example: \\{east: \"0.00\", south: \"0.00\", west: \"1.00\", north: \"1.00\"\\}\n */\n describeExtent(): BoundingBoxObject {\n const b = this.map.getView().calculateExtent(this.map.getSize());\n let pair1 = [b[0], b[1]];\n let pair2 = [b[2], b[3]];\n const cur_proj = this.getCurrentProj().getCode();\n pair1 = transform(pair1, cur_proj, 'EPSG:4326');\n pair2 = transform(pair2, cur_proj, 'EPSG:4326');\n return {\n east: pair1[0].toFixed(2),\n south: pair1[1].toFixed(2),\n west: pair2[0].toFixed(2),\n north: pair2[1].toFixed(2),\n };\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["VectorSource","controlDefaults","platformModifierKeyOnlyCondition","Static"],"mappings":"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