@geogirafe/lib-geoportal
Version:
GeoGirafe is a flexible application to build online geoportals.
125 lines (124 loc) • 5 kB
JavaScript
// SPDX-License-Identifier: Apache-2.0
import GirafeSingleton from '../../base/GirafeSingleton.js';
import { isSnappableLayer } from '../../models/layers/snappablelayer.js';
import SelectionParam from '../../models/selectionparam.js';
import Snap from 'ol/interaction/Snap.js';
import { Collection } from 'ol';
class SnapManager extends GirafeSingleton {
activeSnapLayers = new Map();
inactiveSnapLayers = [];
get olMap() {
return this.context.mapManager.getMap();
}
get state() {
return this.context.stateManager.state;
}
initializeSingleton() {
this.context.stateManager.subscribe(/layers\.layersList\..*\.activeState/, (_oldActive, _newActive, layer) => {
this.layerUpdated(layer);
});
this.context.stateManager.subscribe(/layers\.layersList\..*\.snapActive/, (_oldSnap, _newSnap, layer) => {
this.layerUpdated(layer);
});
this.context.stateManager.subscribe('layers.isSnappingActive', (_, isSnappingActive) => {
if (isSnappingActive) {
this.activateSnappingForAllLayers();
}
else {
this.deactivateSnappingForAllLayers();
}
});
this.olMap
.getInteractions()
.on('add', (event) => this.mapInteractionsChanged(event.element));
}
mapInteractionsChanged(interaction) {
if (!(interaction instanceof Snap)) {
for (const options of this.activeSnapLayers.values()) {
// Snapping interactions have to be removed and readded, because they mut be the last ones in the list of interactions
// This is a limitation of OpenLayers. Otherwise the drawing interaction will prevail to the snapping one
// And snapping won't work when the drawing tool is changed.
this.olMap.removeInteraction(options.snapInteraction);
this.olMap.addInteraction(options.snapInteraction);
}
}
}
activateSnappingForAllLayers() {
for (const layer of this.inactiveSnapLayers) {
const snapOptions = this.createSnapOptions(layer);
this.registerLayer(layer, snapOptions);
}
this.inactiveSnapLayers = [];
}
deactivateSnappingForAllLayers() {
const layersToDeactivate = Array.from(this.activeSnapLayers.keys());
for (const layer of layersToDeactivate) {
this.unregisterLayer(layer);
this.inactiveSnapLayers.push(layer);
}
}
layerUpdated(layer) {
if (!isSnappableLayer(layer)) {
// Nothing to do
return;
}
if (layer.active && layer.snapActive) {
if (this.state.layers.isSnappingActive) {
const snapOptions = this.createSnapOptions(layer);
this.registerLayer(layer, snapOptions);
}
else {
this.inactiveSnapLayers.push(layer);
}
}
else {
this.unregisterLayer(layer);
}
}
createSnapOptions(layer) {
const snapFeatures = new Collection();
const options = layer.snapOptions || {};
const interaction = new Snap({
edge: options.edge,
features: snapFeatures,
pixelTolerance: options.tolerance,
vertex: options.vertex
});
const snapOptions = {
active: layer.snapActive,
snapInteraction: interaction,
snapFeatures: snapFeatures
};
return snapOptions;
}
registerLayer(layer, snapOptions) {
this.activeSnapLayers.set(layer, snapOptions);
this.loadFeaturesForLayer(layer, snapOptions);
snapOptions.snapInteraction.setActive(true);
this.olMap.addInteraction(snapOptions.snapInteraction);
this.olMap.getView().un('change', this.reloadFeatures.bind(this));
this.olMap.getView().on('change', this.reloadFeatures.bind(this));
}
unregisterLayer(layer) {
const snapOptions = this.activeSnapLayers.get(layer);
if (snapOptions) {
snapOptions.snapInteraction.setActive(false);
snapOptions.snapFeatures.clear();
this.olMap.removeInteraction(snapOptions.snapInteraction);
this.activeSnapLayers.delete(layer);
}
}
reloadFeatures() {
for (const [layer, options] of this.activeSnapLayers) {
this.loadFeaturesForLayer(layer, options);
}
}
async loadFeaturesForLayer(layer, options) {
const client = this.context.wfsManager.getClient(layer.ogcServer);
const extent = this.olMap.getView().getViewStateAndExtent().extent;
const selectionParam = new SelectionParam(layer.ogcServer, [layer], this.state.projection, extent);
const features = await client.getFeature(selectionParam);
options.snapFeatures.extend(features);
}
}
export default SnapManager;