OpenLayers OpenLayers

Changeset 5335

Show
Ignore:
Timestamp:
12/04/07 04:54:05 (1 year ago)
Author:
elemoine
Message:

unselect features on clickout (ticket #1137) - see <http://dev.openlayers.org/sandbox/elemoine/playground/examples/select-feature.html> for a live example.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • sandbox/elemoine/playground/examples/select-feature.html

    r5211 r5335  
    1414    <script src="../lib/OpenLayers.js"></script> 
    1515    <script type="text/javascript"> 
    16         var map, drawControls, select
     16        var map, drawControls
    1717        OpenLayers.Feature.Vector.style['default']['strokeWidth'] = '2'; 
    1818        function init(){ 
     
    3939                    vectors, OpenLayers.Handler.Polygon 
    4040                ), 
    41                 select: new OpenLayers.Control.SelectFeature(vectors), 
     41                click: new OpenLayers.Control.SelectFeature( 
     42                    vectors 
     43                ), 
     44                multiple: new OpenLayers.Control.SelectFeature( 
     45                    vectors, {multiple: true} 
     46                ), 
     47                clickout: new OpenLayers.Control.SelectFeature( 
     48                    vectors, {clickout: true} 
     49                ), 
     50                clickoutmulti : new OpenLayers.Control.SelectFeature( 
     51                    vectors, {clickout: true, multiple: true} 
     52                ), 
    4253                hover: new OpenLayers.Control.SelectFeature( 
    4354                    vectors, {hover: true} 
     
    89100        </li> 
    90101        <li> 
    91             <input type="radio" name="type" value="select" id="selectToggle" 
     102            <input type="radio" name="type" value="click" id="clickToggle" 
    92103                   onclick="toggleControl(this);" /> 
    93             <label for="selectToggle">select feature on click</label> 
     104            <label for="clickToggle">select feature on click</label> 
     105        </li> 
     106        <li> 
     107            <input type="radio" name="type" value="multiple" id="multipleToggle" 
     108                   onclick="toggleControl(this);" /> 
     109            <label for="multipleToggle">select multiple features on click</label> 
     110        </li> 
     111        <li> 
     112            <input type="radio" name="type" value="clickout" id="clickoutToggle" 
     113                   onclick="toggleControl(this);" /> 
     114            <label for="clickoutToggle">select feature on click, unselect feature on clickout</label> 
     115        </li> 
     116        <li> 
     117            <input type="radio" name="type" value="clickoutmulti" id="clickoutmultiToggle" 
     118                   onclick="toggleControl(this);" /> 
     119            <label for="clickoutmultiToggle">select multiple features on click, unselect features on clickout</label> 
    94120        </li> 
    95121        <li> 
  • sandbox/elemoine/playground/lib/OpenLayers/Control/DragFeature.js

    r4985 r5335  
    125125                                                    }, this.dragCallbacks); 
    126126        this.dragHandler = new OpenLayers.Handler.Drag(this, this.dragCallbacks); 
    127         this.featureCallbacks = OpenLayers.Util.extend({over: this.overFeature, 
    128                                                         out: this.outFeature 
     127        this.featureCallbacks = OpenLayers.Util.extend({movein: this.overFeature, 
     128                                                        moveout: this.outFeature 
    129129                                                       }, this.featureCallbacks); 
    130130        var handlerOptions = {geometryTypes: this.geometryTypes}; 
  • sandbox/elemoine/playground/lib/OpenLayers/Control/SelectFeature.js

    r5157 r5335  
    2323 
    2424    /** 
     25     * APIProperty: clickout 
     26     * {Boolean} Unselect features when clicking outside any feature. 
     27     */ 
     28    clickout: false, 
     29 
     30    /** 
    2531     * APIProperty: hover 
    2632     * {Boolean} Select on mouse over and deselect on mouse out.  If true, this 
     
    8591        this.layer = layer; 
    8692        this.callbacks = OpenLayers.Util.extend({ 
    87                                                   click: this.clickFeature, 
    88                                                   over: this.overFeature, 
    89                                                   out: this.outFeature 
     93                                                  clickin: this.clickinFeature, 
     94                                                  clickout: this.clickoutFeature, 
     95                                                  movein: this.moveinFeature, 
     96                                                  moveout: this.moveoutFeature 
    9097                                                }, this.callbacks); 
    91         var handlerOptions = {geometryTypes: this.geometryTypes}; 
     98        var handlerOptions = { 
     99            geometryTypes: this.geometryTypes, 
     100            multiple: this.multiple}; 
    92101        this.handler = new OpenLayers.Handler.Feature(this, layer, 
    93102                                                      this.callbacks, 
     
    96105 
    97106    /** 
    98      * Method: clickFeature 
    99      * Called when the feature handler detects a click on a feature 
     107     * Method: unselectAll 
     108     * Unselect all selected features. 
     109     */ 
     110    unselectAll: function() { 
     111        while (this.layer.selectedFeatures.length > 0) { 
     112            this.unselect(this.layer.selectedFeatures[0]); 
     113        } 
     114    }, 
     115 
     116    /** 
     117     * Method: clickinFeature 
     118     * Called on click in a feature 
     119     * Only responds if this.hover is false. 
    100120     * 
    101121     * Parameters: 
    102122     * feature - {<OpenLayers.Vector.Feature>}  
    103123     */ 
    104     clickFeature: function(feature) { 
     124    clickinFeature: function(feature) { 
    105125        if(this.hover) { 
    106126            return; 
    107127        } 
    108128        if (this.multiple) { 
    109             if(OpenLayers.Util.indexOf(this.layer.selectedFeatures, feature) > -1) { 
     129            if(OpenLayers.Util.indexOf(this.layer.selectedFeatures, feature) > -1 && 
     130                !this.clickout) { 
    110131                this.unselect(feature); 
    111132            } else { 
     
    113134            } 
    114135        } else { 
    115             if(OpenLayers.Util.indexOf(this.layer.selectedFeatures, feature) > -1) { 
    116                 this.unselect(feature); 
     136            if(this.clickout) { 
     137                if(OpenLayers.Util.indexOf(this.layer.selectedFeatures, feature) < 0) { 
     138                    this.select(feature); 
     139                } 
    117140            } else { 
    118                 if (this.layer.selectedFeatures) { 
    119                     for (var i = 0; i < this.layer.selectedFeatures.length; i++) { 
    120                         this.unselect(this.layer.selectedFeatures[i]); 
    121                     } 
     141                if(OpenLayers.Util.indexOf(this.layer.selectedFeatures, feature) > -1) { 
     142                     this.unselect(feature); 
     143                } else { 
     144                    this.unselectAll(); 
     145                    this.select(feature); 
    122146                } 
    123                 this.select(feature); 
    124147            } 
    125148        } 
     
    127150 
    128151    /** 
    129      * Method: overFeature 
    130      * Called when the feature handler detects a mouse-over on a feature. 
     152     * Method: clickoutFeature 
     153     * Called on click outside a previously clicked (selected) feature. 
     154     * Only responds if this.hover is false. 
     155     * 
     156     * Parameters: 
     157     * feature - {<OpenLayers.Vector.Feature>}  
     158     */ 
     159    clickoutFeature: function(feature) { 
     160        if(this.hover || !this.clickout) { 
     161            return; 
     162        } 
     163        this.unselectAll(); 
     164    }, 
     165 
     166    /** 
     167     * Method: moveinFeature 
     168     * Called on move in a feature (mouseover). 
    131169     * Only responds if this.hover is true. 
    132170     * 
     
    134172     * feature - {<OpenLayers.Feature.Vector>}  
    135173     */ 
    136     overFeature: function(feature) { 
     174    moveinFeature: function(feature) { 
    137175        if(!this.hover) { 
    138176            return; 
     
    144182 
    145183    /** 
    146      * Method: outFeature 
    147      * Called when the feature handler detects a mouse-out on a feature
     184     * Method: moveoutFeature 
     185     * Called on move out of a selected feature (mouseout)
    148186     * Only responds if this.hover is true. 
    149187     * 
     
    151189     * feature - {<OpenLayers.Feature.Vector>}  
    152190     */ 
    153     outFeature: function(feature) { 
     191    moveoutFeature: function(feature) { 
    154192        if(!this.hover) { 
    155193            return; 
  • sandbox/elemoine/playground/lib/OpenLayers/Handler/Feature.js

    r4985 r5335  
    99 * Class: OpenLayers.Handler.Feature  
    1010 * Handler to respond to mouse events related to a drawn feature. 
    11  * Callbacks will be called for over, move, out, up, down, and click 
    12  * (corresponding to the equivalent mouse events). 
     11 * Callbacks will be called for move, out, up, down, click, and 
     12 * dblclick. 
     13 * 
     14 * The high-level events supported by this handler are: clickin 
     15 * clickout, downin, downout, upin, upout, movein, moveout, 
     16 * dblclickin, and dblclickout. 
    1317 */ 
    1418OpenLayers.Handler.Feature = OpenLayers.Class(OpenLayers.Handler, { 
    1519 
    1620    /** 
     21     * Property: clickFeature 
     22     * {<OpenLayers.Feature.Vector>} 
     23     */ 
     24    clickFeature: null, 
     25 
     26    /** 
     27     * Property: moveFeature 
     28     * {<OpenLayers.Feature.Vector>} 
     29     */ 
     30    moveFeature: null, 
     31 
     32    /** 
     33     * Property: downFeature 
     34     * {<OpenLayers.Feature.Vector>} 
     35     */ 
     36    downFeature: null, 
     37 
     38    /** 
     39     * Property: upFeature 
     40     * {<OpenLayers.Feature.Vector>} 
     41     */ 
     42    upFeature: null, 
     43 
     44    /** 
     45     * Property: dblclickFeature 
     46     * {<OpenLayers.Feature.Vector>} 
     47     */ 
     48    dblclickFeature: null, 
     49 
     50    /** 
     51     * Property: multiple 
     52     * If set to true, the out callback isn't called if out of last 
     53     * feature and in to a new one. 
     54     */ 
     55    multiple: false, 
     56 
     57    /** 
    1758     * To restrict dragging to a limited set of geometry types, send a list 
    1859     * of strings corresponding to the geometry class names. 
     
    2768     */ 
    2869    layerIndex: null, 
    29      
    30     /** 
    31      * Property: feature 
    32      * {<OpenLayers.Feature.Vector>} 
    33      */ 
    34     feature: null, 
    3570     
    3671    /** 
     
    5085    }, 
    5186 
     87 
    5288    /** 
    5389     * Method: click 
    54      * Handle click.  Call the "click" callback if down on a feature. 
    55      *  
    56      * Parameters: 
    57      * evt - {Event}  
     90     * Handle click.  Call the "clickin" callback if click on a feature, 
     91     * or the "clickout" callback if click outside a feature previously 
     92     * clicked in. 
     93     *  
     94     * Parameters: 
     95     * evt - {Event}  
     96     * 
     97     * Returns: 
     98     * {Boolean} 
    5899     */ 
    59100    click: function(evt) { 
    60         var selected = this.select('click', evt); 
    61         return !selected;  // stop event propagation if selected 
    62     }, 
    63  
     101        return !this.handle('click', evt); 
     102    }, 
     103         
    64104    /** 
    65105     * Method: mousedown 
    66      * Handle mouse down.  Call the "down" callback if down on a feature. 
    67      *  
    68      * Parameters: 
    69      * evt - {Event}  
     106     * Handle mouse down.  Call the "downin" callback if down on a feature, 
     107     * or the "downout" callback if down outside a feature previously 
     108     * down'ed in. 
     109     *  
     110     * Parameters: 
     111     * evt - {Event}  
     112     * 
     113     * Returns: 
     114     * {Boolean} 
    70115     */ 
    71116    mousedown: function(evt) { 
    72         var selected = this.select('down', evt); 
    73         return !selected;  // stop event propagation if selected 
     117        return !this.handle('down', evt); 
    74118    }, 
    75119     
    76120    /** 
    77121     * Method: mousemove 
    78      * Handle mouse moves.  Call the "move" callback if moving over a feature. 
    79      * Call the "over" callback if moving over a feature for the first time. 
    80      * Call the "out" callback if moving off of a feature. 
    81      *  
    82      * Parameters: 
    83      * evt - {Event}  
     122     * Handle mouse moves.  Call the "movein" callback if move on a feature, 
     123     * or the "moveout" callback if move outside a feature previously 
     124     * moved in. 
     125     *  
     126     * Parameters: 
     127     * evt - {Event}  
     128     * 
     129     * Returns: 
     130     * {Boolean} 
    84131     */ 
    85132    mousemove: function(evt) { 
    86         this.select('move', evt); 
     133        this.handle('move', evt); 
    87134        return true; 
    88135    }, 
     
    90137    /** 
    91138     * Method: mouseup 
    92      * Handle mouse up.  Call the "up" callback if up on a feature. 
    93      *  
    94      * Parameters: 
    95      * evt - {Event}  
     139     * Handle mouse up.  Call the "upin" callback if up on a feature, 
     140     * or the "upout" callback if up outside a feature previously 
     141     * up'ed in. 
     142     *  
     143     * Parameters: 
     144     * evt - {Event}  
     145     * 
     146     * Returns: 
     147     * {Boolean} 
    96148     */ 
    97149    mouseup: function(evt) { 
    98         var selected = this.select('up', evt); 
    99         return !selected;  // stop event propagation if selected         
     150        return !this.handle('up', evt); 
    100151    }, 
    101152     
    102153    /** 
    103154     * Method: dblclick 
    104      * Capture double-clicks.  Let the event continue propagating if the  
    105      *     double-click doesn't hit a feature.  Otherwise call the dblclick 
    106      *     callback. 
    107      * 
    108      * Parameters: 
    109      * evt - {Event}  
     155     * Handle dblclick.  Call the "dblclickin" callback if dblclick on a feature, 
     156     * or the "dblickout" callback if dblclick outside a feature previously 
     157     * dblclicked in. 
     158     * 
     159     * Parameters: 
     160     * evt - {Event}  
     161     * 
     162     * Returns: 
     163     * {Boolean} 
    110164     */ 
    111165    dblclick: function(evt) { 
    112         var selected = this.select('dblclick', evt); 
    113         return !selected;  // stop event propagation if selected         
    114     }, 
    115  
    116     /** 
    117      * Method: select 
    118      * Trigger the appropriate callback if a feature is under the mouse. 
    119      * 
    120      * Parameters: 
    121      * type - {String} Callback key 
    122      * 
    123      * Returns: 
    124      * {Boolean} A feature was selected 
    125      */ 
    126     select: function(type, evt) { 
     166        return !this.handle('dblclick', evt); 
     167    }, 
     168 
     169    /** 
     170     * Method: geometryTypeMatches 
     171     * Return true if the geometry type of the passed feature matches 
     172     * one of the geometry types in the geometryTypes array. 
     173     * 
     174     * Parameters: 
     175     * feature - {<OpenLayers.Vector.Feature>} 
     176     * 
     177     * Returns: 
     178     * {Boolean} 
     179     */ 
     180    geometryTypeMatches: function(feature) { 
     181        return this.geometryTypes == null || 
     182            OpenLayers.Util.indexOf(this.geometryTypes, 
     183                                    feature.geometry.CLASS_NAME) > -1; 
     184    }, 
     185 
     186    /** 
     187     * Method: handle 
     188     * 
     189     * Parameters: 
     190     * type - {String} the low-level event type 
     191     * evt - {Event} 
     192     * 
     193     * Returns: 
     194     * {Boolean} 
     195     */ 
     196    handle: function(type, evt) { 
    127197        var feature = this.layer.getFeatureFromEvent(evt); 
    128         var selected = false; 
    129         if(feature) { 
    130             if(this.geometryTypes == null || 
    131                (OpenLayers.Util.indexOf(this.geometryTypes, 
    132                                         feature.geometry.CLASS_NAME) > -1)) { 
    133                 // three cases: 
    134                 // over a new, out of the last and over a new, or still on the last 
    135                 if(!this.feature) { 
    136                     // over a new feature 
    137                     this.callback('over', [feature]); 
    138                 } else if(this.feature != feature) { 
    139                     // out of the last and over a new 
    140                     this.callback('out', [this.feature]); 
    141                     this.callback('over', [feature]); 
     198        var lastFeature = this[type + 'Feature']; 
     199        var stopEvtPropag = false; 
     200        if (feature) { 
     201            if (this.geometryTypeMatches(feature)) { 
     202                if (lastFeature && (lastFeature != feature) && !this.multiple) { 
     203                    this.callback(type + 'out', [lastFeature]); 
    142204                } 
    143                 this.feature = feature
    144                 this.callback(type, [feature])
    145                 selected = true; 
     205                this.callback(type + 'in', [feature])
     206                lastFeature = feature
     207                stopEvtPropag = true; 
    146208            } else { 
    147                 if(this.feature && (this.feature != feature)) { 
    148                     // out of the last and over a new 
    149                     this.callback('out', [this.feature]); 
    150                     this.feature = null; 
     209                if (lastFeature && (lastFeature != feature)) { 
     210                    this.callback(type + 'out', [lastFeature]); 
     211                    lastFeature = feature; 
    151212                } 
    152                 selected = false; 
    153213            } 
    154214        } else { 
    155             if(this.feature) { 
    156                 // out of the last 
    157                 this.callback('out', [this.feature]); 
    158                 this.feature = null; 
     215            if (lastFeature) { 
     216                this.callback(type + 'out', [lastFeature]); 
     217                lastFeature = null; 
    159218            } 
    160             selected = false; 
    161219        } 
    162         return selected; 
     220        this[type + 'Feature'] = lastFeature; 
     221        return stopEvtPropag; 
    163222    }, 
    164223 
  • sandbox/elemoine/playground/tests/Handler/test_Feature.html

    r4243 r5335  
    100100  
    101101    function test_Handler_feature_geometrytype_limit(t) { 
    102         t.plan(2); 
     102        t.plan(1); 
    103103        var feature = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(0,0)); 
    104104        var map = new OpenLayers.Map('map'); 
     
    113113            t.eq(featurelist[0].id, feature.id, "Correct feature called back on"); 
    114114        } 
    115         handler.select("foo", {});  
    116         handler.feature = null; 
     115        handler.handle("click", {});  
     116        handler.clickFeature = null; 
    117117        handler.callback = function(type,featurelist) { 
    118118            t.fail("Shouldn't have called back on " + featurelist[0].geometry); 
    119119        }     
    120120        feature = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString(0,0)); 
    121         handler.select("foo", {});  
     121        handler.handle("click", {});  
    122122    } 
    123123    function test_Handler_Feature_callbacks(t) { 
    124         t.plan(75); 
     124        t.plan(50); 
    125125         
    126126        var map = new OpenLayers.Map('map', {controls: []}); 
     
    181181            handler.feature = null; 
    182182  
    183             numEvents[evtShortName] = 0; 
    184             numEvents["over"] = 0; 
    185             numEvents["out"] = 0; 
     183            numEvents[evtShortName + "in"] = 0; 
     184            numEvents[evtShortName + "out"] = 0; 
    186185            oldFeature = null; 
    187186            newFeature = new OpenLayers.Feature.Vector(); 
    188             callbacks[evtShortName] = getCallback(evtShortName, newFeature); 
    189             callbacks["over"] = getCallback("over", newFeature); 
    190             callbacks["out"] = getCallback("out", oldFeature); 
     187            callbacks[evtShortName + "in"] = getCallback(evtShortName + "in", newFeature); 
     188            callbacks[evtShortName + "out"] = getCallback(evtShortName + "out", oldFeature); 
    191189            map.events.triggerEvent(evtLongName, evtPx); 
    192             t.ok(numEvents[evtShortName] == 1, evtShortName + " triggered click callback"); 
    193             t.ok(numEvents["over"] == 1, evtShortName + " triggered over callbacks"); 
    194             t.ok(numEvents["out"] == 0, evtShortName + " did not trigger out callback"); 
    195   
    196             numEvents[evtShortName] = 0; 
    197             numEvents["over"] = 0; 
    198             numEvents["out"] = 0; 
     190            t.ok(numEvents[evtShortName + "in"] == 1, evtLongName + " triggered " + evtShortName + "in callback"); 
     191            t.ok(numEvents[evtShortName + "out"] == 0, evtLongName + " did not trigger " + evtShortName + "out callback"); 
     192  
     193            numEvents[evtShortName + "in"] = 0; 
     194            numEvents[evtShortName + "out"] = 0; 
    199195            oldFeature = newFeature; 
    200196            newFeature = new OpenLayers.Feature.Vector(); 
    201             callbacks[evtShortName] = getCallback(evtShortName, newFeature); 
    202             callbacks["over"] = getCallback("over", newFeature); 
    203             callbacks["out"] = getCallback("out", oldFeature); 
     197            callbacks[evtShortName + "in"] = getCallback(evtShortName + "in", newFeature); 
     198            callbacks[evtShortName + "out"] = getCallback(evtShortName + "out", oldFeature); 
    204199            map.events.triggerEvent(evtLongName, evtPx); 
    205             t.ok(numEvents[evtShortName] == 1, evtShortName + " triggered click callback"); 
    206             t.ok(numEvents["over"] == 1, evtShortName + " triggered over callbacks"); 
    207             t.ok(numEvents["out"] == 1, evtShortName + " triggered out callback"); 
    208   
    209             numEvents[evtShortName] = 0; 
    210             numEvents["over"] = 0; 
    211             numEvents["out"] = 0; 
    212             oldFeature =  newFeature; 
    213             callbacks[evtShortName] = getCallback(evtShortName, newFeature); 
    214             callbacks["over"] = getCallback("over", newFeature); 
    215             callbacks["out"] = getCallback("out", oldFeature); 
     200            t.ok(numEvents[evtShortName + "in"] == 1, evtLongName + " triggered " + evtShortName + "in callback"); 
     201            t.ok(numEvents[evtShortName + "out"] == 1, evtLongName + " triggered " + evtShortName + "out callback"); 
     202  
     203            numEvents[evtShortName + "in"] = 0; 
     204            numEvents[evtShortName + "out"] = 0; 
     205            oldFeature = newFeature; 
     206            callbacks[evtShortName + "in"] = getCallback(evtShortName + "in", newFeature); 
     207            callbacks[evtShortName + "out"] = getCallback(evtShortName + "out", oldFeature); 
    216208            map.events.triggerEvent(evtLongName, evtPx); 
    217             t.ok(numEvents[evtShortName] == 1, evtShortName + " triggered click callback"); 
    218             t.ok(numEvents["over"] == 0, evtShortName + " did not trigger over callbacks"); 
    219             t.ok(numEvents["out"] == 0, evtShortName + " did not trigger out callback"); 
     209            t.ok(numEvents[evtShortName + "in"] == 1, evtLongName + " triggered " + evtShortName + "in callback"); 
     210            t.ok(numEvents[evtShortName + "out"] == 0, evtLongName + " did not trigger " + evtShortName + "out callback"); 
    220211        } 
    221212    }