From d41bfde25df1f3f9279e565649bc2108cce20b09 Mon Sep 17 00:00:00 2001 From: drnextgis Date: Sun, 20 Mar 2016 03:04:58 +0600 Subject: [PATCH] snap to vertices or edges --- externs/olx.js | 19 ++++++- src/ol/interaction/snapinteraction.js | 56 +++++++++++++++---- .../ol/interaction/snapinteraction.test.js | 37 ++++++++++++ 3 files changed, 99 insertions(+), 13 deletions(-) diff --git a/externs/olx.js b/externs/olx.js index 2472c92e83..3ebe0f635f 100644 --- a/externs/olx.js +++ b/externs/olx.js @@ -3098,7 +3098,9 @@ olx.interaction.SelectOptions.prototype.wrapX; * @typedef {{ * features: (ol.Collection.|undefined), * pixelTolerance: (number|undefined), - * source: (ol.source.Vector|undefined) + * source: (ol.source.Vector|undefined), + * edge: (boolean|undefined), + * vertex: (boolean|undefined) * }} * @api */ @@ -3112,6 +3114,21 @@ olx.interaction.SnapOptions; */ olx.interaction.SnapOptions.prototype.features; +/** + * Snap to edges. Default is `true`. + * @type {boolean|undefined} + * @api + */ +olx.interaction.SnapOptions.prototype.edge; + + +/** + * Snap to vertices. Default is `true`. + * @type {boolean|undefined} + * @api + */ +olx.interaction.SnapOptions.prototype.vertex; + /** * Pixel tolerance for considering the pointer close enough to a segment or diff --git a/src/ol/interaction/snapinteraction.js b/src/ol/interaction/snapinteraction.js index b952c684a6..826a13b4f3 100644 --- a/src/ol/interaction/snapinteraction.js +++ b/src/ol/interaction/snapinteraction.js @@ -61,6 +61,18 @@ ol.interaction.Snap = function(opt_options) { */ this.source_ = options.source ? options.source : null; + /** + * @private + * @type {boolean} + */ + this.vertex_ = options.vertex !== undefined ? options.vertex : true; + + /** + * @private + * @type {boolean} + */ + this.edge_ = options.edge !== undefined ? options.edge : true; + /** * @type {ol.Collection.} * @private @@ -374,28 +386,48 @@ ol.interaction.Snap.prototype.snapTo = function(pixel, pixelCoordinate, map) { var snapped = false; var vertex = null; var vertexPixel = null; + var dist, pixel1, pixel2, squaredDist1, squaredDist2; if (segments.length > 0) { this.pixelCoordinate_ = pixelCoordinate; segments.sort(this.sortByDistance_); var closestSegment = segments[0].segment; - vertex = (ol.coordinate.closestOnSegment(pixelCoordinate, - closestSegment)); - vertexPixel = map.getPixelFromCoordinate(vertex); - if (Math.sqrt(ol.coordinate.squaredDistance(pixel, vertexPixel)) <= - this.pixelTolerance_) { - snapped = true; - var pixel1 = map.getPixelFromCoordinate(closestSegment[0]); - var pixel2 = map.getPixelFromCoordinate(closestSegment[1]); - var squaredDist1 = ol.coordinate.squaredDistance(vertexPixel, pixel1); - var squaredDist2 = ol.coordinate.squaredDistance(vertexPixel, pixel2); - var dist = Math.sqrt(Math.min(squaredDist1, squaredDist2)); + if (this.vertex_ && !this.edge_) { + pixel1 = map.getPixelFromCoordinate(closestSegment[0]); + pixel2 = map.getPixelFromCoordinate(closestSegment[1]); + squaredDist1 = ol.coordinate.squaredDistance(pixel, pixel1); + squaredDist2 = ol.coordinate.squaredDistance(pixel, pixel2); + dist = Math.sqrt(Math.min(squaredDist1, squaredDist2)); snappedToVertex = dist <= this.pixelTolerance_; if (snappedToVertex) { + snapped = true; vertex = squaredDist1 > squaredDist2 ? closestSegment[1] : closestSegment[0]; vertexPixel = map.getPixelFromCoordinate(vertex); - vertexPixel = [Math.round(vertexPixel[0]), Math.round(vertexPixel[1])]; } + } else if (this.edge_) { + vertex = (ol.coordinate.closestOnSegment(pixelCoordinate, + closestSegment)); + vertexPixel = map.getPixelFromCoordinate(vertex); + if (Math.sqrt(ol.coordinate.squaredDistance(pixel, vertexPixel)) <= + this.pixelTolerance_) { + snapped = true; + if (this.vertex_) { + pixel1 = map.getPixelFromCoordinate(closestSegment[0]); + pixel2 = map.getPixelFromCoordinate(closestSegment[1]); + squaredDist1 = ol.coordinate.squaredDistance(vertexPixel, pixel1); + squaredDist2 = ol.coordinate.squaredDistance(vertexPixel, pixel2); + dist = Math.sqrt(Math.min(squaredDist1, squaredDist2)); + snappedToVertex = dist <= this.pixelTolerance_; + if (snappedToVertex) { + vertex = squaredDist1 > squaredDist2 ? + closestSegment[1] : closestSegment[0]; + vertexPixel = map.getPixelFromCoordinate(vertex); + } + } + } + } + if (snapped) { + vertexPixel = [Math.round(vertexPixel[0]), Math.round(vertexPixel[1])]; } } return /** @type {ol.interaction.Snap.ResultType} */ ({ diff --git a/test/spec/ol/interaction/snapinteraction.test.js b/test/spec/ol/interaction/snapinteraction.test.js index d5df59cb7f..0b2b7fa07a 100644 --- a/test/spec/ol/interaction/snapinteraction.test.js +++ b/test/spec/ol/interaction/snapinteraction.test.js @@ -64,6 +64,42 @@ describe('ol.interaction.Snap', function() { expect(event.coordinate).to.eql([0, 0]); }); + it('snaps to edges only', function() { + var point = new ol.Feature(new ol.geom.LineString([[-10, 0], [10, 0]])); + var snapInteraction = new ol.interaction.Snap({ + features: new ol.Collection([point]), + pixelTolerance: 5, + vertex: false + }); + snapInteraction.setMap(map); + + var event = { + pixel: [7 + width / 2, height / 2 - 4], + coordinate: [7, 4], + map: map + }; + ol.interaction.Snap.handleEvent_.call(snapInteraction, event); + expect(event.coordinate).to.eql([7, 0]); + }); + + it('snaps to vertices only', function() { + var point = new ol.Feature(new ol.geom.LineString([[-10, 0], [10, 0]])); + var snapInteraction = new ol.interaction.Snap({ + features: new ol.Collection([point]), + pixelTolerance: 5, + edge: false + }); + snapInteraction.setMap(map); + + var event = { + pixel: [7 + width / 2, height / 2 - 4], + coordinate: [7, 4], + map: map + }; + ol.interaction.Snap.handleEvent_.call(snapInteraction, event); + expect(event.coordinate).to.eql([10, 0]); + }); + }); }); @@ -73,4 +109,5 @@ goog.require('ol.Feature'); goog.require('ol.Map'); goog.require('ol.View'); goog.require('ol.geom.Point'); +goog.require('ol.geom.LineString'); goog.require('ol.interaction.Snap');