diff --git a/examples/modify-feature.html b/examples/modify-feature.html
index 3835a2764f..3338cd7ec7 100644
--- a/examples/modify-feature.html
+++ b/examples/modify-feature.html
@@ -53,6 +53,9 @@
OpenLayers.Handler.Path),
polygon: new OpenLayers.Control.DrawFeature(vectors,
OpenLayers.Handler.Polygon),
+ regular: new OpenLayers.Control.DrawFeature(vectors,
+ OpenLayers.Handler.RegularPolygon,
+ {handlerOptions: {sides: 5}}),
modify: new OpenLayers.Control.ModifyFeature(vectors,
modifyOptions)
};
@@ -65,6 +68,19 @@
document.getElementById('noneToggle').checked = true;
}
+ function update() {
+ var rotate = document.getElementById("rotate").checked;
+ controls.modify.rotate = rotate;
+ var resize = document.getElementById("resize").checked;
+ controls.modify.resize = resize;
+ var drag = document.getElementById("drag").checked;
+ controls.modify.drag = drag;
+ var sides = parseInt(document.getElementById("sides").value);
+ sides = Math.max(3, isNaN(sides) ? 0 : sides);
+ controls.regular.handler.sides = sides;
+ var irregular = document.getElementById("irregular").checked;
+ controls.regular.handler.irregular = irregular;
+ }
function toggleControl(element) {
for(key in controls) {
@@ -101,10 +117,41 @@
+
+
+
+
+
+
+
+
diff --git a/lib/OpenLayers/Control/ModifyFeature.js b/lib/OpenLayers/Control/ModifyFeature.js
index 8f46d3e1ec..5df3eb8066 100644
--- a/lib/OpenLayers/Control/ModifyFeature.js
+++ b/lib/OpenLayers/Control/ModifyFeature.js
@@ -86,7 +86,37 @@ OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, {
* {}
*/
virtualStyle: null,
+
+ /**
+ * APIProperty: rotate
+ * {Boolean} Allow rotation of feature instead of vertex modification.
+ */
+ rotate: false,
+
+ /**
+ * APIProperty: resize
+ * {Boolean} Allow resizing of feature instead of vertex modification.
+ */
+ resize: false,
+
+ /**
+ * Property: radiusHandle
+ * {} A handle for rotating/resizing a feature.
+ */
+ radiusHandle: null,
+
+ /**
+ * APIProperty: drag
+ * {Boolean} Allow dragging of feature with a drag handle.
+ */
+ drag: false,
+ /**
+ * Property: dragHandle
+ * {} A handle for dragging a feature.
+ */
+ dragHandle: null,
+
/**
* APIProperty: onModificationStart
* {Function} Optional function to be called when a feature is selected
@@ -250,9 +280,17 @@ OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, {
*/
unselectFeature: function(feature) {
this.layer.removeFeatures(this.vertices);
- this.layer.removeFeatures(this.virtualVertices);
this.vertices = [];
+ this.layer.destroyFeatures(this.virtualVertices);
this.virtualVertices = [];
+ if(this.dragHandle) {
+ this.layer.destroyFeatures([this.dragHandle]);
+ delete this.dragHandle;
+ }
+ if(this.radiusHandle) {
+ this.layer.destroyFeatures([this.radiusHandle]);
+ delete this.radiusHandle;
+ }
this.feature = null;
this.dragControl.deactivate();
this.onModificationEnd(feature);
@@ -274,9 +312,8 @@ OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, {
*/
dragStart: function(feature, pixel) {
// only change behavior if the feature is not in the vertices array
- if(feature != this.feature &&
- OpenLayers.Util.indexOf(this.vertices, feature) == -1 &&
- OpenLayers.Util.indexOf(this.virtualVertices, feature) == -1) {
+ if(feature != this.feature && !feature.geometry.parent &&
+ feature != this.dragHandle && feature != this.radiusHandle) {
if(this.feature) {
// unselect the currently selected feature
this.selectControl.clickFeature.apply(this.selectControl,
@@ -315,21 +352,41 @@ OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, {
* vertex - {} The vertex being dragged.
*/
dragVertex: function(vertex) {
+ /**
+ * Five cases:
+ * 1) dragging a simple point
+ * 2) dragging a virtual vertex
+ * 3) dragging a drag handle
+ * 4) dragging a radius handle
+ * 5) dragging a real vertex
+ */
if(this.feature.geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
+ // dragging a simple point
if(this.feature != vertex) {
this.feature = vertex;
}
} else {
- if(OpenLayers.Util.indexOf(this.virtualVertices, vertex) != -1) {
+ if(vertex._index) {
+ // dragging a virtual vertex
vertex.geometry.parent.addComponent(vertex.geometry,
vertex._index);
delete vertex._index;
OpenLayers.Util.removeItem(this.virtualVertices, vertex);
- this.layer.removeFeatures(vertex);
+ } else if(vertex == this.dragHandle) {
+ // dragging a drag handle
+ this.layer.removeFeatures(this.vertices);
+ this.vertices = [];
+ if(this.radiusHandle) {
+ this.layer.destroyFeatures([this.radiusHandle]);
+ this.radiusHandle = null;
+ }
}
+ // dragging a radius handle - no special treatment
+ // dragging a real vertex - no special treatment
+ this.layer.destroyFeatures(this.virtualVertices);
+ this.virtualVertices = [];
+ this.layer.drawFeature(this.feature, this.selectControl.selectStyle);
}
- this.layer.drawFeature(this.feature, this.selectControl.selectStyle);
- this.layer.removeFeatures(this.virtualVertices);
// keep the vertex on top so it gets the mouseout after dragging
// this should be removed in favor of an option to draw under or
// maintain node z-index
@@ -360,11 +417,24 @@ OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, {
this.layer.removeFeatures(this.virtualVertices);
this.virtualVertices = [];
}
+ if(this.dragHandle) {
+ this.layer.destroyFeatures([this.dragHandle]);
+ this.dragHandle = null;
+ }
+ if(this.radiusHandle) {
+ this.layer.destroyFeatures([this.radiusHandle]);
+ this.radiusHandle = null;
+ }
if(this.feature &&
this.feature.geometry.CLASS_NAME != "OpenLayers.Geometry.Point") {
- this.collectVertices(this.feature.geometry);
- this.layer.addFeatures(this.vertices);
- this.layer.addFeatures(this.virtualVertices);
+ if(this.drag) {
+ this.collectDragHandle();
+ }
+ if(this.rotate || this.resize) {
+ this.collectRadiusHandle();
+ } else {
+ this.collectVertices();
+ }
}
},
@@ -385,7 +455,8 @@ OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, {
var vertex = this.dragControl.feature;
if(vertex &&
OpenLayers.Util.indexOf(this.vertices, vertex) != -1 &&
- !this.dragControl.dragHandler.dragging) {
+ !this.dragControl.dragHandler.dragging &&
+ vertex.geometry.parent) {
// remove the vertex
vertex.geometry.parent.removeComponent(vertex.geometry);
this.layer.drawFeature(this.feature,
@@ -442,8 +513,69 @@ OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, {
}
}
}
- }
- collectComponentVertices(this.feature.geometry);
+ }
+ collectComponentVertices.call(this, this.feature.geometry);
+ this.layer.addFeatures(this.vertices);
+ this.layer.addFeatures(this.virtualVertices);
+ },
+
+ /**
+ * Method: collectDragHandle
+ * Collect the drag handle for the selected geometry.
+ */
+ collectDragHandle: function() {
+ var geometry = this.feature.geometry;
+ var center = geometry.getBounds().getCenterLonLat();
+ var originGeometry = new OpenLayers.Geometry.Point(
+ center.lon, center.lat
+ );
+ var origin = new OpenLayers.Feature.Vector(originGeometry);
+ originGeometry.move = function(x, y) {
+ OpenLayers.Geometry.Point.prototype.move.call(this, x, y);
+ geometry.move(x, y);
+ }
+ this.dragHandle = origin;
+ this.layer.addFeatures([this.dragHandle]);
+ },
+
+ /**
+ * Method: collectRadiusHandle
+ * Collect the radius handle for the selected geometry.
+ */
+ collectRadiusHandle: function() {
+ var geometry = this.feature.geometry;
+ var bounds = geometry.getBounds();
+ var center = bounds.getCenterLonLat();
+ var originGeometry = new OpenLayers.Geometry.Point(
+ center.lon, center.lat
+ );
+ var radiusGeometry = new OpenLayers.Geometry.Point(
+ bounds.right, bounds.bottom
+ );
+ var radius = new OpenLayers.Feature.Vector(radiusGeometry);
+ var resize = this.resize;
+ var rotate = this.rotate;
+ radiusGeometry.move = function(x, y) {
+ OpenLayers.Geometry.Point.prototype.move.call(this, x, y);
+ var dx1 = this.x - originGeometry.x;
+ var dy1 = this.y - originGeometry.y;
+ var dx0 = dx1 - x;
+ var dy0 = dy1 - y;
+ if(rotate) {
+ var a0 = Math.atan2(dy0, dx0);
+ var a1 = Math.atan2(dy1, dx1);
+ var angle = a1 - a0;
+ angle *= 180 / Math.PI;
+ geometry.rotate(angle, originGeometry);
+ }
+ if(resize) {
+ var l0 = Math.sqrt((dx0 * dx0) + (dy0 * dy0));
+ var l1 = Math.sqrt((dx1 * dx1) + (dy1 * dy1));
+ geometry.resize(l1 / l0, originGeometry);
+ }
+ }
+ this.radiusHandle = radius;
+ this.layer.addFeatures([this.radiusHandle]);
},
/**
diff --git a/lib/OpenLayers/Layer/Vector.js b/lib/OpenLayers/Layer/Vector.js
index 8c93d9e44f..12fe0778fd 100644
--- a/lib/OpenLayers/Layer/Vector.js
+++ b/lib/OpenLayers/Layer/Vector.js
@@ -307,12 +307,27 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
/**
* APIMethod: destroyFeatures
- * Destroy all features on the layer and empty the selected features array.
+ * Erase and estroy features on the layer.
+ *
+ * Parameters:
+ * features - {Array()} An optional array of
+ * features to destroy. If not supplied, all features on the layer
+ * will be destroyed.
*/
- destroyFeatures: function () {
- this.selectedFeatures = [];
- for (var i = this.features.length - 1; i >= 0; i--) {
- this.features[i].destroy();
+ destroyFeatures: function(features) {
+ var all = (features == undefined);
+ if(all) {
+ features = this.features;
+ this.selectedFeatures = [];
+ }
+ this.eraseFeatures(features);
+ var feature;
+ for(var i=features.length-1; i>=0; i--) {
+ feature = features[i];
+ if(!all) {
+ OpenLayers.Util.removeItem(this.selectedFeatures, feature);
+ }
+ feature.destroy();
}
},
diff --git a/tests/Control/test_ModifyFeature.html b/tests/Control/test_ModifyFeature.html
index 5f7ee9e262..4c55e5ea14 100644
--- a/tests/Control/test_ModifyFeature.html
+++ b/tests/Control/test_ModifyFeature.html
@@ -190,7 +190,10 @@
control.dragControl.deactivate = function() { t.ok(true, "Deactivate called on drag control"); }
control.onModificationEnd = function (feature) { t.eq(feature.id, fakeFeature.id, "onModificationEnd got feature.") }
layer.removeFeatures = function(verts) {
- t.ok(verts == 'a' || verts == 'b', "Verts removed correctly")
+ t.ok(verts == 'a', "Normal verts removed correctly");
+ }
+ layer.destroyFeatures = function(verts) {
+ t.ok(verts == 'b', "Virtual verts destroyed correctly");
}
control.unselectFeature(fakeFeature);
t.eq(control.feature, null, "feature is set to null");
@@ -214,9 +217,11 @@
control.selectFeature(fakeFeature);
control.collectVertices = function() {
+ t.ok(true, "collectVertices called");
this.vertices = 'a';
this.virtualVertices = 'd';
- t.ok(true, "collectVertices called");
+ layer.addFeatures(this.vertices);
+ layer.addFeatures(this.virtualVertices);
}
layer.addFeatures = function(features) {
@@ -242,7 +247,7 @@
}
function test_ModifyFeature_resetVertices(t) {
- t.plan(9);
+ t.plan(15);
var layer = new OpenLayers.Layer.Vector();
var control = new OpenLayers.Control.ModifyFeature(layer);
var point = new OpenLayers.Geometry.Point(5,6);
@@ -253,7 +258,7 @@
control.resetVertices();
t.eq(control.vertices.length, 0, "Correct vertices length");
t.eq(control.virtualVertices.length, 0, "Correct virtual vertices length.");
-
+
var multiPoint = new OpenLayers.Geometry.MultiPoint([point, point2]);
control.feature = new OpenLayers.Feature.Vector(multiPoint);
control.resetVertices();
@@ -273,6 +278,20 @@
t.eq(control.vertices[0].geometry.id, control.vertices[3].geometry.id, "First and last vertices are the same");
t.eq(control.virtualVertices.length, 3, "Correct virtual vertices length (polygon).");
+ control.drag = true;
+ control.resetVertices();
+ t.ok(control.dragHandle != null, "Drag handle is set");
+ t.eq(control.vertices.length, 4, "Correct vertices length with polygon (drag)");
+
+ control.rotate = true;
+ control.resetVertices();
+ t.ok(control.radiusHandle != null, "Radius handle is set");
+ t.eq(control.vertices.length, 0, "Correct vertices length with polygon (rotate)");
+
+ control.rotate = false;
+ control.resize = true;
+ t.ok(control.radiusHandle != null, "Radius handle is set");
+ t.eq(control.vertices.length, 0, "Correct vertices length with polygon (resize)");
}
function test_ModifyFeature_onDrag(t) {
@@ -289,11 +308,6 @@
'geometry': { 'id':'myGeom'},
'id': 'fakeFeature'
};
- control.collectVertices = function(geom) {
- t.eq(geom.id, 'myGeom', "collect geom called");
- this.vertices = 'normal';
- this.virtualVertices = 'virtual';
- }
layer.addFeatures = function (verts) {
t.ok(verts == 'virtual' || verts == 'normal', verts + " verts correct");
}
@@ -303,6 +317,13 @@
control.onModification = function(feat) {
t.eq(feat.id, fakeFeature.id, "onModification gets correct feat");
}
+ control.collectVertices = function() {
+ t.ok(true, "collectVertices called");
+ this.vertices = 'normal';
+ this.virtualVertices = 'virtual';
+ layer.addFeatures(this.vertices);
+ layer.addFeatures(this.virtualVertices);
+ }
control.feature = fakeFeature;
control.vertices = 'previous normal';
control.virtualVertices = 'previous virtual';
diff --git a/tests/Layer/test_Vector.html b/tests/Layer/test_Vector.html
index 3e1aab251d..87bc441a94 100644
--- a/tests/Layer/test_Vector.html
+++ b/tests/Layer/test_Vector.html
@@ -130,7 +130,7 @@
}
function test_Layer_Vector_destroyFeatures (t) {
- t.plan(3);
+ t.plan(5);
layer = new OpenLayers.Layer.Vector(name);
var map = new OpenLayers.Map('map');
map.addLayer(layer);
@@ -145,6 +145,17 @@
layer.destroyFeatures();
t.eq(layer.features.length, 0, "destroyFeatures triggers removal");
t.eq(layer.selectedFeatures, [], "Destroy features removes selected features");
+ features = [];
+ for (var i = 0; i < 5; i++) {
+ features.push(new OpenLayers.Feature.Vector(
+ new OpenLayers.Geometry.Point(0,0)));
+ }
+ layer.addFeatures(features);
+ layer.selectedFeatures.push(features[0]);
+ layer.selectedFeatures.push(features[1]);
+ layer.destroyFeatures([features[0], features[1]]);
+ t.eq(layer.features.length, 3, "destroyFeatures removes appropriate features");
+ t.eq(layer.selectedFeatures, [], "destroyFeatures removes appropriate selected features");
}
function test_99_Layer_Vector_destroy (t) {