diff --git a/externs/olx.js b/externs/olx.js index 9f34c4723c..1711191910 100644 --- a/externs/olx.js +++ b/externs/olx.js @@ -2359,6 +2359,7 @@ olx.interaction.DragZoomOptions.prototype.style; * type: ol.geom.GeometryType, * minPointsPerRing: (number|undefined), * style: (ol.style.Style|Array.|ol.style.StyleFunction|undefined), + * geometryFunction: (ol.interaction.Draw.GeometryFunctionType|undefined), * geometryName: (string|undefined), * condition: (ol.events.ConditionType|undefined), * freehandCondition: (ol.events.ConditionType|undefined)}} @@ -2417,6 +2418,14 @@ olx.interaction.DrawOptions.prototype.minPointsPerRing; olx.interaction.DrawOptions.prototype.style; +/** + * Function that is called when a geometry's coordinates are updated. + * @type {ol.interaction.Draw.GeometryFunctionType|undefined} + * @api + */ +olx.interaction.DrawOptions.prototype.geometryFunction; + + /** * Geometry name to use for features created by the draw interaction. * @type {string|undefined} diff --git a/src/ol/interaction/drawinteraction.js b/src/ol/interaction/drawinteraction.js index 8fdbf488ce..a7f9423cbe 100644 --- a/src/ol/interaction/drawinteraction.js +++ b/src/ol/interaction/drawinteraction.js @@ -12,6 +12,7 @@ goog.require('ol.FeatureOverlay'); goog.require('ol.MapBrowserEvent'); goog.require('ol.MapBrowserEvent.EventType'); goog.require('ol.Object'); +goog.require('ol.coordinate'); goog.require('ol.events.condition'); goog.require('ol.geom.Circle'); goog.require('ol.geom.GeometryType'); @@ -21,6 +22,7 @@ goog.require('ol.geom.MultiPoint'); goog.require('ol.geom.MultiPolygon'); goog.require('ol.geom.Point'); goog.require('ol.geom.Polygon'); +goog.require('ol.geom.SimpleGeometry'); goog.require('ol.interaction.InteractionProperty'); goog.require('ol.interaction.Pointer'); goog.require('ol.source.Vector'); @@ -149,6 +151,57 @@ ol.interaction.Draw = function(options) { */ this.mode_ = ol.interaction.Draw.getMode_(this.type_); + var geometryFunction = options.geometryFunction; + if (!goog.isDef(geometryFunction)) { + if (this.type_ === ol.geom.GeometryType.CIRCLE) { + /** + * @param {ol.Coordinate|Array.|Array.>} coordinates + * @param {ol.geom.SimpleGeometry=} opt_geometry + * @return {ol.geom.SimpleGeometry} + */ + geometryFunction = function(coordinates, opt_geometry) { + var circle = goog.isDef(opt_geometry) ? opt_geometry : + new ol.geom.Circle([NaN, NaN]); + goog.asserts.assertInstanceof(circle, ol.geom.Circle, + 'geometry must be an ol.geom.Circle'); + var squaredLength = ol.coordinate.squaredDistance( + coordinates[0], coordinates[1]); + circle.setCenterAndRadius(coordinates[0], Math.sqrt(squaredLength)); + return circle; + }; + } else { + var Constructor; + var mode = this.mode_; + if (mode === ol.interaction.DrawMode.POINT) { + Constructor = ol.geom.Point; + } else if (mode === ol.interaction.DrawMode.LINE_STRING) { + Constructor = ol.geom.LineString; + } else if (mode === ol.interaction.DrawMode.POLYGON) { + Constructor = ol.geom.Polygon; + } + /** + * @param {ol.Coordinate|Array.|Array.>} coordinates + * @param {ol.geom.SimpleGeometry=} opt_geometry + * @return {ol.geom.SimpleGeometry} + */ + geometryFunction = function(coordinates, opt_geometry) { + var geometry = opt_geometry; + if (goog.isDef(geometry)) { + geometry.setCoordinates(coordinates); + } else { + geometry = new Constructor(coordinates); + } + return geometry; + }; + } + } + + /** + * @type {ol.interaction.Draw.GeometryFunctionType} + * @private + */ + this.geometryFunction_ = geometryFunction; + /** * Finish coordinate for the feature (first point for polygons, last point for * linestrings). @@ -427,19 +480,19 @@ ol.interaction.Draw.prototype.startDrawing_ = function(event) { this.finishCoordinate_ = start; var geometry; if (this.mode_ === ol.interaction.DrawMode.POINT) { - geometry = new ol.geom.Point(start.slice()); + geometry = this.geometryFunction_(start.slice()); } else { if (this.mode_ === ol.interaction.DrawMode.LINE_STRING) { - geometry = new ol.geom.LineString([start.slice(), start.slice()]); + geometry = this.geometryFunction_([start.slice(), start.slice()]); } else if (this.mode_ === ol.interaction.DrawMode.POLYGON) { this.sketchLine_ = new ol.Feature(new ol.geom.LineString([start.slice(), start.slice()])); this.sketchPolygonCoords_ = [[start.slice(), start.slice()]]; - geometry = new ol.geom.Polygon(this.sketchPolygonCoords_); + geometry = this.geometryFunction_(this.sketchPolygonCoords_); } else if (this.mode_ === ol.interaction.DrawMode.CIRCLE) { - geometry = new ol.geom.Circle(start.slice(), 0); - this.sketchLine_ = new ol.Feature(new ol.geom.LineString([start.slice(), - start.slice()])); + var sketchCoords = [start.slice(), start.slice()]; + this.sketchLine_ = new ol.Feature(new ol.geom.LineString(sketchCoords)); + geometry = this.geometryFunction_(sketchCoords); } } goog.asserts.assert(goog.isDef(geometry), 'geometry should be defined'); @@ -462,27 +515,21 @@ ol.interaction.Draw.prototype.startDrawing_ = function(event) { ol.interaction.Draw.prototype.modifyDrawing_ = function(event) { var coordinate = event.coordinate; var geometry = this.sketchFeature_.getGeometry(); + goog.asserts.assertInstanceof(geometry, ol.geom.SimpleGeometry, + 'geometry should be ol.geom.SimpleGeometry or subclass'); var coordinates, last, sketchLineGeom; if (this.mode_ === ol.interaction.DrawMode.POINT) { - goog.asserts.assertInstanceof(geometry, ol.geom.Point, - 'geometry should be an ol.geom.Point'); last = geometry.getCoordinates(); last[0] = coordinate[0]; last[1] = coordinate[1]; - geometry.setCoordinates(last); + this.geometryFunction_(last, geometry); } else { if (this.mode_ === ol.interaction.DrawMode.LINE_STRING) { - goog.asserts.assertInstanceof(geometry, ol.geom.LineString, - 'geometry should be an ol.geom.LineString'); coordinates = geometry.getCoordinates(); } else if (this.mode_ === ol.interaction.DrawMode.POLYGON) { - goog.asserts.assertInstanceof(geometry, ol.geom.Polygon, - 'geometry should be an ol.geom.Polygon'); coordinates = this.sketchPolygonCoords_[0]; } else if (this.mode_ === ol.interaction.DrawMode.CIRCLE) { - goog.asserts.assertInstanceof(geometry, ol.geom.Circle, - 'geometry should be an ol.geom.Circle'); - coordinates = geometry.getCenter(); + coordinates = coordinate; } if (this.atFinish_(event)) { // snap to finish @@ -496,25 +543,23 @@ ol.interaction.Draw.prototype.modifyDrawing_ = function(event) { last[0] = coordinate[0]; last[1] = coordinate[1]; if (this.mode_ === ol.interaction.DrawMode.LINE_STRING) { - goog.asserts.assertInstanceof(geometry, ol.geom.LineString, - 'geometry should be an ol.geom.LineString'); - geometry.setCoordinates(coordinates); + this.geometryFunction_(coordinates, geometry); } else if (this.mode_ === ol.interaction.DrawMode.POLYGON) { sketchLineGeom = this.sketchLine_.getGeometry(); goog.asserts.assertInstanceof(sketchLineGeom, ol.geom.LineString, 'sketchLineGeom should be an ol.geom.LineString'); sketchLineGeom.setCoordinates(coordinates); - goog.asserts.assertInstanceof(geometry, ol.geom.Polygon, - 'geometry should be an ol.geom.Polygon'); - geometry.setCoordinates(this.sketchPolygonCoords_); + goog.asserts.assert(!goog.isNull(this.sketchPolygonCoords_), + 'sketchPolygonCoords_ must not be null'); + this.geometryFunction_(this.sketchPolygonCoords_, geometry); } else if (this.mode_ === ol.interaction.DrawMode.CIRCLE) { - goog.asserts.assertInstanceof(geometry, ol.geom.Circle, - 'geometry should be an ol.geom.Circle'); sketchLineGeom = this.sketchLine_.getGeometry(); goog.asserts.assertInstanceof(sketchLineGeom, ol.geom.LineString, 'sketchLineGeom should be an ol.geom.LineString'); - sketchLineGeom.setCoordinates([geometry.getCenter(), coordinate]); - geometry.setRadius(sketchLineGeom.getLength()); + var center = sketchLineGeom.getFlatCoordinates().slice(0, 2); + coordinates = [center, coordinate]; + sketchLineGeom.setCoordinates(coordinates); + this.geometryFunction_(coordinates, geometry); } } this.updateSketchFeatures_(); @@ -536,12 +581,12 @@ ol.interaction.Draw.prototype.addToDrawing_ = function(event) { 'geometry should be an ol.geom.LineString'); coordinates = geometry.getCoordinates(); coordinates.push(coordinate.slice()); - geometry.setCoordinates(coordinates); + this.geometryFunction_(coordinates, geometry); } else if (this.mode_ === ol.interaction.DrawMode.POLYGON) { this.sketchPolygonCoords_[0].push(coordinate.slice()); goog.asserts.assertInstanceof(geometry, ol.geom.Polygon, 'geometry should be an ol.geom.Polygon'); - geometry.setCoordinates(this.sketchPolygonCoords_); + this.geometryFunction_(this.sketchPolygonCoords_, geometry); } this.updateSketchFeatures_(); }; @@ -569,7 +614,7 @@ ol.interaction.Draw.prototype.finishDrawing = function() { coordinates = geometry.getCoordinates(); // remove the redundant last point coordinates.pop(); - geometry.setCoordinates(coordinates); + this.geometryFunction_(coordinates, geometry); } else if (this.mode_ === ol.interaction.DrawMode.POLYGON) { goog.asserts.assertInstanceof(geometry, ol.geom.Polygon, 'geometry should be an ol.geom.Polygon'); @@ -578,7 +623,7 @@ ol.interaction.Draw.prototype.finishDrawing = function() { // we force the replacement by the first point this.sketchPolygonCoords_[0].pop(); this.sketchPolygonCoords_[0].push(this.sketchPolygonCoords_[0][0]); - geometry.setCoordinates(this.sketchPolygonCoords_); + this.geometryFunction_(this.sketchPolygonCoords_, geometry); coordinates = geometry.getCoordinates(); } @@ -686,6 +731,19 @@ ol.interaction.Draw.getMode_ = function(type) { }; +/** + * Function that takes coordinates and an optional existing geometry as + * arguments, and returns a geometry. The optional existing geometry is the + * geometry that is returned when the function is called without a second + * argument. + * @typedef {function(!(ol.Coordinate|Array.| + * Array.>), ol.geom.SimpleGeometry=): + * ol.geom.SimpleGeometry} + * @api + */ +ol.interaction.Draw.GeometryFunctionType; + + /** * Draw mode. This collapses multi-part geometry types with their single-part * cousins.