{"version":3,"file":"hslayers-ng-services-external.mjs","sources":["../../../projects/hslayers/services/external/external.service.ts","../../../projects/hslayers/services/external/hslayers-ng-services-external.ts"],"sourcesContent":["import {Injectable, inject} from '@angular/core';\n\nimport BaseLayer from 'ol/layer/Base';\nimport {Cluster, Source, Vector as VectorSource} from 'ol/source';\nimport {Feature} from 'ol';\nimport {Geometry} from 'ol/geom';\nimport {Layer, Vector as VectorLayer} from 'ol/layer';\nimport {ObjectEvent} from 'ol/Object';\nimport {buffer, getCenter} from 'ol/extent';\n\nimport {DOMFeatureLink} from 'hslayers-ng/types';\nimport {\n  DOM_FEATURE_LINKS,\n  getDomFeatureLinks,\n} from 'hslayers-ng/common/extensions';\nimport {\n  debounce,\n  instOf,\n  isLayerClustered,\n  isLayerVectorLayer,\n} from 'hslayers-ng/services/utils';\nimport {HsLayoutService} from 'hslayers-ng/services/layout';\nimport {HsLogService} from 'hslayers-ng/services/log';\nimport {HsMapService} from 'hslayers-ng/services/map';\nimport {\n  HsQueryBaseService,\n  HsQueryVectorService,\n} from 'hslayers-ng/services/query';\nimport {HsQueryPopupService} from 'hslayers-ng/common/query-popup';\n\nexport type FeatureDomEventLink = {\n  handles: EventListenerOrEventListenerObject[];\n  layer: Layer<Source>;\n  domElements: Element[];\n  event: string;\n};\n\nexport interface FeatureDomEventLinkDict {\n  [key: string]: FeatureDomEventLink;\n}\n\n@Injectable({\n  providedIn: 'root',\n})\nexport class HsExternalService {\n  hsMapService = inject(HsMapService);\n  private hsLog = inject(HsLogService);\n  private hsQueryPopupService = inject(HsQueryPopupService);\n  private hsQueryBaseService = inject(HsQueryBaseService);\n  private hsQueryVectorService = inject(HsQueryVectorService);\n  private hsLayoutService = inject(HsLayoutService);\n\n  featureLinks: FeatureDomEventLinkDict = {};\n\n  constructor() {\n    this.hsMapService.loaded().then((map) => {\n      for (const layer of map.getLayers().getArray()) {\n        this.layerAdded(layer as Layer<Source>);\n      }\n      map.getLayers().on('add', (e) => this.layerAdded(e.element));\n      map.getLayers().on('remove', (e) => this.layerRemoved(e.element));\n    });\n  }\n\n  layerRemoved(layer: BaseLayer): void {\n    if (isLayerVectorLayer(layer)) {\n      for (const key of Object.keys(this.featureLinks)) {\n        const link = this.featureLinks[key];\n        if (link.layer == layer) {\n          this.removeFeatureLink(link);\n          delete this.featureLinks[key];\n        }\n      }\n    }\n  }\n\n  /**\n   * Registers DOM--feature links for newly added layer and\n   * also sets listener for 'propertychange' in case the domFeatureLinks are changed later on.\n   * The linked feature cannot be a RenderFeature.\n   * @param layer - OL BaseLayer (superclass of Layer)\n   */\n  layerAdded(layer: BaseLayer): void {\n    if (!isLayerVectorLayer(layer)) {\n      return;\n    }\n    if (getDomFeatureLinks(layer)) {\n      this.processLinks(layer as VectorLayer<VectorSource<Feature>>);\n    }\n    (layer as VectorLayer<VectorSource<Feature>>).on('propertychange', (e) => {\n      debounce(this.layerPropChanged(e), 100, false, this);\n    });\n  }\n\n  layerPropChanged(e: ObjectEvent): void {\n    if (e.key == DOM_FEATURE_LINKS) {\n      this.processLinks(e.target);\n    }\n  }\n\n  private processLinks(layer: VectorLayer<VectorSource<Feature>>) {\n    const source: VectorSource = isLayerClustered(layer)\n      ? (layer.getSource() as Cluster<Feature>).getSource()\n      : layer.getSource();\n    for (const link of getDomFeatureLinks(layer)) {\n      const domElements = document.querySelectorAll(link.domSelector);\n      domElements.forEach((domElement) => {\n        const feature = this.getFeature(layer, source, link, domElement);\n        if (!feature) {\n          this.hsLog.error(\n            `Cannot bind event ${link.event} from ${domElement} to feature ${link.feature}. Feature not found!`,\n          );\n          return;\n        }\n        if (feature.getId() === undefined) {\n          feature.setId(crypto.randomUUID());\n        }\n        //We don't want to add handlers with the same feature and domElement twice\n        if (\n          feature &&\n          (!this.featureLinks[feature.getId()] ||\n            !this.featureLinks[feature.getId()].domElements.includes(\n              domElement,\n            ))\n        ) {\n          const featureId = feature.getId();\n          //This was the only way how to unregister handlers afterwards\n          const handler = (e) => {\n            for (const action of link.actions) {\n              this.actOnFeature(action, feature, domElement, e);\n            }\n          };\n          if (!this.featureLinks[featureId]) {\n            this.featureLinks[featureId] = {\n              handles: [],\n              layer,\n              domElements: [],\n              event: link.event,\n            };\n          }\n          this.featureLinks[featureId].handles.push(handler);\n          this.featureLinks[featureId].domElements.push(domElement);\n          domElement.addEventListener(link.event, handler);\n        }\n      });\n    }\n    source.on('removefeature', (event) => {\n      if (!event.features) {\n        return;\n      }\n      for (const removedFeature of event.features) {\n        const linkage = this.featureLinks[removedFeature.getId()];\n        if (linkage) {\n          this.removeFeatureLink(linkage);\n          delete this.featureLinks[removedFeature.getId()];\n        }\n      }\n    });\n  }\n\n  private removeFeatureLink(linkage: FeatureDomEventLink) {\n    for (const handle of linkage.handles) {\n      for (const domEl of linkage.domElements) {\n        domEl.removeEventListener(linkage.event, handle);\n      }\n    }\n  }\n\n  actOnFeature(\n    action:\n      | 'zoomToExtent'\n      | 'panToCenter'\n      | 'showPopup'\n      | 'hidePopup'\n      | 'select'\n      | ((feature: Feature<Geometry>, domElement: Element, event: any) => any),\n    feature: Feature,\n    domElement: Element,\n    e: Event,\n  ) {\n    if (!this.hsMapService.getLayerForFeature(feature)?.getVisible()) {\n      return;\n    }\n    const geom = feature.getGeometry();\n    // do not zoom strictly to the extent, but a bit bigger area - needed especially for points\n    const extent = buffer(geom.getExtent(), 100);\n    const center = getCenter(extent);\n    const map = this.hsMapService.getMap();\n    switch (action) {\n      case 'zoomToExtent':\n        this.hsMapService.fitExtent(extent);\n        break;\n      case 'panToCenter':\n        map.getView().setCenter(center);\n        break;\n      case 'showPopup':\n        this.hsQueryPopupService.fillFeatures([feature]);\n        const pixel = map.getPixelFromCoordinate(center);\n        this.hsQueryPopupService.showPopup({pixel, map});\n        break;\n      case 'hidePopup':\n        this.hsQueryPopupService.closePopup();\n        break;\n      case 'select':\n        const select = this.hsQueryBaseService.selector;\n        select.getFeatures().clear();\n        this.hsQueryBaseService.clear('features');\n        select.getFeatures().push(feature);\n        this.hsQueryVectorService.createFeatureAttributeList();\n        this.hsLayoutService.setMainPanel('query');\n        this.hsLayoutService.sidebarExpanded = true;\n        break;\n      default:\n        if (typeof action == 'function') {\n          action(feature, domElement, e);\n        }\n    }\n  }\n\n  private getFeature(\n    layer: Layer<Source>,\n    source: VectorSource,\n    link: DOMFeatureLink,\n    domElement: Element,\n  ): Feature<Geometry> {\n    if (typeof link.feature == 'string' || typeof link.feature == 'number') {\n      const featureLike = source.getFeatureById(link.feature);\n      //Filter out possible RenderFeatures\n      return featureLike instanceof Feature ? featureLike : undefined;\n    }\n    if (instOf(link.feature, Feature)) {\n      return link.feature as Feature<Geometry>;\n    }\n    if (typeof link.feature == 'function') {\n      return link.feature(layer, domElement);\n    }\n  }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}