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.
Starting at OpenLayers 3.7.0, ol.interaction.Modify emits modifystart
and 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With