PageSourceSearch

http://vttrack.fr/js/OpenLayers-2.12/lib/OpenLayers/Control/ModifyFeature.js?1791055304

js vttrack.fr collected 2026-10-03 21:20:29 UTC 31,873 bytes, 851 lines download raw bytes

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

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.