OpenLayers OpenLayers

Changeset 4307

Show
Ignore:
Timestamp:
09/14/07 19:35:55 (1 year ago)
Author:
tschaub
Message:

update modify features control

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • sandbox/tschaub/wfsv/lib/OpenLayers/Control/FeatureEditor.js

    r4304 r4307  
    115115                {displayClass: "olControlModifyFeature"} 
    116116        ); 
    117         this.modifyControl.onModify = function(feature) { 
     117        this.modifyControl.onModification = function(feature) { 
    118118            if(feature.state != OpenLayers.State.INSERT) { 
    119119                feature.state = OpenLayers.State.UPDATE; 
  • sandbox/tschaub/wfsv/lib/OpenLayers/Control/ModifyFeature.js

    r3895 r4307  
    55 
    66/** 
    7  * Move a feature with a drag. 
     7 * @requires OpenLayers/Control/DragFeature.js 
     8 * @requires OpenLayers/Control/SelectFeature.js 
     9 * @requires OpenLayers/Handler/Keyboard.js 
    810 *  
    9  * @class 
    10  * @requires OpenLayers/Control/DragFeature.js 
     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> 
    1120 */ 
    12 OpenLayers.Control.ModifyFeature = OpenLayers.Class.create(); 
    13 OpenLayers.Control.ModifyFeature.prototype =  
    14   OpenLayers.Class.inherit(OpenLayers.Control, { 
    15  
    16     /** 
    17      * To restrict dragging to a limited set of geometry types, send a list 
    18      * of strings corresponding to the geometry class names. 
     21OpenLayers.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. 
    19194     *  
    20      * @type Array(String) 
    21      */ 
    22     geometryTypes: null, 
    23      
    24     /** 
    25      * APIProperty: onModify 
    26      * Called on each feature modification. 
    27      */ 
    28     onModify: function(feature) {}, 
    29  
    30     /** 
    31      * @type OpenLayers.Layer.Vector 
    32      * @private 
    33      */ 
    34     layer: null, 
    35      
    36     /** 
    37      * @type OpenLayers.Feature.Vector 
    38      * @private 
    39      */ 
    40     feature: null, 
    41      
    42     /** 
    43      * @type Array(OpenLayers.Feature.Vector) 
    44      * @private 
    45      */ 
    46     verticies: null, 
    47  
    48     /** 
    49      * @type OpenLayers.Control.Select 
    50      * @private 
    51      */ 
    52     selectControl: null, 
    53      
    54     /** 
    55      * @type OpenLayers.Control.DragFeature 
    56      * @private 
    57      */ 
    58     dragControl: null, 
    59      
    60     /** 
    61      * @param {OpenLayers.Layer.Vector} layer 
    62      * @param {Object} options 
    63      */ 
    64     initialize: function(layer, options) { 
    65         OpenLayers.Control.prototype.initialize.apply(this, [options]); 
    66         this.verticies = []; 
    67         this.layer = layer; 
    68         var control = this; 
    69         this.selectControl = new OpenLayers.Control.SelectFeature(layer, 
    70                                     {onSelect: function(feature) { 
    71                                         control.onSelect.apply(control, [feature]); 
    72                                      }, 
    73                                      onUnselect: function(feature) { 
    74                                         control.onUnselect.apply(control, [feature]); 
    75                                      }}); 
    76         this.dragControl = new OpenLayers.Control.DragFeature(layer, 
    77                                 {geometryTypes: ["OpenLayers.Geometry.Point"], 
    78                                  onDrag: function(feature) { 
    79                                     control.onDrag.apply(control, [feature]); 
    80                                  }, 
    81                                  onComplete: function() { 
    82                                     control.onModify(control.feature) 
    83                                  }}); 
    84     }, 
    85  
    86     /** 
    87      * Activate the control and the feature handler 
    88      *  
    89      * @type Boolean 
    90      * @return Successfully activated the control and feature handler 
     195     * Returns: 
     196     * {Boolean} Successfully activated the control and feature handler. 
    91197     */ 
    92198    activate: function() { 
    93199        return (this.selectControl.activate() && 
     200                this.keyboardHandler.activate() && 
    94201                OpenLayers.Control.prototype.activate.apply(this, arguments)); 
    95202    }, 
    96203 
    97204    /** 
    98      * Deactivate the controls 
    99      *  
    100      * @type Boolean 
    101      * @return Successfully deactivated the control 
     205     * APIMethod: deactivate 
     206     * Deactivate the controls. 
     207     * 
     208     * Returns:  
     209     * {Boolean} Successfully deactivated the control. 
    102210     */ 
    103211    deactivate: function() { 
     212        var deactivated = false; 
    104213        // the return from the controls is unimportant in this case 
    105214        if(OpenLayers.Control.prototype.deactivate.apply(this, arguments)) { 
    106             this.layer.removeFeatures(this.verticies); 
    107             this.verticies = []; 
     215            this.layer.removeFeatures(this.vertices); 
     216            this.layer.removeFeatures(this.virtualVertices); 
     217            this.vertices = []; 
    108218            this.dragControl.deactivate(); 
    109219            if(this.feature) { 
    110                 this.selectControl.unselect.apply(this.selectControl, [this.feature]); 
     220                this.selectControl.unselect.apply(this.selectControl, 
     221                                                  [this.feature]); 
    111222            } 
    112223            this.selectControl.deactivate(); 
    113             return true; 
    114         } else { 
    115             return false; 
    116         }    
    117     }, 
    118  
    119     /** 
     224            this.keyboardHandler.deactivate(); 
     225            deactivated = true; 
     226        } 
     227        return deactivated; 
     228    }, 
     229 
     230    /** 
     231     * Method: selectFeature 
    120232     * Called when the select feature control selects a feature. 
    121      *  
    122      * @param {OpenLayers.Feature.Vector} feature 
    123      */ 
    124     onSelect: function(feature) { 
     233     * 
     234     * Parameters: 
     235     * feature - {<OpenLayers.Feature.Vector>} The selected feature. 
     236     */ 
     237    selectFeature: function(feature) { 
    125238        this.feature = feature; 
    126         if(this.verticies.length > 0) { 
    127             this.layer.removeFeatures(this.verticies); 
    128             this.verticies = []; 
    129         } 
    130         if(this.feature.geometry.CLASS_NAME != "OpenLayers.Geometry.Point") { 
    131             this.collectVerticies(feature.geometry); 
    132             this.layer.addFeatures(this.verticies); 
    133         } 
     239        this.resetVertices(); 
    134240        this.dragControl.activate(); 
    135     }, 
    136  
    137     /** 
     241        this.onModificationStart(this.feature); 
     242    }, 
     243 
     244    /** 
     245     * Method: unselectFeature 
    138246     * Called when the select feature control unselects a feature. 
    139      *  
    140      * @param {OpenLayers.Feature.Vector} feature 
    141      */ 
    142     onUnselect: function(feature) { 
    143         this.layer.removeFeatures(this.verticies); 
    144         this.verticies = []; 
     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 = []; 
    145256        this.feature = null; 
    146257        this.dragControl.deactivate(); 
    147     }, 
    148      
    149     /** 
     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 
    150312     * Called by the drag feature control with each drag move of a vertex. 
    151      * @param {OpenLayers.Feature.Vector} vertex 
    152      */ 
    153     onDrag: function(vertex) { 
     313     * 
     314     * Parameters: 
     315     * vertex - {<OpenLayers.Feature.Vector>} The vertex being dragged. 
     316     */ 
     317    dragVertex: function(vertex) { 
    154318        if(this.feature.geometry.CLASS_NAME == "OpenLayers.Geometry.Point") { 
    155319            if(this.feature != vertex) { 
    156320                this.feature = vertex; 
    157321            } 
     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            } 
    158330        } 
    159331        this.layer.drawFeature(this.feature, this.selectControl.selectStyle); 
     332        this.layer.removeFeatures(this.virtualVertices); 
    160333        // keep the vertex on top so it gets the mouseout after dragging 
    161334        // this should be removed in favor of an option to draw under or 
     
    165338     
    166339    /** 
    167      * Collect the verticies from the input geometry and push them on to the 
    168      * control's vertices array 
    169      * @param {OpenLayers.Geometry} geometry 
    170      */ 
    171     collectVerticies: function(geometry) { 
    172         var i, vertex, component; 
    173         if(geometry.CLASS_NAME == "OpenLayers.Geometry.Point") { 
    174             vertex = new  OpenLayers.Feature.Vector(geometry); 
    175             this.verticies.push(vertex); 
    176         } else { 
    177             for(i=0; i<geometry.components.length; ++i) { 
    178                 component = geometry.components[i]; 
    179                 if(component.CLASS_NAME == "OpenLayers.Geometry.Point") { 
    180                     vertex = new OpenLayers.Feature.Vector(component); 
    181                     this.verticies.push(vertex); 
    182                 } else { 
    183                     this.collectVerticies(component); 
     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                    } 
    184421                } 
    185             } 
    186         } 
    187     }, 
    188  
    189     /** 
     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 
    190450     * Set the map property for the control and all handlers. 
    191      *  
    192      * @param {OpenLayers.Map} map 
     451     * 
     452     * Parameters: 
     453     * map - {OpenLayers.Map} The control's map. 
    193454     */ 
    194455    setMap: function(map) { 
     
    198459    }, 
    199460 
    200     /** @final @type String */ 
    201461    CLASS_NAME: "OpenLayers.Control.ModifyFeature" 
    202462});