Ticket #941: modify-features.patch
| File modify-features.patch, 41.0 kB (added by tschaub, 11 months ago) |
|---|
-
tests/Control/test_ModifyFeature.html
old new 1 <html> 2 <head> 3 <script src="../../lib/OpenLayers.js"></script> 4 <script type="text/javascript"> 5 6 function test_ModifyFeature_constructor(t) { 7 t.plan(2); 8 var layer = "foo"; 9 var options = { 10 geometryTypes: "bar" 11 }; 12 var control = new OpenLayers.Control.ModifyFeature(layer, options); 13 14 t.eq(control.layer, "foo", 15 "constructor sets layer correctly"); 16 t.eq(control.selectControl.geometryTypes, "bar", 17 "constructor sets options correctly on feature handler"); 18 } 19 20 function test_ModifyFeature_destroy(t) { 21 t.plan(2); 22 var map = new OpenLayers.Map("map"); 23 var layer = new OpenLayers.Layer.Vector(); 24 map.addLayer(layer); 25 var control = new OpenLayers.Control.ModifyFeature(layer); 26 control.selectControl.destroy = function() { 27 t.ok(true, 28 "control.destroy calls destroy on select control"); 29 } 30 control.dragControl.destroy = function() { 31 t.ok(true, 32 "control.destroy calls destroy on feature handler"); 33 } 34 control.destroy(); 35 } 36 37 function test_ModifyFeature_activate(t) { 38 t.plan(2); 39 var map = new OpenLayers.Map("map"); 40 var layer = new OpenLayers.Layer.Vector(); 41 map.addLayer(layer); 42 var control = new OpenLayers.Control.ModifyFeature(layer); 43 map.addControl(control); 44 t.ok(!control.selectControl.active, 45 "select control is not active prior to activating control"); 46 control.activate(); 47 t.ok(control.selectControl.active, 48 "select control is active after activating control"); 49 } 50 51 function test_ModifyFeature_initDeleteCodes(t) { 52 t.plan(3); 53 var layer = new OpenLayers.Layer.Vector(); 54 var control = new OpenLayers.Control.ModifyFeature(layer, {'deleteCodes': 46}); 55 t.eq(control.deleteCodes[0], 46, "Delete code properly turned into an array."); 56 var control = new OpenLayers.Control.ModifyFeature(layer); 57 t.eq(control.deleteCodes[0], 46, "Default deleteCodes include delete"); 58 t.eq(control.deleteCodes[1], 100, "Default deleteCodes include 'd'"); 59 60 } 61 62 function test_ModifyFeature_handleKeypress(t) { 63 t.plan(8); 64 65 /** 66 * There are two things that we want to test here 67 * 1) test that control.deleteCodes are respected 68 * 3) test that a vertex is properly deleted 69 * 70 * In the future, feature deletion may be added to the control. 71 */ 72 73 var control = new OpenLayers.Control.ModifyFeature({style: null}); 74 var delKey = 46; 75 var dKey = 100; 76 control.deleteCodes = [delKey, dKey]; 77 78 //// test that point is deleted for all delete codes 79 //var point = new OpenLayers.Feature.Vector( 80 // new OpenLayers.Geometry.Point() 81 //); 82 //// mock up deletion before dragging (but after selection) 83 //control.dragControl.feature = null; 84 //control.feature = point; 85 //var oldUnselect = control.unselectFeature; 86 //control.unselectFeature = function(feature) { 87 // t.eq(feature.id, point.id, 88 // "point deletion before drag: unselectFeature called with the correct feature"); 89 //}; 90 //control.layer = { 91 // removeFeatures: function(features) { 92 // t.ok(features.length == 1, 93 // "point deletion before drag: removeFeatures called with a single feature"); 94 // t.eq(features[0].id, point.id, 95 // "point deletion before drag: removeFeatures called with the correct feature"); 96 // } 97 //}; 98 //control.onDelete = function(feature) { 99 // t.eq(feature.id, point.id, 100 // "point deletion before drag: onDelete called with the correct feature"); 101 //}; 102 //// run the above four tests twice 103 //control.handleKeypress(delKey); 104 //control.handleKeypress(dKey); 105 //// reset modified methods 106 //control.unselectFeatures = oldUnselect; 107 //control.onDelete = function() {}; 108 // 109 //// mock up deletion during dragging - these repeat the above tests 110 //control.dragControl.feature = point; 111 //control.feature = point; 112 //var oldUnselect = control.unselectFeature; 113 //control.unselectFeature = function(feature) { 114 // t.eq(feature.id, point.id, 115 // "point deletion during drag: unselectFeature called with the correct feature"); 116 //}; 117 //control.layer = { 118 // removeFeatures: function(features) { 119 // t.ok(features.length == 1, 120 // "point deletion during drag: removeFeatures called with a single feature"); 121 // t.eq(features[0].id, point.id, 122 // "point deletion during drag: removeFeatures called with the correct feature"); 123 // } 124 //}; 125 //control.onDelete = function(feature) { 126 // t.eq(feature.id, point.id, 127 // "point deletion during drag: onDelete called with the correct feature"); 128 //}; 129 //// run the above four tests twice 130 //control.handleKeypress(delKey); 131 //control.handleKeypress(dKey); 132 //// reset modified methods 133 //control.unselectFeatures = oldUnselect; 134 //control.onDelete = function() {}; 135 136 // test that a polygon vertex is deleted for all delete codes 137 var point = new OpenLayers.Feature.Vector( 138 new OpenLayers.Geometry.Point() 139 ); 140 var poly = new OpenLayers.Feature.Vector( 141 new OpenLayers.Geometry.Polygon() 142 ); 143 144 // mock up vertex deletion 145 control.dragControl.feature = point; 146 control.feature = poly; 147 control.vertices = [point]; 148 point.geometry.parent = { 149 removeComponent: function(geometry) { 150 t.eq(geometry.id, point.geometry.id, 151 "vertex deletion: removeComponent called on parent with proper geometry"); 152 } 153 }; 154 control.layer = { 155 drawFeature: function(feature) { 156 t.eq(feature.id, poly.id, 157 "vertex deletion: drawFeature called with the proper feature"); 158 } 159 }; 160 var oldReset = control.resetVertices; 161 control.resetVertices = function() { 162 t.ok(true, "vertex deletion: resetVertices called"); 163 }; 164 control.onModification = function(feature) { 165 t.eq(feature.id, poly.id, 166 "vertex deletion: onModification called with the proper feature"); 167 }; 168 // run the above four tests twice 169 control.handleKeypress(delKey); 170 control.handleKeypress(dKey); 171 // reset modified methods 172 control.onModification = function() {}; 173 174 } 175 176 177 function test_ModifyFeature_onUnSelect(t) { 178 t.plan(5); 179 var layer = new OpenLayers.Layer.Vector(); 180 var control = new OpenLayers.Control.ModifyFeature(layer); 181 var fakeFeature = {'id':'myid'}; 182 control.vertices = 'a'; 183 control.virtualVertices = 'b'; 184 control.features = true; 185 control.dragControl.deactivate = function() { t.ok(true, "Deactivate called on drag control"); } 186 control.onModificationEnd = function (feature) { t.eq(feature.id, fakeFeature.id, "onModificationEnd got feature.") } 187 layer.removeFeatures = function(verts) { 188 t.ok(verts == 'a' || verts == 'b', "Verts removed correctly") 189 } 190 control.unselectFeature(fakeFeature); 191 t.eq(control.feature, null, "feature is set to null"); 192 } 193 function test_ModifyFeature_selectFeature(t) { 194 t.plan(12); 195 var layer = new OpenLayers.Layer.Vector(); 196 var control = new OpenLayers.Control.ModifyFeature(layer); 197 control.vertices = []; 198 control.virtualVertices = []; 199 control.dragControl.activate = function() { t.ok(true, "drag Control activated"); } 200 control.onModificationStart = function(feature) { t.eq(feature.id, fakeFeature.id, "On Modification Start called with correct feature."); } 201 202 203 // Start of testing 204 205 control.collectVertices = function() { t.fail("Collect vertices called when geom is a point"); } 206 var fakeFeature = {'id':'myFakeFeature','geometry':{'CLASS_NAME':'OpenLayers.Geometry.Point'}}; 207 208 // Points don't call collectVertices 209 control.selectFeature(fakeFeature); 210 211 control.collectVertices = function() { 212 this.vertices = 'a'; 213 this.virtualVertices = 'd'; 214 t.ok(true, "collectVertices called"); 215 } 216 217 layer.addFeatures = function(features) { 218 t.ok(features == 'a' || features == 'd', "features passed correctly"); 219 } 220 fakeFeature.geometry.CLASS_NAME='OpenLayers.Geometry.Polygon'; 221 222 // OnSelect calls collectVertices and passes features to layer 223 control.selectFeature(fakeFeature); 224 225 control.vertices = ['a']; 226 control.virtualVertices = ['b']; 227 228 layer.addFeatures = function(features) {} 229 230 layer.removeFeatures = function(features) { 231 t.eq(features.length, 1, "Correct feature length passed in"); 232 } 233 234 // Features are removed whenever they exist 235 control.selectFeature(fakeFeature); 236 237 } 238 239 function test_ModifyFeature_resetVertices(t) { 240 t.plan(9); 241 var layer = new OpenLayers.Layer.Vector(); 242 var control = new OpenLayers.Control.ModifyFeature(layer); 243 var point = new OpenLayers.Geometry.Point(5,6); 244 var point2 = new OpenLayers.Geometry.Point(7,8); 245 var point3 = new OpenLayers.Geometry.Point(9,10); 246 247 control.feature = new OpenLayers.Feature.Vector(point); 248 control.resetVertices(); 249 t.eq(control.vertices.length, 0, "Correct vertices length"); 250 t.eq(control.virtualVertices.length, 0, "Correct virtual vertices length."); 251 252 var multiPoint = new OpenLayers.Geometry.MultiPoint([point, point2]); 253 control.feature = new OpenLayers.Feature.Vector(multiPoint); 254 control.resetVertices(); 255 t.eq(control.vertices.length, 2, "Correct vertices length with multipoint"); 256 t.eq(control.virtualVertices.length, 0, "Correct virtual vertices length (multipoint)."); 257 258 var line = new OpenLayers.Geometry.LineString([point, point2]); 259 control.feature = new OpenLayers.Feature.Vector(line); 260 control.resetVertices(); 261 t.eq(control.vertices.length, 2, "Correct vertices length with line"); 262 t.eq(control.virtualVertices.length, 1, "Correct virtual vertices length (linestring)."); 263 264 var polygon = new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing([point, point2, point3])]); 265 control.feature = new OpenLayers.Feature.Vector(polygon); 266 control.resetVertices(); 267 t.eq(control.vertices.length, 4, "Correct vertices length with polygon"); 268 t.eq(control.vertices[0].geometry.id, control.vertices[3].geometry.id, "First and last vertices are the same"); 269 t.eq(control.virtualVertices.length, 3, "Correct virtual vertices length (polygon)."); 270 271 } 272 273 function test_ModifyFeature_onDrag(t) { 274 t.plan(1); 275 t.ok(true, "onDrag not tested yet."); 276 } 277 278 function test_ModifyFeature_dragComplete(t) { 279 t.plan(6); 280 var layer = new OpenLayers.Layer.Vector(); 281 var control = new OpenLayers.Control.ModifyFeature(layer); 282 283 var fakeFeature = { 284 'geometry': { 'id':'myGeom'}, 285 'id': 'fakeFeature' 286 }; 287 control.collectVertices = function(geom) { 288 t.eq(geom.id, 'myGeom', "collect geom called"); 289 this.vertices = 'normal'; 290 this.virtualVertices = 'virtual'; 291 } 292 layer.addFeatures = function (verts) { 293 t.ok(verts == 'virtual' || verts == 'normal', verts + " verts correct"); 294 } 295 layer.removeFeatures = function (verts) { 296 t.ok(verts == 'previous virtual' || verts == 'previous normal', verts + " verts correct"); 297 } 298 control.onModification = function(feat) { 299 t.eq(feat.id, fakeFeature.id, "onModification gets correct feat"); 300 } 301 control.feature = fakeFeature; 302 control.vertices = 'previous normal'; 303 control.virtualVertices = 'previous virtual'; 304 control.dragComplete(); 305 } 306 307 function test_ModifyFeature_deactivate(t) { 308 t.plan(2); 309 var map = new OpenLayers.Map("map"); 310 var layer = new OpenLayers.Layer.Vector(); 311 map.addLayer(layer); 312 var control = new OpenLayers.Control.ModifyFeature(layer); 313 map.addControl(control); 314 315 control.selectControl.deactivate = function() { 316 t.ok(true, 317 "control.deactivate calls deactivate on select control"); 318 } 319 control.dragControl.deactivate = function() { 320 t.ok(true, 321 "control.deactivate calls deactivate on drag control"); 322 } 323 control.active = true; 324 control.deactivate(); 325 } 326 327 function test_ModifyFeature_onModificationStart(t) { 328 t.plan(1); 329 var map = new OpenLayers.Map("map"); 330 var layer = new OpenLayers.Layer.Vector(); 331 map.addLayer(layer); 332 var control = new OpenLayers.Control.ModifyFeature(layer); 333 map.addControl(control); 334 control.activate(); 335 336 // make sure onModificationStart is called on feature selection 337 var testFeature = new OpenLayers.Feature.Vector( 338 new OpenLayers.Geometry.Point(Math.random(), Math.random()) 339 ); 340 control.onModificationStart = function(feature) { 341 t.eq(feature.id, testFeature.id, 342 "onModificationStart called with the right feature"); 343 }; 344 control.selectFeature(testFeature); 345 } 346 347 function test_ModifyFeature_onModification(t) { 348 t.plan(2); 349 var map = new OpenLayers.Map("map"); 350 var layer = new OpenLayers.Layer.Vector(); 351 map.addLayer(layer); 352 var control = new OpenLayers.Control.ModifyFeature(layer); 353 map.addControl(control); 354 control.activate(); 355 356 // make sure onModification is called on drag complete 357 var point = new OpenLayers.Feature.Vector( 358 new OpenLayers.Geometry.Point(Math.random(), Math.random()) 359 ); 360 control.feature = point; 361 control.onModification = function(feature) { 362 t.eq(feature.id, point.id, 363 "onModification called with the right feature on drag complete"); 364 }; 365 control.dragComplete(); 366 367 // make sure onModification is called on vertex deletion 368 var poly = new OpenLayers.Feature.Vector( 369 new OpenLayers.Geometry.Polygon() 370 ); 371 var oldDraw = layer.drawFeature; 372 layer.drawFeature = function() { 373 return; 374 }; 375 control.feature = poly; 376 control.vertices = [point]; 377 control.onModification = function(feature) { 378 t.eq(feature.id, poly.id, 379 "onModification called with the right feature on vertex delete"); 380 }; 381 point.geometry.parent = poly.geometry; 382 control.dragControl.feature = point; 383 control.handleKeypress(46); 384 layer.drawFeature = oldDraw; 385 386 } 387 388 function test_ModifyFeature_onModificationEnd(t) { 389 t.plan(1); 390 var map = new OpenLayers.Map("map"); 391 var layer = new OpenLayers.Layer.Vector(); 392 map.addLayer(layer); 393 var control = new OpenLayers.Control.ModifyFeature(layer); 394 map.addControl(control); 395 control.activate(); 396 397 // make sure onModificationEnd is called on unselect feature 398 var testFeature = new OpenLayers.Feature.Vector( 399 new OpenLayers.Geometry.Point(Math.random(), Math.random()) 400 ); 401 control.onModificationEnd = function(feature) { 402 t.eq(feature.id, testFeature.id, 403 "onModificationEnd called with the right feature"); 404 }; 405 control.unselectFeature(testFeature); 406 } 407 408 409 //function t//est_ModifyFeature_onDelete(t) { 410 // t.plan(2); 411 // var map = new OpenLayers.Map("map"); 412 // var layer = new OpenLayers.Layer.Vector(); 413 // map.addLayer(layer); 414 // var control = new OpenLayers.Control.ModifyFeature(layer); 415 // map.addControl(control); 416 // control.activate(); 417 // 418 // // make sure onDelete is called on point deletion (before dragging) 419 // var point = new OpenLayers.Feature.Vector( 420 // new OpenLayers.Geometry.Point(Math.random(), Math.random()) 421 // ); 422 // control.feature = point; 423 // control.onDelete = function(feature) { 424 // t.eq(feature.id, point.id, 425 // "onDelete called with the right feature before drag"); 426 // }; 427 // control.handleKeypress(46); 428 // 429 // // make sure onDelete is called on point deletion (during dragging) 430 // var point = new OpenLayers.Feature.Vector( 431 // new OpenLayers.Geometry.Point(Math.random(), Math.random()) 432 // ); 433 // control.dragControl.feature = point; 434 // control.feature = point; 435 // control.onDelete = function(feature) { 436 // t.eq(feature.id, point.id, 437 // "onDelete called with the right feature during drag"); 438 // }; 439 // control.handleKeypress(46); 440 // 441 //} 442 443 </script> 444 </head> 445 <body> 446 <div id="map" style="width: 400px; height: 250px;"/> 447 </body> 448 </html> -
tests/list-tests.html
old new 66 66 <li>Control/test_Attribution.html</li> 67 67 <li>Control/test_SelectFeature.html</li> 68 68 <li>Control/test_DragFeature.html</li> 69 <li>Control/test_ModifyFeature.html</li> 69 70 <li>Control/test_DragPan.html</li> 70 71 <li>Control/test_OverviewMap.html</li> 71 72 <li>Control/test_NavToolbar.html</li> -
lib/OpenLayers/Control/ModifyFeature.js
old new 1 /* Copyright (c) 2006 MetaCarta, Inc., published under a modified BSD license. 2 * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 3 * for the full text of the license. */ 4 5 6 /** 7 * @requires OpenLayers/Control/DragFeature.js 8 * @requires OpenLayers/Control/SelectFeature.js 9 * @requires OpenLayers/Handler/Keyboard.js 10 * 11 * Class: OpenLayers.Control.ModifyFeature 12 * Control to modify features. When activated, a click renders the vertices 13 * of a feature - these vertices can then be dragged. By default, the 14 * delete key will delete the vertex under the mouse. New features are 15 * added by dragging "virtual vertices" between vertices. Create a new 16 * control with the <OpenLayers.Control.ModifyFeature> constructor. 17 * 18 * Inherits From: 19 * - <OpenLayers.Control> 20 */ 21 OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, { 22 23 /** 24 * APIProperty: geometryTypes 25 * {Array(String)} To restrict modification to a limited set of geometry 26 * types, send a list of strings corresponding to the geometry class 27 * names. 28 */ 29 geometryTypes: null, 30 31 /** 32 * Property: layer 33 * {OpenLayers.Layer.Vector} 34 */ 35 layer: null, 36 37 /** 38 * Property: feature 39 * {<OpenLayers.Feature.Vector>} Feature currently available for modification. 40 */ 41 feature: null, 42 43 /** 44 * Property: vertices 45 * {Array(<OpenLayers.Feature.Vector>)} Verticies currently available 46 * for dragging. 47 */ 48 vertices: null, 49 50 /** 51 * Property: virtualVertices 52 * {Array(<OpenLayers.Feature.Vector>)} Virtual vertices in the middle 53 * of each edge. 54 */ 55 virtualVertices: null, 56 57 /** 58 * Property: selectControl 59 * {<OpenLayers.Control.Select>} 60 */ 61 selectControl: null, 62 63 /** 64 * Property: dragControl 65 * {<OpenLayers.Control.DragFeature>} 66 */ 67 dragControl: null, 68 69 /** 70 * Property: keyboardHandler 71 * {<OpenLayers.Handler.Keyboard>} 72 */ 73 keyboardHandler: null, 74 75 /** 76 * APIProperty: deleteCodes 77 * {Array(Integer)} Keycodes for deleting verticies. Set to null to disable 78 * vertex deltion by keypress. If non-null, keypresses with codes 79 * in this array will delete vertices under the mouse. Default 80 * is 46 and 100, the 'delete' and lowercase 'd' keys. 81 */ 82 deleteCodes: null, 83 84 /** 85 * APIProperty: virtualStyle 86 * {<OpenLayers.Feature.Vector.Style>} 87 */ 88 virtualStyle: null, 89 90 /** 91 * APIProperty: onModificationStart 92 * {Function} Optional function to be called when a feature is selected 93 * to be modified. The function should expect to be called with a 94 * feature. This could be used for example to allow to lock the 95 * feature on server-side. 96 */ 97 onModificationStart: function() {}, 98 99 /** 100 * APIProperty: onModification 101 * {Function} Optional function to be called when a feature has been 102 * modified. The function should expect to be called with a feature. 103 */ 104 onModification: function() {}, 105 106 /** 107 * APIProperty: onModificationEnd 108 * {Function} Optional function to be called when a feature is finished 109 * being modified. The function should expect to be called with a 110 * feature. 111 */ 112 onModificationEnd: function() {}, 113 114 /** 115 * Constructor: OpenLayers.Control.ModifyFeature 116 * Create a new modify feature control. 117 * 118 * Parameters: 119 * layer - {OpenLayers.Layer.Vector} Layer that contains features that 120 * will be modified. 121 * options - {Object} Optional object whose properties will be set on the 122 * control. 123 */ 124 initialize: function(layer, options) { 125 this.layer = layer; 126 this.vertices = []; 127 this.virtualVertices = []; 128 this.styleVirtual = OpenLayers.Util.extend({}, this.layer.style); 129 this.styleVirtual.fillOpacity = 0.3; 130 this.styleVirtual.strokeOpacity = 0.3; 131 this.deleteCodes = [46, 100]; 132 OpenLayers.Control.prototype.initialize.apply(this, [options]); 133 if(!(this.deleteCodes instanceof Array)) { 134 this.deleteCodes = [this.deleteCodes]; 135 } 136 var control = this; 137 138 // configure the select control 139 var selectOptions = { 140 geometryTypes: this.geometryTypes, 141 onSelect: function(feature) { 142 control.selectFeature.apply(control, [feature]); 143 }, 144 onUnselect: function(feature) { 145 control.unselectFeature.apply(control, [feature]); 146 } 147 }; 148 this.selectControl = new OpenLayers.Control.SelectFeature( 149 layer, selectOptions 150 ); 151 152 // configure the drag control 153 var dragOptions = { 154 geometryTypes: ["OpenLayers.Geometry.Point"], 155 snappingOptions: this.snappingOptions, 156 onStart: function(feature, pixel) { 157 control.dragStart.apply(control, [feature, pixel]); 158 }, 159 onDrag: function(feature) { 160 control.dragVertex.apply(control, [feature]); 161 }, 162 onComplete: function(feature) { 163 control.dragComplete.apply(control, [feature]); 164 } 165 }; 166 this.dragControl = new OpenLayers.Control.DragFeature( 167 layer, dragOptions 168 ); 169 170 // configure the keyboard handler 171 var keyboardOptions = { 172 keypress: this.handleKeypress 173 }; 174 this.keyboardHandler = new OpenLayers.Handler.Keyboard( 175 this, keyboardOptions 176 ); 177 }, 178 179 /** 180 * APIMethod: destroy 181 * Take care of things that are not handled in superclass. 182 */ 183 destroy: function() { 184 this.layer = null; 185 this.selectControl.destroy(); 186 this.dragControl.destroy(); 187 this.keyboardHandler.destroy(); 188 OpenLayers.Control.prototype.destroy.apply(this, []); 189 }, 190 191 /** 192 * APIMethod: activate 193 * Activate the control and the feature handler. 194 * 195 * Returns: 196 * {Boolean} Successfully activated the control and feature handler. 197 */ 198 activate: function() { 199 return (this.selectControl.activate() && 200 this.keyboardHandler.activate() && 201 OpenLayers.Control.prototype.activate.apply(this, arguments)); 202 }, 203 204 /** 205 * APIMethod: deactivate 206 * Deactivate the controls. 207 * 208 * Returns: 209 * {Boolean} Successfully deactivated the control. 210 */ 211 deactivate: function() { 212 var deactivated = false; 213 // the return from the controls is unimportant in this case 214 if(OpenLayers.Control.prototype.deactivate.apply(this, arguments)) { 215 this.layer.removeFeatures(this.vertices); 216 this.layer.removeFeatures(this.virtualVertices); 217 this.vertices = []; 218 this.dragControl.deactivate(); 219 if(this.feature) { 220 this.selectControl.unselect.apply(this.selectControl, 221 [this.feature]); 222 } 223 this.selectControl.deactivate(); 224 this.keyboardHandler.deactivate(); 225 deactivated = true; 226 } 227 return deactivated; 228 }, 229 230 /** 231 * Method: selectFeature 232 * Called when the select feature control selects a feature. 233 * 234 * Parameters: 235 * feature - {<OpenLayers.Feature.Vector>} The selected feature. 236 */ 237 selectFeature: function(feature) { 238 this.feature = feature; 239 this.resetVertices(); 240 this.dragControl.activate(); 241 this.onModificationStart(this.feature); 242 }, 243 244 /** 245 * Method: unselectFeature 246 * Called when the select feature control unselects a feature. 247 * 248 * Parameters: 249 * feature - {<OpenLayers.Feature.Vector>} The unselected feature. 250 */ 251 unselectFeature: function(feature) { 252 this.layer.removeFeatures(this.vertices); 253 this.layer.removeFeatures(this.virtualVertices); 254 this.vertices = []; 255 this.virtualVertices = []; 256 this.feature = null; 257 this.dragControl.deactivate(); 258 this.onModificationEnd(feature); 259 }, 260 261 /** 262 * Method: dragStart 263 * Called by the drag feature control with before a feature is dragged. 264 * This method is used to differentiate between points and vertices 265 * of higher order geometries. This respects the <geometryTypes> 266 * property and forces a select of points when the drag control is 267 * already active (and stops events from propagating to the select 268 * control). 269 * 270 * Parameters: 271 * feature - {<OpenLayers.Feature.Vector>} The point or vertex about to be 272 * dragged. 273 * pixel - {<OpenLayers.Pixel>} Pixel location of the mouse event. 274 */ 275 dragStart: function(feature, pixel) { 276 // only change behavior if the feature is not in the vertices array 277 if(feature != this.feature && 278 OpenLayers.Util.indexOf(this.vertices, feature) == -1 && 279 OpenLayers.Util.indexOf(this.virtualVertices, feature) == -1) { 280 if(this.feature) { 281 // unselect the currently selected feature 282 this.selectControl.clickFeature.apply(this.selectControl, 283 [this.feature]); 284 } 285 // check any constraints on the geometry type 286 if(this.geometryTypes == null || 287 OpenLayers.Util.indexOf(this.geometryTypes, 288 feature.geometry.CLASS_NAME) != -1) { 289 // select the point 290 this.selectControl.clickFeature.apply(this.selectControl, 291 [feature]); 292 /** 293 * TBD: These lines improve workflow by letting the user 294 * immediately start dragging after the mouse down. 295 * However, it is very ugly to be messing with controls 296 * and their handlers in this way. I'd like a better 297 * solution if the workflow change is necessary. 298 */ 299 // prepare the point for dragging 300 this.dragControl.overFeature.apply(this.dragControl, 301 [feature]); 302 this.dragControl.lastPixel = pixel; 303 this.dragControl.dragHandler.started = true; 304 this.dragControl.dragHandler.start = pixel; 305 this.dragControl.dragHandler.last = pixel; 306 } 307 } 308 }, 309 310 /** 311 * Method: dragVertex 312 * Called by the drag feature control with each drag move of a vertex. 313 * 314 * Parameters: 315 * vertex - {<OpenLayers.Feature.Vector>} The vertex being dragged. 316 */ 317 dragVertex: function(vertex) { 318 if(this.feature.geometry.CLASS_NAME == "OpenLayers.Geometry.Point") { 319 if(this.feature != vertex) { 320 this.feature = vertex; 321 } 322 } else { 323 if(OpenLayers.Util.indexOf(this.virtualVertices, vertex) != -1) { 324 vertex.geometry.parent.addComponent(vertex.geometry, 325 vertex._index); 326 delete vertex._index; 327 OpenLayers.Util.removeItem(this.virtualVertices, vertex); 328 this.layer.removeFeatures(vertex); 329 } 330 } 331 this.layer.drawFeature(this.feature, this.selectControl.selectStyle); 332 this.layer.removeFeatures(this.virtualVertices); 333 // keep the vertex on top so it gets the mouseout after dragging 334 // this should be removed in favor of an option to draw under or 335 // maintain node z-index 336 this.layer.drawFeature(vertex); 337 }, 338 339 /** 340 * Method: dragComplete 341 * Called by the drag feature control when the feature dragging is complete. 342 * 343 * Parameters: 344 * vertex - {<OpenLayers.Feature.Vector>} The vertex being dragged. 345 */ 346 dragComplete: function(vertex) { 347 this.resetVertices(); 348 this.onModification(this.feature); 349 }, 350 351 /** 352 * Method: resetVertices 353 */ 354 resetVertices: function() { 355 if(this.vertices.length > 0) { 356 this.layer.removeFeatures(this.vertices); 357 this.vertices = []; 358 } 359 if(this.virtualVertices.length > 0) { 360 this.layer.removeFeatures(this.virtualVertices); 361 this.virtualVertices = []; 362 } 363 if(this.feature && 364 this.feature.geometry.CLASS_NAME != "OpenLayers.Geometry.Point") { 365 this.collectVertices(this.feature.geometry); 366 this.layer.addFeatures(this.vertices); 367 this.layer.addFeatures(this.virtualVertices); 368 } 369 }, 370 371 /** 372 * Method: handleKeypress 373 * Called by the feature handler on keypress. This is used to delete 374 * vertices and point features. If the <deleteCode> property is set, 375 * vertices and points will be deleted when a feature is selected 376 * for modification and the mouse is over a vertex. 377 * 378 * Parameters: 379 * {Integer} Key code corresponding to the keypress event. 380 */ 381 handleKeypress: function(code) { 382 // check for delete key 383 if(this.feature && 384 OpenLayers.Util.indexOf(this.deleteCodes, code) != -1) { 385 var vertex = this.dragControl.feature; 386 if(vertex && 387 OpenLayers.Util.indexOf(this.vertices, vertex) != -1) { 388 // remove the vertex 389 vertex.geometry.parent.removeComponent(vertex.geometry); 390 this.layer.drawFeature(this.feature, 391 this.selectControl.selectStyle); 392 this.resetVertices(); 393 this.onModification(this.feature); 394 } 395 } 396 }, 397 398 /** 399 * Method: collectVertices 400 * Collect the vertices from the modifiable feature's geometry and push 401 * them on to the control's vertices array. 402 */ 403 collectVertices: function() { 404 this.vertices = []; 405 this.virtualVirtices = []; 406 var control = this; 407 function collectComponentVertices(geometry) { 408 var i, vertex, component; 409 if(geometry.CLASS_NAME == "OpenLayers.Geometry.Point") { 410 vertex = new OpenLayers.Feature.Vector(geometry); 411 control.vertices.push(vertex); 412 } else { 413 for(i=0; i<geometry.components.length; ++i) { 414 component = geometry.components[i]; 415 if(component.CLASS_NAME == "OpenLayers.Geometry.Point") { 416 vertex = new OpenLayers.Feature.Vector(component); 417 control.vertices.push(vertex); 418 } else { 419 collectComponentVertices(component); 420 } 421 } 422 423 // add virtual vertices in the middle of each edge 424 if(geometry.CLASS_NAME != "OpenLayers.Geometry.MultiPoint") { 425 for(i=0; i<geometry.components.length-1; ++i) { 426 var prevVertex = geometry.components[i]; 427 var nextVertex = geometry.components[i + 1]; 428 if(prevVertex.CLASS_NAME == "OpenLayers.Geometry.Point" && 429 nextVertex.CLASS_NAME == "OpenLayers.Geometry.Point") { 430 var x = (prevVertex.x + nextVertex.x) / 2; 431 var y = (prevVertex.y + nextVertex.y) / 2; 432 var point = new OpenLayers.Feature.Vector( 433 new OpenLayers.Geometry.Point(x, y), 434 null, control.styleVirtual 435 ); 436 // set the virtual parent and intended index 437 point.geometry.parent = geometry; 438 point._index = i + 1; 439 control.virtualVertices.push(point); 440 } 441 } 442 } 443 } 444 } 445 collectComponentVertices(this.feature.geometry); 446 }, 447 448 /** 449 * Method: setMap 450 * Set the map property for the control and all handlers. 451 * 452 * Parameters: 453 * map - {OpenLayers.Map} The control's map. 454 */ 455 setMap: function(map) { 456 this.selectControl.setMap(map); 457 this.dragControl.setMap(map); 458 OpenLayers.Control.prototype.setMap.apply(this, arguments); 459 }, 460 461 CLASS_NAME: "OpenLayers.Control.ModifyFeature" 462 }); -
lib/OpenLayers.js
old new 142 142 "OpenLayers/Control/LayerSwitcher.js", 143 143 "OpenLayers/Control/DrawFeature.js", 144 144 "OpenLayers/Control/DragFeature.js", 145 "OpenLayers/Control/ModifyFeature.js", 145 146 "OpenLayers/Control/Panel.js", 146 147 "OpenLayers/Control/SelectFeature.js", 147 148 "OpenLayers/Geometry.js", -
examples/modify-feature.html
old new 1 <html xmlns="http://www.w3.org/1999/xhtml"> 2 <head> 3 <title>Modify Feature</title> 4 <style type="text/css"> 5 #map { 6 width: 512px; 7 height: 350px; 8 border: 1px solid gray; 9 } 10 #controls { 11 width: 512px; 12 } 13 #controlToggle { 14 padding-left: 1em; 15 } 16 #controlToggle li { 17 list-style: none; 18 } 19 </style> 20 <script src="../lib/Firebug/firebug.js"></script> 21 <script src="../lib/OpenLayers.js"></script> 22 <script type="text/javascript"> 23 var map, vectors, controls; 24 function init(){ 25 map = new OpenLayers.Map('map'); 26 var wms = new OpenLayers.Layer.WMS( "OpenLayers WMS", 27
