OpenLayers OpenLayers

Changeset 5301

Show
Ignore:
Timestamp:
11/30/07 12:09:23 (1 year ago)
Author:
tschaub
Message:

drag, rotate, resize, and reshape with the ModifyFeature control - thanks pvalsecc and elemoine for the inspiration, tests, and code - good partenering with you guys (closes #1150).

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/openlayers/examples/modify-feature.html

    r4272 r5301  
    5454                polygon: new OpenLayers.Control.DrawFeature(vectors, 
    5555                            OpenLayers.Handler.Polygon), 
     56                regular: new OpenLayers.Control.DrawFeature(vectors, 
     57                            OpenLayers.Handler.RegularPolygon, 
     58                            {handlerOptions: {sides: 5}}), 
    5659                modify: new OpenLayers.Control.ModifyFeature(vectors, 
    5760                                                             modifyOptions) 
     
    6669        } 
    6770         
     71        function update() { 
     72            var rotate = document.getElementById("rotate").checked; 
     73            controls.modify.rotate = rotate; 
     74            var resize = document.getElementById("resize").checked; 
     75            controls.modify.resize = resize; 
     76            var drag = document.getElementById("drag").checked; 
     77            controls.modify.drag = drag; 
     78            var sides = parseInt(document.getElementById("sides").value); 
     79            sides = Math.max(3, isNaN(sides) ? 0 : sides); 
     80            controls.regular.handler.sides = sides; 
     81            var irregular =  document.getElementById("irregular").checked; 
     82            controls.regular.handler.irregular = irregular; 
     83        } 
    6884 
    6985        function toggleControl(element) { 
     
    103119            </li> 
    104120            <li> 
     121                <input type="radio" name="type" value="regular" id="regularToggle" onclick="toggleControl(this);" /> 
     122                <label for="regularToggle">draw regular polygon</label> 
     123                <label for="sides"> - sides</label> 
     124                <input id="sides" type="text" size="2" maxlength="2" 
     125                       name="sides" value="5" onchange="update()" /> 
     126                <ul> 
     127                    <li> 
     128                        <input id="irregular" type="checkbox" 
     129                               name="irregular" onchange="update()" /> 
     130                        <label for="irregular">irregular</label> 
     131                    </li> 
     132                </ul> 
     133            </li> 
     134            <li> 
    105135                <input type="radio" name="type" value="modify" id="modifyToggle" 
    106136                       onclick="toggleControl(this);" /> 
    107137                <label for="modifyToggle">modify feature</label> 
     138                <ul> 
     139                    <li> 
     140                        <input id="rotate" type="checkbox" 
     141                               name="rotate" onchange="update()" /> 
     142                        <label for="rotate">allow rotation</label> 
     143                    </li> 
     144                    <li> 
     145                        <input id="resize" type="checkbox" 
     146                               name="resize" onchange="update()" /> 
     147                        <label for="resize">allow resizing</label> 
     148                    </li> 
     149                    <li> 
     150                        <input id="drag" type="checkbox" 
     151                               name="drag" onchange="update()" /> 
     152                        <label for="drag">allow dragging</label> 
     153                    </li> 
     154                </ul> 
    108155            </li> 
    109156        </ul> 
  • trunk/openlayers/lib/OpenLayers/Control/ModifyFeature.js

    r5099 r5301  
    8787     */ 
    8888    virtualStyle: null, 
    89      
     89 
     90    /** 
     91     * APIProperty: rotate 
     92     * {Boolean} Allow rotation of feature instead of vertex modification. 
     93     */ 
     94    rotate: false, 
     95 
     96    /** 
     97     * APIProperty: resize 
     98     * {Boolean} Allow resizing of feature instead of vertex modification. 
     99     */ 
     100    resize: false, 
     101 
     102    /** 
     103     * Property: radiusHandle 
     104     * {<OpenLayers.Feature.Vector>} A handle for rotating/resizing a feature. 
     105     */ 
     106    radiusHandle: null, 
     107 
     108    /** 
     109     * APIProperty: drag 
     110     * {Boolean} Allow dragging of feature with a drag handle. 
     111     */ 
     112    drag: false, 
     113     
     114    /** 
     115     * Property: dragHandle 
     116     * {<OpenLayers.Feature.Vector>} A handle for dragging a feature. 
     117     */ 
     118    dragHandle: null, 
     119 
    90120    /** 
    91121     * APIProperty: onModificationStart  
     
    251281    unselectFeature: function(feature) { 
    252282        this.layer.removeFeatures(this.vertices); 
    253         this.layer.removeFeatures(this.virtualVertices); 
    254283        this.vertices = []; 
     284        this.layer.destroyFeatures(this.virtualVertices); 
    255285        this.virtualVertices = []; 
     286        if(this.dragHandle) { 
     287            this.layer.destroyFeatures([this.dragHandle]); 
     288            delete this.dragHandle; 
     289        } 
     290        if(this.radiusHandle) { 
     291            this.layer.destroyFeatures([this.radiusHandle]); 
     292            delete this.radiusHandle; 
     293        } 
    256294        this.feature = null; 
    257295        this.dragControl.deactivate(); 
     
    275313    dragStart: function(feature, pixel) { 
    276314        // 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) { 
     315        if(feature != this.feature && !feature.geometry.parent && 
     316           feature != this.dragHandle && feature != this.radiusHandle) { 
    280317            if(this.feature) { 
    281318                // unselect the currently selected feature 
     
    316353     */ 
    317354    dragVertex: function(vertex) { 
     355        /** 
     356         * Five cases: 
     357         * 1) dragging a simple point 
     358         * 2) dragging a virtual vertex 
     359         * 3) dragging a drag handle 
     360         * 4) dragging a radius handle 
     361         * 5) dragging a real vertex 
     362         */ 
    318363        if(this.feature.geometry.CLASS_NAME == "OpenLayers.Geometry.Point") { 
     364            // dragging a simple point 
    319365            if(this.feature != vertex) { 
    320366                this.feature = vertex; 
    321367            } 
    322368        } else { 
    323             if(OpenLayers.Util.indexOf(this.virtualVertices, vertex) != -1) { 
     369            if(vertex._index) { 
     370                // dragging a virtual vertex 
    324371                vertex.geometry.parent.addComponent(vertex.geometry, 
    325372                                                    vertex._index); 
    326373                delete vertex._index; 
    327374                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); 
     375            } else if(vertex == this.dragHandle) { 
     376                // dragging a drag handle 
     377                this.layer.removeFeatures(this.vertices); 
     378                this.vertices = []; 
     379                if(this.radiusHandle) { 
     380                    this.layer.destroyFeatures([this.radiusHandle]); 
     381                    this.radiusHandle = null; 
     382                } 
     383            } 
     384            // dragging a radius handle - no special treatment 
     385            // dragging a real vertex - no special treatment 
     386            this.layer.destroyFeatures(this.virtualVertices); 
     387            this.virtualVertices = []; 
     388            this.layer.drawFeature(this.feature, this.selectControl.selectStyle); 
     389        } 
    333390        // keep the vertex on top so it gets the mouseout after dragging 
    334391        // this should be removed in favor of an option to draw under or 
     
    361418            this.virtualVertices = []; 
    362419        } 
     420        if(this.dragHandle) { 
     421            this.layer.destroyFeatures([this.dragHandle]); 
     422            this.dragHandle = null; 
     423        } 
     424        if(this.radiusHandle) { 
     425            this.layer.destroyFeatures([this.radiusHandle]); 
     426            this.radiusHandle = null; 
     427        } 
    363428        if(this.feature && 
    364429           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); 
     430            if(this.drag) { 
     431                this.collectDragHandle(); 
     432            } 
     433            if(this.rotate || this.resize) { 
     434                this.collectRadiusHandle(); 
     435            } else { 
     436                this.collectVertices(); 
     437            } 
    368438        } 
    369439    }, 
     
    386456            if(vertex && 
    387457               OpenLayers.Util.indexOf(this.vertices, vertex) != -1 && 
    388                !this.dragControl.dragHandler.dragging) { 
     458               !this.dragControl.dragHandler.dragging && 
     459               vertex.geometry.parent) { 
    389460                // remove the vertex 
    390461                vertex.geometry.parent.removeComponent(vertex.geometry); 
     
    443514                } 
    444515            } 
    445         }        
    446         collectComponentVertices(this.feature.geometry); 
     516        } 
     517        collectComponentVertices.call(this, this.feature.geometry); 
     518        this.layer.addFeatures(this.vertices); 
     519        this.layer.addFeatures(this.virtualVertices); 
     520    }, 
     521 
     522    /** 
     523     * Method: collectDragHandle 
     524     * Collect the drag handle for the selected geometry. 
     525     */ 
     526    collectDragHandle: function() { 
     527        var geometry = this.feature.geometry; 
     528        var center = geometry.getBounds().getCenterLonLat(); 
     529        var originGeometry = new OpenLayers.Geometry.Point( 
     530            center.lon, center.lat 
     531        ); 
     532        var origin = new OpenLayers.Feature.Vector(originGeometry); 
     533        originGeometry.move = function(x, y) { 
     534            OpenLayers.Geometry.Point.prototype.move.call(this, x, y); 
     535            geometry.move(x, y); 
     536        } 
     537        this.dragHandle = origin; 
     538        this.layer.addFeatures([this.dragHandle]); 
     539    }, 
     540 
     541    /** 
     542     * Method: collectRadiusHandle 
     543     * Collect the radius handle for the selected geometry. 
     544     */ 
     545    collectRadiusHandle: function() { 
     546        var geometry = this.feature.geometry; 
     547        var bounds = geometry.getBounds(); 
     548        var center = bounds.getCenterLonLat(); 
     549        var originGeometry = new OpenLayers.Geometry.Point( 
     550            center.lon, center.lat 
     551        ); 
     552        var radiusGeometry = new OpenLayers.Geometry.Point( 
     553            bounds.right, bounds.bottom 
     554        ); 
     555        var radius = new OpenLayers.Feature.Vector(radiusGeometry); 
     556        var resize = this.resize; 
     557        var rotate = this.rotate; 
     558        radiusGeometry.move = function(x, y) { 
     559            OpenLayers.Geometry.Point.prototype.move.call(this, x, y); 
     560            var dx1 = this.x - originGeometry.x; 
     561            var dy1 = this.y - originGeometry.y; 
     562            var dx0 = dx1 - x; 
     563            var dy0 = dy1 - y; 
     564            if(rotate) { 
     565                var a0 = Math.atan2(dy0, dx0); 
     566                var a1 = Math.atan2(dy1, dx1); 
     567                var angle = a1 - a0; 
     568                angle *= 180 / Math.PI; 
     569                geometry.rotate(angle, originGeometry); 
     570            } 
     571            if(resize) { 
     572                var l0 = Math.sqrt((dx0 * dx0) + (dy0 * dy0)); 
     573                var l1 = Math.sqrt((dx1 * dx1) + (dy1 * dy1)); 
     574                geometry.resize(l1 / l0, originGeometry); 
     575            } 
     576        } 
     577        this.radiusHandle = radius; 
     578        this.layer.addFeatures([this.radiusHandle]); 
    447579    }, 
    448580 
  • trunk/openlayers/lib/OpenLayers/Layer/Vector.js

    r5244 r5301  
    308308    /** 
    309309     * APIMethod: destroyFeatures 
    310      * Destroy all features on the layer and empty the selected features array. 
    311      */ 
    312     destroyFeatures: function () { 
    313         this.selectedFeatures = []; 
    314         for (var i = this.features.length - 1; i >= 0; i--) { 
    315             this.features[i].destroy(); 
     310     * Erase and estroy features on the layer. 
     311     * 
     312     * Parameters: 
     313     * features - {Array(<OpenLayers.Feature.Vector>)} An optional array of 
     314     *     features to destroy.  If not supplied, all features on the layer 
     315     *     will be destroyed. 
     316     */ 
     317    destroyFeatures: function(features) { 
     318        var all = (features == undefined); 
     319        if(all) { 
     320            features = this.features; 
     321            this.selectedFeatures = []; 
     322        } 
     323        this.eraseFeatures(features); 
     324        var feature; 
     325        for(var i=features.length-1; i>=0; i--) { 
     326            feature = features[i]; 
     327            if(!all) { 
     328                OpenLayers.Util.removeItem(this.selectedFeatures, feature); 
     329            } 
     330            feature.destroy(); 
    316331        } 
    317332    }, 
  • trunk/openlayers/tests/Control/test_ModifyFeature.html

    r5099 r5301  
    191191        control.onModificationEnd = function (feature) { t.eq(feature.id, fakeFeature.id, "onModificationEnd got feature.") } 
    192192        layer.removeFeatures = function(verts) { 
    193             t.ok(verts == 'a' || verts == 'b', "Verts removed correctly") 
     193            t.ok(verts == 'a', "Normal verts removed correctly"); 
     194        } 
     195        layer.destroyFeatures = function(verts) { 
     196            t.ok(verts == 'b', "Virtual verts destroyed correctly"); 
    194197        } 
    195198        control.unselectFeature(fakeFeature); 
     
    215218         
    216219        control.collectVertices = function() {  
     220          t.ok(true, "collectVertices called");  
    217221          this.vertices = 'a'; 
    218222          this.virtualVertices = 'd'; 
    219           t.ok(true, "collectVertices called");  
     223          layer.addFeatures(this.vertices); 
     224          layer.addFeatures(this.virtualVertices); 
    220225        } 
    221226         
     
    243248 
    244249    function test_ModifyFeature_resetVertices(t) { 
    245         t.plan(9); 
     250        t.plan(15); 
    246251        var layer = new OpenLayers.Layer.Vector(); 
    247252        var control = new OpenLayers.Control.ModifyFeature(layer); 
     
    254259        t.eq(control.vertices.length, 0, "Correct vertices length"); 
    255260        t.eq(control.virtualVertices.length, 0, "Correct virtual vertices length."); 
    256          
     261 
    257262        var multiPoint = new OpenLayers.Geometry.MultiPoint([point, point2]); 
    258263        control.feature = new OpenLayers.Feature.Vector(multiPoint); 
     
    274279        t.eq(control.virtualVertices.length, 3, "Correct virtual vertices length (polygon)."); 
    275280 
     281        control.drag = true; 
     282        control.resetVertices(); 
     283        t.ok(control.dragHandle != null, "Drag handle is set"); 
     284        t.eq(control.vertices.length, 4, "Correct vertices length with polygon (drag)"); 
     285 
     286        control.rotate = true; 
     287        control.resetVertices(); 
     288        t.ok(control.radiusHandle != null, "Radius handle is set"); 
     289        t.eq(control.vertices.length, 0, "Correct vertices length with polygon (rotate)"); 
     290 
     291        control.rotate = false; 
     292        control.resize = true; 
     293        t.ok(control.radiusHandle != null, "Radius handle is set"); 
     294        t.eq(control.vertices.length, 0, "Correct vertices length with polygon (resize)"); 
    276295    }     
    277296         
     
    290309         'id': 'fakeFeature' 
    291310        }; 
    292         control.collectVertices = function(geom) { 
    293             t.eq(geom.id, 'myGeom', "collect geom called"); 
     311        layer.addFeatures = function (verts) { 
     312            t.ok(verts == 'virtual' || verts == 'normal', verts + " verts correct"); 
     313        } 
     314        layer.removeFeatures = function (verts) { 
     315            t.ok(verts == 'previous virtual' || verts == 'previous normal', verts + " verts correct"); 
     316        } 
     317        control.onModification = function(feat) { 
     318            t.eq(feat.id, fakeFeature.id, "onModification gets correct feat"); 
     319        } 
     320        control.collectVertices = function() { 
     321            t.ok(true, "collectVertices called"); 
    294322            this.vertices = 'normal'; 
    295323            this.virtualVertices = 'virtual'; 
    296         } 
    297         layer.addFeatures = function (verts) { 
    298             t.ok(verts == 'virtual' || verts == 'normal', verts + " verts correct"); 
    299         } 
    300         layer.removeFeatures = function (verts) { 
    301             t.ok(verts == 'previous virtual' || verts == 'previous normal', verts + " verts correct"); 
    302         } 
    303         control.onModification = function(feat) { 
    304             t.eq(feat.id, fakeFeature.id, "onModification gets correct feat"); 
     324            layer.addFeatures(this.vertices); 
     325            layer.addFeatures(this.virtualVertices); 
    305326        } 
    306327        control.feature = fakeFeature; 
  • trunk/openlayers/tests/Layer/test_Vector.html

    r4356 r5301  
    131131 
    132132    function test_Layer_Vector_destroyFeatures (t) { 
    133         t.plan(3);  
     133        t.plan(5);  
    134134        layer = new OpenLayers.Layer.Vector(name); 
    135135        var map = new OpenLayers.Map('map'); 
     
    146146        t.eq(layer.features.length, 0, "destroyFeatures triggers removal"); 
    147147        t.eq(layer.selectedFeatures, [], "Destroy features removes selected features"); 
     148        features = []; 
     149        for (var i = 0; i < 5; i++) { 
     150            features.push(new OpenLayers.Feature.Vector( 
     151                          new OpenLayers.Geometry.Point(0,0))); 
     152        } 
     153        layer.addFeatures(features); 
     154        layer.selectedFeatures.push(features[0]); 
     155        layer.selectedFeatures.push(features[1]); 
     156        layer.destroyFeatures([features[0], features[1]]); 
     157        t.eq(layer.features.length, 3, "destroyFeatures removes appropriate features"); 
     158        t.eq(layer.selectedFeatures, [], "destroyFeatures removes appropriate selected features"); 
    148159    } 
    149160