Skip to content
Snippets Groups Projects
edition-service.js 9.00 KiB
import { Draw, Snap } from 'ol/interaction';
import Modify from 'ol/interaction/Modify';
import { Collection } from 'ol';
import MultiPoint from 'ol/geom/MultiPoint';
import {
  Fill, Stroke, Style, Circle, Text //RegularShape, Circle as CircleStyle, Text,Icon
} from 'ol/style';
import VectorSource from 'ol/source/Vector';
import VectorLayer from 'ol/layer/Vector';
import mapService from '@/services/map-service';
import { buffer } from 'ol/extent';

const editionService = {
  drawnFeature: null,
  featureToEdit: null,
  editing_feature: {},
  geom_type: 'linestring',
  // Création d'une collection filtrée
  filteredFeatures: new Collection(),
  // Méthode pour créer un style basé sur la couleur actuelle
  createDrawStyle(isEditing) {
    return [
      new Style({
        // Style principal pour le polygone
        fill: new Fill({
          color: isEditing ? 'rgba(255, 145, 0, .2)' : 'rgba(255, 255, 255, .2)',
        }),
        // Style principal pour la ligne et le tour du polygone
        stroke: new Stroke({
          color: isEditing ? 'rgba(255, 145, 0, .9)' : 'rgba(255, 45, 0, 0.5)',
          lineDash: [],
          width: 2,
        }),
        // Style principal pour le point
        image: new Circle({
          radius: 7,
          stroke: new Stroke({
            color: 'rgba(255, 0, 0, 0.5)',
            lineDash: [],
            width: 2
          }),
          fill: new Fill({
            color: isEditing ? 'rgba(255, 145, 0, 0.9)' : 'rgba(255, 255, 255, 0.5)'
          })
        }),
        // Style pour le texte, pas utilisé mais peut être conservé au cas où
        text: new Text({
          font: '12px Calibri,sans-serif',
          fill: new Fill({ color: '#000' }),
          stroke: new Stroke({
            color: '#fff',
            width: 1
          }),
          text: ''
        }),
        zIndex: 50
      }),
      // Style pour afficher des points sur les sommets de ligne ou polygone (seulement en mode édition)
      ...(isEditing
        ? [
          // Définition du style de point
          new Style({
            image: new Circle({
              radius: 5,
              stroke: new Stroke({
                color: 'rgba(255, 145, 0, .9)',
                width: 2,
              }),
              fill: new Fill({
                color: 'rgba(255, 145, 0, .5)',
              }),
            }),
            // Récupération des sommets où afficher les points uniquement pour ligne et polygone
            geometry: function (feature) {
              const geometry = feature.getGeometry();
              if (geometry.getType() === 'LineString') {
                return new MultiPoint(geometry.getCoordinates()); // Sommets de la ligne
              } else if (geometry.getType() === 'Polygon') {
                return new MultiPoint(geometry.getCoordinates()[0]); // Sommets du premier anneau
              }
              return null;
            },
          }),
        ]
        : []),
    ];
  },

  // Méthode pour changer la couleur de la géométrie existante en passant en mode édition
  toggleEditionColor(isEditing) {
    const drawStyle = this.createDrawStyle(isEditing); // Re-crée le style
    this.drawnItems.setStyle(drawStyle); // Applique le style à la couche
  },

  setEditingFeature(feature) {
    this.editing_feature = feature;
  },

  initFeatureToEdit(feature) {
    this.editing_feature = feature;
    this.draw.setActive(false);
    this.drawSource.addFeature(feature);
    this.drawnItems.setZIndex(50);
    mapService.fitExtent(buffer(this.drawSource.getExtent(),200));
  },

  addEditionControls(geomType) {
    this.geom_type = geomType;
    this.drawSource = new VectorSource();
    this.drawnItems = new VectorLayer({
      source: this.drawSource,
      style: this.createDrawStyle(),
      zIndex: 4000
    });

    mapService.getMap().addLayer(this.drawnItems);
    if (this.draw) {
      mapService.getMap().removeInteraction(this.draw);
    }
    let gType = 'Point';
    if (geomType.toUpperCase().indexOf('POLYGON') >= 0) {
      gType = 'Polygon';
    }
    else if (geomType.toUpperCase().indexOf('LINE') >= 0) {
      gType = 'LineString';
    }

    this.draw = new Draw({
      source: this.drawSource,
      type: gType,
      style: this.createDrawStyle()
    });
    mapService.getMap().addInteraction(this.draw);
    this.setEditingFeature(undefined);

    this.draw.on('drawend', (evt) => {
      var feature = evt.feature;
      this.drawnFeature = feature;
      this.setEditingFeature(feature);
      this.draw.setActive(false);
    });

    this.modify = new Modify({
      style: this.createDrawStyle(),
      features: this.filteredFeatures, // Limite la modification aux entités filtrées
    });

    // This workaround allows to avoid the ol freeze
    // referenced bug : https://github.com/openlayers/openlayers/issues/6310
    // May be corrected in a future version
    this.modify.handleUpEvent_old = this.modify.handleUpEvent;
    this.modify.handleUpEvent = function (evt) {
      try {
        this.handleUpEvent_old(evt);
      } catch (ex) {
        console.log(ex);
      }
    };

    mapService.getMap().addInteraction(this.modify);

    // Supprime dynamiquement la feature des entités modifiables
    this.drawSource.on('removefeature', (event) => {
      const feature = event.feature;
      this.filteredFeatures.remove(feature);
    });
  },
  resetAllTools() {
    if (this.draw) {
      this.draw.setActive(false);
    }
    if (this.modify) {
      this.modify.setActive(false);
    }
  },
  removeSelectInteraction(interaction) {
    interaction.getFeatures().clear();
    interaction.setActive(false);
  },
  activeUpdateFeature(isEditing) {
    this.resetAllTools();
    if (isEditing) {
      // Mise à jour des entités modifiables
      this.drawSource.forEachFeature((feature) => {
        if (
          (this.featureToEdit && feature.id_ === this.featureToEdit.id) ||
          (this.drawnFeature && feature.ol_uid === this.drawnFeature.ol_uid) ||
          (!this.drawnFeature && !this.featureToEdit)
        ) {
          this.filteredFeatures.push(feature);
        }
      });
      
      this.modify.setActive(true);
    }
    this.toggleEditionColor(isEditing);
  },
  /**
   * Deletes the currently displayed feature from the map.
   * This method removes the feature directly from the source without additional selection steps.
   * It assumes that there is only one feature present in the source.
   * Resets the color for future drawings to the default to ensure that the editing color
   * is not displayed if the edit mode was active prior to deletion.
   */
  removeFeatureFromMap() {
    // Access the source where the features are stored
    const source = this.drawSource; // Replace with the correct reference to your OpenLayers source
    // Get all features from the source
    const features = source.getFeatures();
    // Check if there is a feature to delete
    if (features.length > 0 && confirm('Etes-vous sur de vouloir supprimer cet objet ?')) {
      try {
        // Reset all other tools to ensure only the delete feature functionality is active
        this.resetAllTools();
        // Remove the feature from the source
        const featureToRemove = features[0];
        source.removeFeature(featureToRemove);
        // Reinitialize the feature edited on the map
        this.editing_feature = undefined;
        // Toggle draw mode to create a new feature
        this.draw.setActive(true);
        // Reset color to default
        this.toggleEditionColor(false);
        // Return operation result after user confirmed to remove the feature
        return true;
      } catch (error) {
        // Log an error if the feature cannot be removed
        console.error('Error while deleting the feature: ', error);
      }
    }
    return false;
  },

  setFeatureToEdit(feature) {
    this.featureToEdit = feature;
  },

  removeActiveFeatures() {
    this.drawnFeature = null;
    this.featureToEdit = null;
  },

  addSnapInteraction(map) {
    // The snap interaction must be added after the Modify and Draw interactions
    // in order for its map browser event handlers to be fired first. Its handlers
    // are responsible of doing the snapping.

    // Since we can't give a list of source to snap,
    // we use this workaround, an interaction collection: https://github.com/openlayers/openlayers/issues/7100
    let interactions = [];
    map.getLayers().forEach((layer) => {
      if (layer instanceof VectorLayer) {
        let interaction = new Snap({
          source: layer.getSource()
        });
        interactions.push(interaction);
      }
    });

    for(let snap of interactions ) {
      map.addInteraction(snap);
    }
  },

  removeSnapInteraction(map) {
    // Find the double click interaction that is on the map.
    let interactions = [];
    map.getInteractions().forEach(function (interaction) {
      if (interaction instanceof Snap) {
        interactions.push(interaction);
      }
    });

    // Remove the interaction from the map.
    for(let snap of interactions ) {
      map.removeInteraction(snap);
    }
  }
};

export default editionService;