hslayers-ng
Version:
HSLayers-NG mapping library
191 lines (187 loc) • 8.22 kB
JavaScript
import * as i0 from '@angular/core';
import { inject, Injectable } from '@angular/core';
import { Feature } from 'ol';
import { buffer, getCenter } from 'ol/extent';
import { getDomFeatureLinks, DOM_FEATURE_LINKS } from 'hslayers-ng/common/extensions';
import { isLayerVectorLayer, debounce, isLayerClustered, instOf } from 'hslayers-ng/services/utils';
import { HsLayoutService } from 'hslayers-ng/services/layout';
import { HsLogService } from 'hslayers-ng/services/log';
import { HsMapService } from 'hslayers-ng/services/map';
import { HsQueryBaseService, HsQueryVectorService } from 'hslayers-ng/services/query';
import { HsQueryPopupService } from 'hslayers-ng/common/query-popup';
class HsExternalService {
constructor() {
this.hsMapService = inject(HsMapService);
this.hsLog = inject(HsLogService);
this.hsQueryPopupService = inject(HsQueryPopupService);
this.hsQueryBaseService = inject(HsQueryBaseService);
this.hsQueryVectorService = inject(HsQueryVectorService);
this.hsLayoutService = inject(HsLayoutService);
this.featureLinks = {};
this.hsMapService.loaded().then((map) => {
for (const layer of map.getLayers().getArray()) {
this.layerAdded(layer);
}
map.getLayers().on('add', (e) => this.layerAdded(e.element));
map.getLayers().on('remove', (e) => this.layerRemoved(e.element));
});
}
layerRemoved(layer) {
if (isLayerVectorLayer(layer)) {
for (const key of Object.keys(this.featureLinks)) {
const link = this.featureLinks[key];
if (link.layer == layer) {
this.removeFeatureLink(link);
delete this.featureLinks[key];
}
}
}
}
/**
* Registers DOM--feature links for newly added layer and
* also sets listener for 'propertychange' in case the domFeatureLinks are changed later on.
* The linked feature cannot be a RenderFeature.
* @param layer - OL BaseLayer (superclass of Layer)
*/
layerAdded(layer) {
if (!isLayerVectorLayer(layer)) {
return;
}
if (getDomFeatureLinks(layer)) {
this.processLinks(layer);
}
layer.on('propertychange', (e) => {
debounce(this.layerPropChanged(e), 100, false, this);
});
}
layerPropChanged(e) {
if (e.key == DOM_FEATURE_LINKS) {
this.processLinks(e.target);
}
}
processLinks(layer) {
const source = isLayerClustered(layer)
? layer.getSource().getSource()
: layer.getSource();
for (const link of getDomFeatureLinks(layer)) {
const domElements = document.querySelectorAll(link.domSelector);
domElements.forEach((domElement) => {
const feature = this.getFeature(layer, source, link, domElement);
if (!feature) {
this.hsLog.error(`Cannot bind event ${link.event} from ${domElement} to feature ${link.feature}. Feature not found!`);
return;
}
if (feature.getId() === undefined) {
feature.setId(crypto.randomUUID());
}
//We don't want to add handlers with the same feature and domElement twice
if (feature &&
(!this.featureLinks[feature.getId()] ||
!this.featureLinks[feature.getId()].domElements.includes(domElement))) {
const featureId = feature.getId();
//This was the only way how to unregister handlers afterwards
const handler = (e) => {
for (const action of link.actions) {
this.actOnFeature(action, feature, domElement, e);
}
};
if (!this.featureLinks[featureId]) {
this.featureLinks[featureId] = {
handles: [],
layer,
domElements: [],
event: link.event,
};
}
this.featureLinks[featureId].handles.push(handler);
this.featureLinks[featureId].domElements.push(domElement);
domElement.addEventListener(link.event, handler);
}
});
}
source.on('removefeature', (event) => {
if (!event.features) {
return;
}
for (const removedFeature of event.features) {
const linkage = this.featureLinks[removedFeature.getId()];
if (linkage) {
this.removeFeatureLink(linkage);
delete this.featureLinks[removedFeature.getId()];
}
}
});
}
removeFeatureLink(linkage) {
for (const handle of linkage.handles) {
for (const domEl of linkage.domElements) {
domEl.removeEventListener(linkage.event, handle);
}
}
}
actOnFeature(action, feature, domElement, e) {
if (!this.hsMapService.getLayerForFeature(feature)?.getVisible()) {
return;
}
const geom = feature.getGeometry();
// do not zoom strictly to the extent, but a bit bigger area - needed especially for points
const extent = buffer(geom.getExtent(), 100);
const center = getCenter(extent);
const map = this.hsMapService.getMap();
switch (action) {
case 'zoomToExtent':
this.hsMapService.fitExtent(extent);
break;
case 'panToCenter':
map.getView().setCenter(center);
break;
case 'showPopup':
this.hsQueryPopupService.fillFeatures([feature]);
const pixel = map.getPixelFromCoordinate(center);
this.hsQueryPopupService.showPopup({ pixel, map });
break;
case 'hidePopup':
this.hsQueryPopupService.closePopup();
break;
case 'select':
const select = this.hsQueryBaseService.selector;
select.getFeatures().clear();
this.hsQueryBaseService.clear('features');
select.getFeatures().push(feature);
this.hsQueryVectorService.createFeatureAttributeList();
this.hsLayoutService.setMainPanel('query');
this.hsLayoutService.sidebarExpanded = true;
break;
default:
if (typeof action == 'function') {
action(feature, domElement, e);
}
}
}
getFeature(layer, source, link, domElement) {
if (typeof link.feature == 'string' || typeof link.feature == 'number') {
const featureLike = source.getFeatureById(link.feature);
//Filter out possible RenderFeatures
return featureLike instanceof Feature ? featureLike : undefined;
}
if (instOf(link.feature, Feature)) {
return link.feature;
}
if (typeof link.feature == 'function') {
return link.feature(layer, domElement);
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.3", ngImport: i0, type: HsExternalService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.2.3", ngImport: i0, type: HsExternalService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.3", ngImport: i0, type: HsExternalService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root',
}]
}], ctorParameters: () => [] });
/**
* Generated bundle index. Do not edit.
*/
export { HsExternalService };
//# sourceMappingURL=hslayers-ng-services-external.mjs.map