From e612330dd7679c08043dcea90c77ca00b9e02758 Mon Sep 17 00:00:00 2001 From: ahocevar Date: Thu, 20 Mar 2014 18:31:22 +0100 Subject: [PATCH] Add a way to delete vertices with the Modify interaction After this change, vertices can be deleted by simply clicking on them. This is the same behaviour as e.g. in geojson.io. --- src/ol/interaction/modifyinteraction.js | 153 ++++++++++++++++++++---- 1 file changed, 131 insertions(+), 22 deletions(-) diff --git a/src/ol/interaction/modifyinteraction.js b/src/ol/interaction/modifyinteraction.js index a2f39b2d88..6e95f85706 100644 --- a/src/ol/interaction/modifyinteraction.js +++ b/src/ol/interaction/modifyinteraction.js @@ -63,6 +63,12 @@ ol.interaction.Modify = function(options) { */ this.modifiable_ = false; + /** + * @type {ol.Coordinate} + * @private + */ + this.lastVertexCoordinate_; + /** * @type {ol.Pixel} * @private @@ -401,6 +407,7 @@ ol.interaction.Modify.prototype.handlePointerDown = function(evt) { for (i = insertVertices.length - 1; i >= 0; --i) { this.insertVertex_.apply(this, insertVertices[i]); } + this.lastVertexCoordinate_ = goog.array.clone(vertex); } return this.modifiable_; }; @@ -457,11 +464,18 @@ ol.interaction.Modify.prototype.handlePointerDrag = function(evt) { * @inheritDoc */ ol.interaction.Modify.prototype.handlePointerUp = function(evt) { - var segmentData; - for (var i = this.dragSegments_.length - 1; i >= 0; --i) { - segmentData = this.dragSegments_[i][0]; - this.rBush_.update(ol.extent.boundingExtent(segmentData.segment), - segmentData); + var geometry = this.vertexFeature_.getGeometry(); + goog.asserts.assertInstanceof(geometry, ol.geom.Point); + if (goog.array.equals(this.lastVertexCoordinate_, + geometry.getCoordinates())) { + this.removeVertex_(); + } else { + var segmentData; + for (var i = this.dragSegments_.length - 1; i >= 0; --i) { + segmentData = this.dragSegments_[i][0]; + this.rBush_.update(ol.extent.boundingExtent(segmentData.segment), + segmentData); + } } return false; }; @@ -599,23 +613,8 @@ ol.interaction.Modify.prototype.insertVertex_ = function(segmentData, vertex) { var rTree = this.rBush_; goog.asserts.assert(goog.isDef(segment)); rTree.remove(segmentData); - var uid = goog.getUid(feature); - var segmentDataMatches = []; - this.rBush_.forEachInExtent(geometry.getExtent(), - function(segmentData) { - if (goog.getUid(segmentData.feature) === uid) { - segmentDataMatches.push(segmentData); - } - }); - for (var i = 0, ii = segmentDataMatches.length; i < ii; ++i) { - var segmentDataMatch = segmentDataMatches[i]; - if (segmentDataMatch.geometry === geometry && - (!goog.isDef(depth) || - goog.array.equals(segmentDataMatch.depth, depth)) && - segmentDataMatch.index > index) { - ++segmentDataMatch.index; - } - } + goog.asserts.assert(goog.isDef(index)); + this.updateSegmentIndices_(geometry, index, depth, 1); var newSegmentData = /** @type {ol.interaction.SegmentDataType} */ ({ segment: [segment[0], vertex], feature: feature, @@ -638,3 +637,113 @@ ol.interaction.Modify.prototype.insertVertex_ = function(segmentData, vertex) { newSegmentData2); this.dragSegments_.push([newSegmentData2, 0]); }; + + +/** + * Removes a vertex from all matching features. + * @private + */ +ol.interaction.Modify.prototype.removeVertex_ = function() { + var dragSegments = this.dragSegments_; + var segmentsByFeature = {}; + var component, coordinates, deleted, dragSegment, geometry, i, index, left; + var newIndex, newSegment, right, segmentData, uid; + for (i = dragSegments.length - 1; i >= 0; --i) { + dragSegment = dragSegments[i]; + segmentData = dragSegment[0]; + geometry = segmentData.geometry; + coordinates = geometry.getCoordinates(); + uid = goog.getUid(segmentData.feature); + left = right = index = undefined; + if (dragSegment[1] == 0) { + right = segmentData; + index = segmentData.index; + } else if (dragSegment[1] == 1) { + left = segmentData; + index = segmentData.index + 1; + } + if (!(uid in segmentsByFeature)) { + segmentsByFeature[uid] = [left, right, index]; + } + newSegment = segmentsByFeature[uid]; + if (goog.isDef(left)) { + newSegment[0] = left; + } + if (goog.isDef(right)) { + newSegment[1] = right; + } + if (goog.isDef(newSegment[0]) && goog.isDef(newSegment[1])) { + component = coordinates; + deleted = false; + newIndex = index - 1; + switch (geometry.getType()) { + case ol.geom.GeometryType.MULTI_LINE_STRING: + coordinates[segmentData.depth[0]].splice(index, 1); + deleted = true; + break; + case ol.geom.GeometryType.LINE_STRING: + coordinates.splice(index, 1); + deleted = true; + break; + case ol.geom.GeometryType.MULTI_POLYGON: + component = component[segmentData.depth[1]]; + case ol.geom.GeometryType.POLYGON: + component = component[segmentData.depth[0]]; + if (component.length > 4) { + if (index == component.length - 1) { + index = 0; + } + component.splice(index, 1); + deleted = true; + if (index === 0) { + // close the ring again + component.pop(); + component.push(component[0]); + newIndex = component.length - 1; + } + } + break; + } + + if (deleted) { + this.rBush_.remove(newSegment[0]); + this.rBush_.remove(newSegment[1]); + geometry.setCoordinates(coordinates); + goog.asserts.assert(newIndex >= 0); + var newSegmentData = /** @type {ol.interaction.SegmentDataType} */ ({ + depth: segmentData.depth, + feature: segmentData.feature, + geometry: segmentData.geometry, + index: newIndex, + segment: [newSegment[0].segment[0], newSegment[1].segment[1]] + }); + this.rBush_.insert(ol.extent.boundingExtent(newSegmentData.segment), + newSegmentData); + this.updateSegmentIndices_(geometry, index, segmentData.depth, -1); + + this.overlay_.removeFeature(this.vertexFeature_); + this.vertexFeature_ = null; + } + } + } +}; + + +/** + * @param {ol.geom.SimpleGeometry} geometry Geometry. + * @param {number} index Index. + * @param {Array.|undefined} depth Depth. + * @param {number} delta Delta (1 or -1). + * @private + */ +ol.interaction.Modify.prototype.updateSegmentIndices_ = function( + geometry, index, depth, delta) { + this.rBush_.forEachInExtent(geometry.getExtent(), function(segmentDataMatch) { + if (segmentDataMatch.geometry === geometry && + (!goog.isDef(depth) || + goog.array.equals(segmentDataMatch.depth, depth)) && + segmentDataMatch.index > index) { + segmentDataMatch.index += delta; + } + }); +};