Adrian
Adrian

Reputation: 11

How can a feature be selected after the geometry has been changed in openlayers?

I am trying to draw a Rectangle and increase it size that it stays rectified. The corner of the rectangle can be selected and moved. The two adjacent corner are automatically moved that the polygon/rectangle is still rectified. After the rectangle is modified it is correctly drawn, but none of the adjacent corner are selectable anymore. If the mouse is place where the old position of the corners were, the corner can be selected and moved

I am working with the modify Interaction and it looks like if am changing the geometry of the feature, the Interaction does not recognice it. I am not sure how I can update the feature for the Interaction.

My starting point was this stackoverflow code here: OpenLayers - lock rotation of box or rectangle geometry while modifying.

Here is my “playground” code for my Reactcomponent. I added all code, because I am not sure, if am doing something wrong during the initialziaton of the map:

import React, { useEffect, useState } from 'react';
import Map from 'ol/Map';
import View from 'ol/View';
import TileLayer from 'ol/layer/Tile';
import LayerVector from 'ol/layer/Vector';
import Collection from 'ol/Collection';
import SourceVector from 'ol/source/Vector';
import OSM from 'ol/source/OSM'
import { fromLonLat} from 'ol/proj'

//Fancy CSS 
import 'ol/ol.css';

//Draw Box https://openlayers.org/en/latest/examples/draw-shapes.html?q=poly
import Draw, { createBox } from 'ol/interaction/Draw';
import { Modify } from 'ol/interaction'
import { never } from 'ol/events/condition';


function Map() {

  const mapsize = {
    height: '10%vp',
    width: '100%',
  };

  var old_coords;

  useEffect(() => {

    var collection = new Collection();
    var source = new SourceVector({
      feature: collection
      // wrapX: false
    });

    //default OpenStreetMap layer
    var raster = new TileLayer({ source: new OSM() });

    //drawing Rectangle
    var draw = new Draw({
      source: source,
      type: 'Circle',
      geometryFunction: createBox()
    });
    draw.on("drawend", function (e) {
      draw.setActive(false);
      old_coords = e.feature.getGeometry().getCoordinates()[0];
    });

    // create feature layer and vector source
    var layerVector = new LayerVector({
      source: source,
    });

    // create map object with feature layer
    var map = new Map({
      target: 'map',
      layers: [raster, layerVector],
      view: new View({
        center: fromLonLat([-0.164794921875, 51.481382896100996]),
        zoom: 13,
      })
    });


    // Only the corner can be modified
    var modify = new Modify({
      source: source,
      insertVertexCondition: never,
    });
    modify.on('modifystart', function (event) {
      var feature = event.features.getArray()[0];
      feature.on("change", changeFeatureFunction);
    });
    modify.on('modifyend', function (event) {
      old_coords = event.features.getArray()[0].getGeometry().getCoordinates()[0];
    })

    map.addInteraction(draw);
    map.addInteraction(modify);
  }, [])


  function changeFeatureFunction(event) {
    let feature = event.target;
    let geometry = feature.getGeometry();
    const coords = geometry.getCoordinates()[0];

    // Removing change event temporarily to avoid infinite recursion
    feature.un("change", changeFeatureFunction);

    var new_coords = rectanglifyModifiedGeometry(coords);
    feature.getGeometry().setCoordinates([[...new_coords]]);

    feature.on("change", changeFeatureFunction);
  }

  function rectanglifyModifiedGeometry(coords) {
    var new_coords = [...coords];
    //Bottom Left
    if (!SameCoordinate(coords[0], old_coords[0])) {
      console.log("first Coordinates has been change");
      new_coords[3][0] = new_coords[0][0]
      new_coords[1][1] = new_coords[0][1]
    }
    //Bottom Right
    else if (!SameCoordinate(coords[1], old_coords[1])) {
      console.log("second Coordinates has been change");
      new_coords[0][1] = new_coords[1][1]
      new_coords[2][0] = new_coords[1][0]
    }
    //Top Right
    else if (!SameCoordinate(coords[2], old_coords[2])) {
      console.log("third Coordinates has been change");
      new_coords[1][0] = new_coords[2][0]
      new_coords[3][1] = new_coords[2][1]
    }
    //Top Left
    else if (!SameCoordinate(coords[3], old_coords[3])) {
      console.log("fourth Coordinates has been change");
      new_coords[2][1] = new_coords[3][1]
      new_coords[0][0] = new_coords[3][0]
    }
    old_coords = coords;
    new_coords.length = 4;
    return new_coords
  }

  function SameCoordinate(point1, point2) {
    return (point1[0] === point2[0]) && (point1[1] === point2[1])

  }

  return (
    <div id="dummycontainer" >
      <div id="map" >
      </div>
    </div>
  )
}

export default Map;

Upvotes: 1

Views: 1227

Answers (1)

Mike
Mike

Reputation: 17962

Your new coordinates are invalid as the first and last should be the same to close the polygon, so a rectangle needs 5 pairs of coordinates.

replace

new_coords.length = 4;

with

  new_coords[4][0] = new_coords[0][0]
  new_coords[4][1] = new_coords[0][1]

A better way to avoid recursion is to use

feature.once("change", changeFeatureFunction);

Upvotes: 0

Related Questions