Undoing last point when drawing linestring in OpenLayers 3?

Undoing last point when drawing linestring in OpenLayers 3?

I would like to be able to draw a linestring and to be able to undo the last drawn point when the key ESC is pressed.

I used that code when I first wrote my application :

// create the interaction draw_interaction = new ol.interaction.Draw({ source: vector_layer.getSource(), type: /** @type {ol.geom.GeometryType} */ ($geom_type.val()) }); // add it to the map map.addInteraction(draw_interaction); // when a new feature has been drawn… draw_interaction.on('drawstart', function(evt) { var feature = evt.feature; var geom = feature.getGeometry(); document.addEventListener('keyup', function() { if (event.keyCode === 27) { if (geom.getType() === "LineString") { var coords = geom.getCoordinates(); var len = coords.length; console.log("undo"); if (len > 1) { geom.setCoordinates(geom.getCoordinates().slice(0, len - 1)); } } } }); });

You can see a live version on codepen following that link:

My problem is when I upgraded from 3.5.0 to 3.6.0, the behaviour changed :

As you can see on the live example, when undoing (pressing ESC) it seems to be working but when you want to add a new point to the linestring, the points I removed are back in place. Looks like a caching behaviour as been added to 3.6.0

I hope someone can help me, it's either a regression or a api modification that I did not notice in the change log.

Since OpenLayers 3.9.0, this is as simple as using theremoveLastPointmethod of theDrawInteraction. So you can do something like this:

document.addEventListener('keydown', function(e) { if (e.which == 27) draw_interaction.removeLastPoint() });

Since v3.6.0, ageometryFunctionis used to return the geometry resulting from drawing withol.interaction.Draw. ThisgeometryFunctionis where you modify the geometry during drawing. So what you can do is set an undo flag to true when the user hits the Esc key. In thegeometryFunctionyou change the coordinates when the flag was set:

var undo = false; // set this to true in the Esc key handler var draw = new ol.interaction.Draw({ //… geometryFunction: function(coords, geom) { if (!geom) { geom = new ol.geom.LineString(null); } if (undo) { if (coords.length > 1) { coords.pop(); } undo = false; } geom.setCoordinates(coords); return geom; } });

I've made some tests and this can be done with something like this:

Set a custom listener to your draw interaction.


Set a global variable if drawing start, and store the created feature:

draw.on('drawstart', function(evt){ drawing = true; drawing_feature = evt.feature; });

Set a keydown listener to the document and if drawing is active, fire your custom event:

var keydown = function(evt){ var charCode = (evt.which) ? evt.which : evt.keyCode; if (charCode === 27 && drawing === true){ //esc key //dispatch event draw.set('escKey', Math.random()); } }; document.addEventListener('keydown', keydown, false);

And then slice the lineString coordinates:

draw.on('change:escKey', function(evt){ var geom = drawing_feature.getGeometry(); var coords = geom.getCoordinates(); var len = coords.length; if (len > 1) { var new_coordinates = coords.slice(0, len - 1); geom.setCoordinates(new_coordinates); //this is just visual //this (target.e) is the equivalent of this.sketchCoords_ in debug mode = new_coordinates; } });

Now, notice, orthis.sketchCoords_in ol-debug.js. This is a temporary/internal array of coords, perhaps, there's a better way to do this. I've tried a lot of others options and this was the only way.

Maybe a core developer can show us a better approach.

Oh yes, a working demo.