mapview_interactions_modify.mjs

/**
## Mapview.interactions.modify()

Dictionary entries:
- delete_vertex

@requires /dictionary

@module /mapview/interactions/modify

@param {Object} params
The params object argument.
*/

export default function (params) {
  const mapview = this;

  // Finish the current interaction.
  mapview.interaction?.finish();

  mapview.interaction = {
    type: 'modify',

    finish,

    format: new ol.format.GeoJSON(),

    source: new ol.source.Vector(),

    Layer: new ol.layer.Vector({
      zIndex: Infinity,
    }),

    vertices: [],

    modifyend: mapp.ui?.elements.contextMenu.modify.bind(this),

    getFeature,

    Style: [
      new ol.style.Style({
        image: new ol.style.Circle({
          stroke: new ol.style.Stroke({
            color: '#3399CC',
            width: 1.25,
          }),
          radius: 5,
        }),
        stroke: new ol.style.Stroke({
          color: '#3399CC',
          width: 1.25,
        }),
      }),
      new ol.style.Style({
        image: new ol.style.Circle({
          radius: 5,
          fill: new ol.style.Fill({
            color: '#eee',
          }),
          stroke: new ol.style.Stroke({
            color: '#3399CC',
            width: 1.25,
          }),
        }),
        geometry: mapp.utils.verticeGeoms,
      }),
    ],

    deleteCondition: (e) => {
      if (e.type === 'singleclick') {
        const geom = mapview.interaction.Feature.getGeometry();

        const geomType = geom.getType();

        if (geomType === 'Point') return;

        const coords = geom.getCoordinates();

        // Return on point or line with 2 vertices.
        if (geomType === 'LineString' && coords.length < 3) return;

        // Return on polygon with less than 3 vertices.
        if (geomType === 'Polygon' && coords[0].length <= 4) return;

        // Set popup to remove vertex.
        mapview.popup({
          coords: geom.getClosestPoint(e.coordinate),
          content: mapp.utils.html.node`<ul>
            <li
              onclick=${() => {
                mapview.interaction.interaction.removePoint();
                mapview.interaction.vertices.push(
                  mapview.interaction.Feature.getGeometry().getClosestPoint(
                    e.coordinate,
                  ),
                );
              }}>${mapp.dictionary.delete_vertex}`,
        });
      }
    },

    // Spread params argument.
    ...params,
  };

  mapview.Map.getTargetElement().style.cursor = 'crosshair';

  mapview.interaction.source.addFeature(mapview.interaction.Feature);

  // Set mapview.interaction.Layer source.
  mapview.interaction.Layer.setSource(mapview.interaction.source);

  // Set mapview.interaction.Layer style
  mapview.interaction.Layer.setStyle(mapview.interaction.Style);

  // Add mapview.interaction.Layer to mapview.
  mapview.Map.addLayer(mapview.interaction.Layer);

  mapview.interaction.interaction = new ol.interaction.Modify(
    mapview.interaction,
  );

  // Will clear remove vertex popup.
  mapview.interaction.interaction.on('modifystart', (e) => {
    mapview.popup(null);
  });

  if (typeof mapview.interaction.modifyend === 'function') {
    mapview.interaction.interaction.on(
      'modifyend',
      mapview.interaction.modifyend,
    );
  }

  // Add OL interaction to mapview.Map
  mapview.Map.addInteraction(mapview.interaction.interaction);

  // Assign snap interaction.
  mapview.interactions.snap(mapview);

  function getFeature() {
    return JSON.parse(
      mapview.interaction.format.writeFeature(mapview.interaction.Feature, {
        dataProjection: 'EPSG:' + mapview.interaction.srid || mapview.srid,
        featureProjection: 'EPSG:' + mapview.srid,
      }),
    );
  }

  function finish(feature) {
    // Remove snap interaction.
    mapview.interaction.snap?.remove?.();

    // Reset the cursor style.
    mapview.Map.getTargetElement().style.cursor = 'default';

    // Remove popup from mapview.
    mapview.popup(null);

    // Remove interaction from mapview.Map.
    mapview.Map.removeInteraction(mapview.interaction.interaction);

    // Clear the modify source.
    mapview.interaction.source.clear();

    // Remove draw Layer from mapview.Map.
    mapview.Map.removeLayer(mapview.interaction.Layer);

    mapview.interaction.callback?.(feature);
  }
}