]> dev.renevier.net Git - syp.git/blob - openlayers/lib/OpenLayers/Control/ModifyFeature.js
initial commit
[syp.git] / openlayers / lib / OpenLayers / Control / ModifyFeature.js
1 /* Copyright (c) 2006 MetaCarta, Inc., published under the Clear BSD license.
2  * See http://svn.openlayers.org/trunk/openlayers/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
12 /**
13  * Class: OpenLayers.Control.ModifyFeature
14  * Control to modify features.  When activated, a click renders the vertices
15  *     of a feature - these vertices can then be dragged.  By default, the
16  *     delete key will delete the vertex under the mouse.  New features are
17  *     added by dragging "virtual vertices" between vertices.  Create a new
18  *     control with the <OpenLayers.Control.ModifyFeature> constructor.
19  *
20  * Inherits From:
21  *  - <OpenLayers.Control>
22  */
23 OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, {
24
25     /**
26      * APIProperty: geometryTypes
27      * {Array(String)} To restrict modification to a limited set of geometry
28      *     types, send a list of strings corresponding to the geometry class
29      *     names.
30      */
31     geometryTypes: null,
32
33     /**
34      * APIProperty: clickout
35      * {Boolean} Unselect features when clicking outside any feature.
36      *     Default is true.
37      */
38     clickout: true,
39
40     /**
41      * APIProperty: toggle
42      * {Boolean} Unselect a selected feature on click.
43      *      Default is true.
44      */
45     toggle: true,
46
47     /**
48      * Property: layer
49      * {<OpenLayers.Layer.Vector>}
50      */
51     layer: null,
52     
53     /**
54      * Property: feature
55      * {<OpenLayers.Feature.Vector>} Feature currently available for modification.
56      */
57     feature: null,
58     
59     /**
60      * Property: vertices
61      * {Array(<OpenLayers.Feature.Vector>)} Verticies currently available
62      *     for dragging.
63      */
64     vertices: null,
65     
66     /**
67      * Property: virtualVertices
68      * {Array(<OpenLayers.Feature.Vector>)} Virtual vertices in the middle
69      *     of each edge.
70      */
71     virtualVertices: null,
72
73     /**
74      * Property: selectControl
75      * {<OpenLayers.Control.SelectFeature>}
76      */
77     selectControl: null,
78     
79     /**
80      * Property: dragControl
81      * {<OpenLayers.Control.DragFeature>}
82      */
83     dragControl: null,
84     
85     /**
86      * Property: handlers
87      * {Object}
88      */
89     handlers: null,
90     
91     /**
92      * APIProperty: deleteCodes
93      * {Array(Integer)} Keycodes for deleting verticies.  Set to null to disable
94      *     vertex deltion by keypress.  If non-null, keypresses with codes
95      *     in this array will delete vertices under the mouse. Default
96      *     is 46 and 68, the 'delete' and lowercase 'd' keys.
97      */
98     deleteCodes: null,
99
100     /**
101      * APIProperty: virtualStyle
102      * {Object} A symbolizer to be used for virtual vertices.
103      */
104     virtualStyle: null,
105
106     /**
107      * APIProperty: mode
108      * {Integer} Bitfields specifying the modification mode. Defaults to
109      *      OpenLayers.Control.ModifyFeature.RESHAPE. To set the mode to a
110      *      combination of options, use the | operator. or example, to allow
111      *      the control to both resize and rotate features, use the following
112      *      syntax
113      * (code)
114      * control.mode = OpenLayers.Control.ModifyFeature.RESIZE |
115      *                OpenLayers.Control.ModifyFeature.ROTATE;
116      *  (end)
117      */
118     mode: null,
119
120     /**
121      * Property: modified
122      * {Boolean} The currently selected feature has been modified.
123      */
124     modified: false,
125
126     /**
127      * Property: radiusHandle
128      * {<OpenLayers.Feature.Vector>} A handle for rotating/resizing a feature.
129      */
130     radiusHandle: null,
131
132     /**
133      * Property: dragHandle
134      * {<OpenLayers.Feature.Vector>} A handle for dragging a feature.
135      */
136     dragHandle: null,
137
138     /**
139      * APIProperty: onModificationStart 
140      * {Function} *Deprecated*.  Register for "beforefeaturemodified" instead.
141      *     The "beforefeaturemodified" event is triggered on the layer before
142      *     any modification begins.
143      *
144      * Optional function to be called when a feature is selected
145      *     to be modified. The function should expect to be called with a
146      *     feature.  This could be used for example to allow to lock the
147      *     feature on server-side.
148      */
149     onModificationStart: function() {},
150
151     /**
152      * APIProperty: onModification
153      * {Function} *Deprecated*.  Register for "featuremodified" instead.
154      *     The "featuremodified" event is triggered on the layer with each
155      *     feature modification.
156      *
157      * Optional function to be called when a feature has been
158      *     modified.  The function should expect to be called with a feature.
159      */
160     onModification: function() {},
161
162     /**
163      * APIProperty: onModificationEnd
164      * {Function} *Deprecated*.  Register for "afterfeaturemodified" instead.
165      *     The "afterfeaturemodified" event is triggered on the layer after
166      *     a feature has been modified.
167      *
168      * Optional function to be called when a feature is finished 
169      *     being modified.  The function should expect to be called with a
170      *     feature.
171      */
172     onModificationEnd: function() {},
173
174     /**
175      * Constructor: OpenLayers.Control.ModifyFeature
176      * Create a new modify feature control.
177      *
178      * Parameters:
179      * layer - {<OpenLayers.Layer.Vector>} Layer that contains features that
180      *     will be modified.
181      * options - {Object} Optional object whose properties will be set on the
182      *     control.
183      */
184     initialize: function(layer, options) {
185         this.layer = layer;
186         this.vertices = [];
187         this.virtualVertices = [];
188         this.virtualStyle = OpenLayers.Util.extend({},
189             this.layer.style || this.layer.styleMap.createSymbolizer());
190         this.virtualStyle.fillOpacity = 0.3;
191         this.virtualStyle.strokeOpacity = 0.3;
192         this.deleteCodes = [46, 68];
193         this.mode = OpenLayers.Control.ModifyFeature.RESHAPE;
194         OpenLayers.Control.prototype.initialize.apply(this, [options]);
195         if(!(this.deleteCodes instanceof Array)) {
196             this.deleteCodes = [this.deleteCodes];
197         }
198         var control = this;
199
200         // configure the select control
201         var selectOptions = {
202             geometryTypes: this.geometryTypes,
203             clickout: this.clickout,
204             toggle: this.toggle,
205             onBeforeSelect: this.beforeSelectFeature,
206             onSelect: this.selectFeature,
207             onUnselect: this.unselectFeature,
208             scope: this
209         };
210         this.selectControl = new OpenLayers.Control.SelectFeature(
211             layer, selectOptions
212         );
213
214         // configure the drag control
215         var dragOptions = {
216             geometryTypes: ["OpenLayers.Geometry.Point"],
217             snappingOptions: this.snappingOptions,
218             onStart: function(feature, pixel) {
219                 control.dragStart.apply(control, [feature, pixel]);
220             },
221             onDrag: function(feature, pixel) {
222                 control.dragVertex.apply(control, [feature, pixel]);
223             },
224             onComplete: function(feature) {
225                 control.dragComplete.apply(control, [feature]);
226             }
227         };
228         this.dragControl = new OpenLayers.Control.DragFeature(
229             layer, dragOptions
230         );
231
232         // configure the keyboard handler
233         var keyboardOptions = {
234             keydown: this.handleKeypress
235         };
236         this.handlers = {
237             keyboard: new OpenLayers.Handler.Keyboard(this, keyboardOptions)
238         };
239     },
240
241     /**
242      * APIMethod: destroy
243      * Take care of things that are not handled in superclass.
244      */
245     destroy: function() {
246         this.layer = null;
247         this.selectControl.destroy();
248         this.dragControl.destroy();
249         OpenLayers.Control.prototype.destroy.apply(this, []);
250     },
251
252     /**
253      * APIMethod: activate
254      * Activate the control.
255      * 
256      * Returns:
257      * {Boolean} Successfully activated the control.
258      */
259     activate: function() {
260         return (this.selectControl.activate() &&
261                 this.handlers.keyboard.activate() &&
262                 OpenLayers.Control.prototype.activate.apply(this, arguments));
263     },
264
265     /**
266      * APIMethod: deactivate
267      * Deactivate the control.
268      *
269      * Returns: 
270      * {Boolean} Successfully deactivated the control.
271      */
272     deactivate: function() {
273         var deactivated = false;
274         // the return from the controls is unimportant in this case
275         if(OpenLayers.Control.prototype.deactivate.apply(this, arguments)) {
276             this.layer.removeFeatures(this.vertices, {silent: true});
277             this.layer.removeFeatures(this.virtualVertices, {silent: true});
278             this.vertices = [];
279             this.dragControl.deactivate();
280             if(this.feature && this.feature.geometry && this.feature.layer) {
281                 this.selectControl.unselect.apply(this.selectControl,
282                                                   [this.feature]);
283             }
284             this.selectControl.deactivate();
285             this.handlers.keyboard.deactivate();
286             deactivated = true;
287         }
288         return deactivated;
289     },
290     
291     /**
292      * Method: beforeSelectFeature
293      * Called before a feature is selected.
294      *
295      * Parameters:
296      * feature - {<OpenLayers.Feature.Vector>} The feature about to be selected.
297      */
298     beforeSelectFeature: function(feature) {
299         return this.layer.events.triggerEvent(
300             "beforefeaturemodified", {feature: feature}
301         );
302     },
303
304     /**
305      * Method: selectFeature
306      * Called when the select feature control selects a feature.
307      *
308      * Parameters:
309      * feature - {<OpenLayers.Feature.Vector>} the selected feature.
310      */
311     selectFeature: function(feature) {
312         this.feature = feature;
313         this.modified = false;
314         this.resetVertices();
315         this.dragControl.activate();
316         this.onModificationStart(this.feature);
317     },
318
319     /**
320      * Method: unselectFeature
321      * Called when the select feature control unselects a feature.
322      *
323      * Parameters:
324      * feature - {<OpenLayers.Feature.Vector>} The unselected feature.
325      */
326     unselectFeature: function(feature) {
327         this.layer.removeFeatures(this.vertices, {silent: true});
328         this.vertices = [];
329         this.layer.destroyFeatures(this.virtualVertices, {silent: true});
330         this.virtualVertices = [];
331         if(this.dragHandle) {
332             this.layer.destroyFeatures([this.dragHandle], {silent: true});
333             delete this.dragHandle;
334         }
335         if(this.radiusHandle) {
336             this.layer.destroyFeatures([this.radiusHandle], {silent: true});
337             delete this.radiusHandle;
338         }
339         this.feature = null;
340         this.dragControl.deactivate();
341         this.onModificationEnd(feature);
342         this.layer.events.triggerEvent("afterfeaturemodified", {
343             feature: feature,
344             modified: this.modified
345         });
346         this.modified = false;
347     },
348
349     /**
350      * Method: dragStart
351      * Called by the drag feature control with before a feature is dragged.
352      *     This method is used to differentiate between points and vertices
353      *     of higher order geometries.  This respects the <geometryTypes>
354      *     property and forces a select of points when the drag control is
355      *     already active (and stops events from propagating to the select
356      *     control).
357      *
358      * Parameters:
359      * feature - {<OpenLayers.Feature.Vector>} The point or vertex about to be
360      *     dragged.
361      * pixel - {<OpenLayers.Pixel>} Pixel location of the mouse event.
362      */
363     dragStart: function(feature, pixel) {
364         // only change behavior if the feature is not in the vertices array
365         if(feature != this.feature && !feature.geometry.parent &&
366            feature != this.dragHandle && feature != this.radiusHandle) {
367             if(this.feature) {
368                 // unselect the currently selected feature
369                 this.selectControl.clickFeature.apply(this.selectControl,
370                                                       [this.feature]);
371             }
372             // check any constraints on the geometry type
373             if(this.geometryTypes == null ||
374                OpenLayers.Util.indexOf(this.geometryTypes,
375                                        feature.geometry.CLASS_NAME) != -1) {
376                 // select the point
377                 this.selectControl.clickFeature.apply(this.selectControl,
378                                                       [feature]);
379                 /**
380                  * TBD: These lines improve workflow by letting the user
381                  *     immediately start dragging after the mouse down.
382                  *     However, it is very ugly to be messing with controls
383                  *     and their handlers in this way.  I'd like a better
384                  *     solution if the workflow change is necessary.
385                  */
386                 // prepare the point for dragging
387                 this.dragControl.overFeature.apply(this.dragControl,
388                                                    [feature]);
389                 this.dragControl.lastPixel = pixel;
390                 this.dragControl.handlers.drag.started = true;
391                 this.dragControl.handlers.drag.start = pixel;
392                 this.dragControl.handlers.drag.last = pixel;
393             }
394         }
395     },
396     
397     /**
398      * Method: dragVertex
399      * Called by the drag feature control with each drag move of a vertex.
400      *
401      * Parameters:
402      * vertex - {<OpenLayers.Feature.Vector>} The vertex being dragged.
403      * pixel - {<OpenLayers.Pixel>} Pixel location of the mouse event.
404      */
405     dragVertex: function(vertex, pixel) {
406         this.modified = true;
407         /**
408          * Five cases:
409          * 1) dragging a simple point
410          * 2) dragging a virtual vertex
411          * 3) dragging a drag handle
412          * 4) dragging a real vertex
413          * 5) dragging a radius handle
414          */
415         if(this.feature.geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
416             // dragging a simple point
417             if(this.feature != vertex) {
418                 this.feature = vertex;
419             }
420             this.layer.events.triggerEvent("vertexmodified", {
421                 vertex: vertex.geometry,
422                 feature: this.feature,
423                 pixel: pixel
424             });
425         } else {
426             if(vertex._index) {
427                 // dragging a virtual vertex
428                 vertex.geometry.parent.addComponent(vertex.geometry,
429                                                     vertex._index);
430                 // move from virtual to real vertex
431                 delete vertex._index;
432                 OpenLayers.Util.removeItem(this.virtualVertices, vertex);
433                 this.vertices.push(vertex);
434             } else if(vertex == this.dragHandle) {
435                 // dragging a drag handle
436                 this.layer.removeFeatures(this.vertices, {silent: true});
437                 this.vertices = [];
438                 if(this.radiusHandle) {
439                     this.layer.destroyFeatures([this.radiusHandle], {silent: true});
440                     this.radiusHandle = null;
441                 }
442             } else if(vertex !== this.radiusHandle) {
443                 // dragging a real vertex
444                 this.layer.events.triggerEvent("vertexmodified", {
445                     vertex: vertex.geometry,
446                     feature: this.feature,
447                     pixel: pixel
448                 });
449             }
450             // dragging a radius handle - no special treatment
451             if(this.virtualVertices.length > 0) {
452                 this.layer.destroyFeatures(this.virtualVertices, {silent: true});
453                 this.virtualVertices = [];
454             }
455             this.layer.drawFeature(this.feature, this.selectControl.renderIntent);
456         }
457         // keep the vertex on top so it gets the mouseout after dragging
458         // this should be removed in favor of an option to draw under or
459         // maintain node z-index
460         this.layer.drawFeature(vertex);
461     },
462     
463     /**
464      * Method: dragComplete
465      * Called by the drag feature control when the feature dragging is complete.
466      *
467      * Parameters:
468      * vertex - {<OpenLayers.Feature.Vector>} The vertex being dragged.
469      */
470     dragComplete: function(vertex) {
471         this.resetVertices();
472         this.setFeatureState();
473         this.onModification(this.feature);
474         this.layer.events.triggerEvent("featuremodified", 
475                                        {feature: this.feature});
476     },
477     
478     /**
479      * Method: setFeatureState
480      * Called when the feature is modified.  If the current state is not
481      *     INSERT or DELETE, the state is set to UPDATE.
482      */
483     setFeatureState: function() {
484         if(this.feature.state != OpenLayers.State.INSERT &&
485            this.feature.state != OpenLayers.State.DELETE) {
486             this.feature.state = OpenLayers.State.UPDATE;
487         }
488     },
489     
490     /**
491      * Method: resetVertices
492      */
493     resetVertices: function() {
494         // if coming from a drag complete we're about to destroy the vertex
495         // that was just dragged. For that reason, the drag feature control
496         // will never detect a mouse-out on that vertex, meaning that the drag
497         // handler won't be deactivated. This can cause errors because the drag
498         // feature control still has a feature to drag but that feature is
499         // destroyed. To prevent this, we call outFeature on the drag feature
500         // control if the control actually has a feature to drag.
501         if(this.dragControl.feature) {
502             this.dragControl.outFeature(this.dragControl.feature);
503         }
504         if(this.vertices.length > 0) {
505             this.layer.removeFeatures(this.vertices, {silent: true});
506             this.vertices = [];
507         }
508         if(this.virtualVertices.length > 0) {
509             this.layer.removeFeatures(this.virtualVertices, {silent: true});
510             this.virtualVertices = [];
511         }
512         if(this.dragHandle) {
513             this.layer.destroyFeatures([this.dragHandle], {silent: true});
514             this.dragHandle = null;
515         }
516         if(this.radiusHandle) {
517             this.layer.destroyFeatures([this.radiusHandle], {silent: true});
518             this.radiusHandle = null;
519         }
520         if(this.feature &&
521            this.feature.geometry.CLASS_NAME != "OpenLayers.Geometry.Point") {
522             if((this.mode & OpenLayers.Control.ModifyFeature.DRAG)) {
523                 this.collectDragHandle();
524             }
525             if((this.mode & (OpenLayers.Control.ModifyFeature.ROTATE |
526                              OpenLayers.Control.ModifyFeature.RESIZE))) {
527                 this.collectRadiusHandle();
528             }
529             if(this.mode & OpenLayers.Control.ModifyFeature.RESHAPE){
530                 // Don't collect vertices when we're resizing
531                 if (!(this.mode & OpenLayers.Control.ModifyFeature.RESIZE)){
532                     this.collectVertices();
533                 }
534             }
535         }
536     },
537     
538     /**
539      * Method: handleKeypress
540      * Called by the feature handler on keypress.  This is used to delete
541      *     vertices. If the <deleteCode> property is set, vertices will
542      *     be deleted when a feature is selected for modification and
543      *     the mouse is over a vertex.
544      *
545      * Parameters:
546      * {Integer} Key code corresponding to the keypress event.
547      */
548     handleKeypress: function(evt) {
549         var code = evt.keyCode;
550         
551         // check for delete key
552         if(this.feature &&
553            OpenLayers.Util.indexOf(this.deleteCodes, code) != -1) {
554             var vertex = this.dragControl.feature;
555             if(vertex &&
556                OpenLayers.Util.indexOf(this.vertices, vertex) != -1 &&
557                !this.dragControl.handlers.drag.dragging &&
558                vertex.geometry.parent) {
559                 // remove the vertex
560                 vertex.geometry.parent.removeComponent(vertex.geometry);
561                 this.layer.drawFeature(this.feature,
562                                        this.selectControl.renderIntent);
563                 this.resetVertices();
564                 this.setFeatureState();
565                 this.onModification(this.feature);
566                 this.layer.events.triggerEvent("featuremodified", 
567                                                {feature: this.feature});
568             }
569         }
570     },
571
572     /**
573      * Method: collectVertices
574      * Collect the vertices from the modifiable feature's geometry and push
575      *     them on to the control's vertices array.
576      */
577     collectVertices: function() {
578         this.vertices = [];
579         this.virtualVertices = [];        
580         var control = this;
581         function collectComponentVertices(geometry) {
582             var i, vertex, component, len;
583             if(geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
584                 vertex = new OpenLayers.Feature.Vector(geometry);
585                 vertex._sketch = true;
586                 control.vertices.push(vertex);
587             } else {
588                 var numVert = geometry.components.length;
589                 if(geometry.CLASS_NAME == "OpenLayers.Geometry.LinearRing") {
590                     numVert -= 1;
591                 }
592                 for(i=0; i<numVert; ++i) {
593                     component = geometry.components[i];
594                     if(component.CLASS_NAME == "OpenLayers.Geometry.Point") {
595                         vertex = new OpenLayers.Feature.Vector(component);
596                         vertex._sketch = true;
597                         control.vertices.push(vertex);
598                     } else {
599                         collectComponentVertices(component);
600                     }
601                 }
602                 
603                 // add virtual vertices in the middle of each edge
604                 if(geometry.CLASS_NAME != "OpenLayers.Geometry.MultiPoint") {
605                     for(i=0, len=geometry.components.length; i<len-1; ++i) {
606                         var prevVertex = geometry.components[i];
607                         var nextVertex = geometry.components[i + 1];
608                         if(prevVertex.CLASS_NAME == "OpenLayers.Geometry.Point" &&
609                            nextVertex.CLASS_NAME == "OpenLayers.Geometry.Point") {
610                             var x = (prevVertex.x + nextVertex.x) / 2;
611                             var y = (prevVertex.y + nextVertex.y) / 2;
612                             var point = new OpenLayers.Feature.Vector(
613                                 new OpenLayers.Geometry.Point(x, y),
614                                 null, control.virtualStyle
615                             );
616                             // set the virtual parent and intended index
617                             point.geometry.parent = geometry;
618                             point._index = i + 1;
619                             point._sketch = true;
620                             control.virtualVertices.push(point);
621                         }
622                     }
623                 }
624             }
625         }
626         collectComponentVertices.call(this, this.feature.geometry);
627         this.layer.addFeatures(this.virtualVertices, {silent: true});
628         this.layer.addFeatures(this.vertices, {silent: true});
629     },
630
631     /**
632      * Method: collectDragHandle
633      * Collect the drag handle for the selected geometry.
634      */
635     collectDragHandle: function() {
636         var geometry = this.feature.geometry;
637         var center = geometry.getBounds().getCenterLonLat();
638         var originGeometry = new OpenLayers.Geometry.Point(
639             center.lon, center.lat
640         );
641         var origin = new OpenLayers.Feature.Vector(originGeometry);
642         originGeometry.move = function(x, y) {
643             OpenLayers.Geometry.Point.prototype.move.call(this, x, y);
644             geometry.move(x, y);
645         };
646         origin._sketch = true;
647         this.dragHandle = origin;
648         this.layer.addFeatures([this.dragHandle], {silent: true});
649     },
650
651     /**
652      * Method: collectRadiusHandle
653      * Collect the radius handle for the selected geometry.
654      */
655     collectRadiusHandle: function() {
656         var geometry = this.feature.geometry;
657         var bounds = geometry.getBounds();
658         var center = bounds.getCenterLonLat();
659         var originGeometry = new OpenLayers.Geometry.Point(
660             center.lon, center.lat
661         );
662         var radiusGeometry = new OpenLayers.Geometry.Point(
663             bounds.right, bounds.bottom
664         );
665         var radius = new OpenLayers.Feature.Vector(radiusGeometry);
666         var resize = (this.mode & OpenLayers.Control.ModifyFeature.RESIZE);
667         var reshape = (this.mode & OpenLayers.Control.ModifyFeature.RESHAPE);
668         var rotate = (this.mode & OpenLayers.Control.ModifyFeature.ROTATE);
669
670         radiusGeometry.move = function(x, y) {
671             OpenLayers.Geometry.Point.prototype.move.call(this, x, y);
672             var dx1 = this.x - originGeometry.x;
673             var dy1 = this.y - originGeometry.y;
674             var dx0 = dx1 - x;
675             var dy0 = dy1 - y;
676             if(rotate) {
677                 var a0 = Math.atan2(dy0, dx0);
678                 var a1 = Math.atan2(dy1, dx1);
679                 var angle = a1 - a0;
680                 angle *= 180 / Math.PI;
681                 geometry.rotate(angle, originGeometry);
682             }
683             if(resize) {
684                 var scale, ratio;
685                 // 'resize' together with 'reshape' implies that the aspect 
686                 // ratio of the geometry will not be preserved whilst resizing 
687                 if (reshape) {
688                     scale = dy1 / dy0;
689                     ratio = (dx1 / dx0) / scale;
690                 } else {
691                     var l0 = Math.sqrt((dx0 * dx0) + (dy0 * dy0));
692                     var l1 = Math.sqrt((dx1 * dx1) + (dy1 * dy1));
693                     scale = l1 / l0;
694                 }
695                 geometry.resize(scale, originGeometry, ratio);
696             }
697         };
698         radius._sketch = true;
699         this.radiusHandle = radius;
700         this.layer.addFeatures([this.radiusHandle], {silent: true});
701     },
702
703     /**
704      * Method: setMap
705      * Set the map property for the control and all handlers.
706      *
707      * Parameters:
708      * map - {<OpenLayers.Map>} The control's map.
709      */
710     setMap: function(map) {
711         this.selectControl.setMap(map);
712         this.dragControl.setMap(map);
713         OpenLayers.Control.prototype.setMap.apply(this, arguments);
714     },
715
716     CLASS_NAME: "OpenLayers.Control.ModifyFeature"
717 });
718
719 /**
720  * Constant: RESHAPE
721  * {Integer} Constant used to make the control work in reshape mode
722  */
723 OpenLayers.Control.ModifyFeature.RESHAPE = 1;
724 /**
725  * Constant: RESIZE
726  * {Integer} Constant used to make the control work in resize mode
727  */
728 OpenLayers.Control.ModifyFeature.RESIZE = 2;
729 /**
730  * Constant: ROTATE
731  * {Integer} Constant used to make the control work in rotate mode
732  */
733 OpenLayers.Control.ModifyFeature.ROTATE = 4;
734 /**
735  * Constant: DRAG
736  * {Integer} Constant used to make the control work in drag mode
737  */
738 OpenLayers.Control.ModifyFeature.DRAG = 8;