OpenLayers 3 How to register Feature Modified event as "featuremodified" in OpenLayer 2

4.8k views Asked by At

I need to implement Undo / Redo functionality using OpenLayers 3 vector editing (just like demonstrated in http://dev.openlayers.org/examples/modify-feature.html for OpenLayers 2).

To keep track of geometry changes of features, I have to manage a memory stack that will hold changed geometric definitions of features upon user interactions. I know OpenLayers 3 provides observable objects. So ol.Feature or ol.Feature.getGeometry() can be observed for changes, but I am looking for explicit events emitted by ol.interaction.Modify, that should notify me when the interaction starts or ends the vector editing operation (just like "beforefeaturemodified" and "featuremodified" events in OpenLayers 2).

A handler listening for observed geometry or feature changes can be used for the purpose but it is too expensive because geometry of the feature under modification is changed with every pixel move.

I have gone through the official documentation of OpenLayers 3 but couldn't find various events that are provided by OpenLayers 2. In most cases the documentation mentions change event only. I wonder if such events are not a consideration for Openlayer 3's architecture. If it is so, any suggestions how can I extend the existing ol.interaction.Modify to incorporate custom events? thanks.

1

There are 1 answers

1
Alvin Lindstam On

Starting at OpenLayers 3.7.0, ol.interaction.Modify emits modifystartand modifyend. Documentation: http://openlayers.org/en/v3.7.0/apidoc/ol.ModifyEvent.html

Example that randomly decides after each modification if it should be kept or reversed (http://jsfiddle.net/rbha7f83/1/):

var select = new ol.interaction.Select({
    style: overlayStyle
});

// The modify interaction does not listen to geometry change events.
// Changing the feature coordinates will make the modify interaction
// unaware of the actual feature coordinates.
// A possible fix: Maintain a collection used by Modify, so we can reload
// the features manually. This collection will always contain the same
// features as the select interaction.
var selectSource = new ol.Collection();
select.on('select', function (evt) {
    evt.selected.forEach(function (feature) {
        selectSource.push(feature);
    });
    evt.deselected.forEach(function (feature) {
        selectSource.remove(feature);
    });
});

var modify = new ol.interaction.Modify({
    features: selectSource, // use our custom collection
    style: overlayStyle
});

var map = new ol.Map({
    interactions: ol.interaction.defaults().extend([select, modify]),
    layers: [layer],
    target: 'map',
    view: new ol.View({
        center: [0, 1000000],
        zoom: 2
    })
});

var originalCoordinates = {};
modify.on('modifystart', function (evt) {
    evt.features.forEach(function (feature) {
        originalCoordinates[feature] = feature.getGeometry().getCoordinates();
    });
});
modify.on('modifyend', function (evt) {
    evt.features.forEach(function (feature) {
        if (feature in originalCoordinates && Math.random() > 0.5) {
            feature.getGeometry().setCoordinates(
                originalCoordinates[feature]
            );
            delete originalCoordinates[feature];

            // remove and re-add the feature to make Modify reload it's geometry
            selectSource.remove(feature);
            selectSource.push(feature);
        }
    });
})

Note that the events are emitted before and after each interaction. Dragging a vertex and then clicking a vertex to remove it (both on the same feature) will trigger two modifystart and modifyend events.