Time For Action – using the SelectFeature control

Time For Action – using the SelectFeature control


Let's put together a few things we've learned so far. We'll create some points and a polygon, place it on the map, and use the SelectFeature control to allow the user to select them. We'll register the featureselected and featureunselected events so that we can fire an event when the user interacts with a feature. When those events are fired, we'll access the feature's attributes object and display information from it. Let's do it.

  1. We'll be adding a vector layer, some features, and a SelectFeature control. The file will be referred to as chapter9_selectFeature.html.

  2. First, let's make vector_layer a global variable like we did earlier in this chapter. Place this outside the init function, right after var map;.

    var vector_layer;
  3. Next, we'll add a <div> element that we'll output feature info to when the user clicks on a feature. Add this div after the map div:

    <div id='map_feature_log'></div>
  4. Now, back to the init function code. Add the vector layer after the WMS layer is added to the map:

    vector_layer = new OpenLayers.Layer.Vector('Basic Vector Layer');
    map.addLayer(vector_layer);
  5. Now, let's add some features. We'll add two point features and one polygon feature. We'll pass in an attributes object (an object with key:value pairs to store data) to each feature. Let's first create the two point features:

      var feature_point_1 = new OpenLayers.Feature.Vector( 
        new OpenLayers.Geometry.Point(6.055, 46.234), 
        { 
            'location': 'Cern', 
            'description': "Stand back, I'm going to try science!" 
        } 
      ); 
      var feature_point_2 = new OpenLayers.Feature.Vector( 
        new OpenLayers.Geometry.Point(-129, 3), 
        { 
            'location': 'The Sea', 
            'description': 'Here be dragons' 
        }
      );
  6. Notice how we passed in two key:value pairs—location and description. These are just arbitrary keys and values—you can use whatever you like, and we'll see how to access them in a minute. First though, let's add a polygon feature. To do so, remember—we'll need to pass in an array of points into a LinearRing object, then pass that LinearRing object into the Polygon class to instantiate it. Whew. It's easier than it sounds:

    var feature_polygon = new OpenLayers.Feature.Vector( 
          //We'll make a polygon from a linear ring object, which consists of points 
        new OpenLayers.Geometry.Polygon(new OpenLayers.Geometry.LinearRing( 
        [ 
            new OpenLayers.Geometry.Point(-124.2, 41.9), 
            new OpenLayers.Geometry.Point(-120.1, 41.9), 
            new OpenLayers.Geometry.Point(-120, 39), 
            new OpenLayers.Geometry.Point(-114.5, 34.9), 
            new OpenLayers.Geometry.Point(-114.7, 32.7), 
            new OpenLayers.Geometry.Point(-117.1, 32.5), 
            new OpenLayers.Geometry.Point(-120, 34), 
            new OpenLayers.Geometry.Point(-123.7, 38.4) 
            //We won't pass in the first point, the polygon will close automatically 
        ] 
        )), 
        { 
            'location': 'Fanghorn Forest', 
            'description': 'Land of the Ents' 
        } 
      );
    
  7. Now we add the features to the map:

    vector_layer.addFeatures([feature_point_1, feature_point_2, feature_polygon]);
  8. Alright—nothing too new so far. Take a look at the map, and you should see the features. We can't yet interact with them though.

  9. Now, let's make the features interactive. To do so, we'll first need a SelectFeature control. When we instantiate it, we pass in the vector layer that we want the control to use (alternatively, we could pass in an {Array} of vector layers if we wanted the control to use multiple vector layers). We'll also pass in a couple properties, which we'll cover in more detail after this example. The multiple property will allow multiple features to be selected at once, the toggle property will cause features to be unselected when selecting a different feature, and the multipleKey specifies which key to press to allow multiple features to be selected:

      var select_feature_control = new OpenLayers.Control.SelectFeature( 
        vector_layer, 
        { 
          multiple: false, 
          toggle: true,
          multipleKey: 'shiftKey'
        } 
      ); 
      map.addControl(select_feature_control);
  10. At this point, the control is created and has been added to the map. However, before we can use it we must activate it by calling its activate method.

    select_feature_control.activate();
  11. Now we can select our features. Because we passed in the multipleKey property, we can select multiple controls by holding Shift and clicking on them. Holding control will toggle a feature selection. Click on a feature to see:

  12. Now, let's do something when the user clicks on a feature. To do this, we'll create two functions that will be called when the featureselected and featureunselected events are fired (they get fired from the SelectFeature control). First let's create the function to call when a feature is selected. It will clear the map_feature_log div and then look at the attributes object of the passed in feature. Finally, it will loop through all selected features and display the location property of all selected features.

    function selected_feature(event){ 
          //clear out the log's contents 
          document.getElementById('map_feature_log').innerHTML = ''; 
          
          //Show the current selected feature (passed in from the event object) 
          var display_text = 'Clicked on: ' 
              + '<strong>' + event.feature.attributes.location + '</strong>' 
              + ': ' + event.feature.attributes.description + '<hr />'; 
        document.getElementById('map_feature_log').innerHTML = display_text; 
         
        //Show all the selected features 
        document.getElementById('map_feature_log').innerHTML += 'All selected features: '; 
    
        //Now, loop through the selected feature array 
        for(var i=0; i<vector_layer.selectedFeatures.length; i++){ 
                document.getElementById('map_feature_log').innerHTML += 
                    vector_layer.selectedFeatures[i].attributes.location + ' | '; 
            }
      }
  13. We need a function to call when a feature is unselected now. It will do a similar thing to the previous function—display the feature the user clicked on, then show all the selected features.

      function unselected_feature(event){ 
          var display_text = event.feature.attributes.location + ' unselected!' + '<hr />'; 
        document.getElementById('map_feature_log').innerHTML = display_text; 
     
        //Show all the selected features 
        document.getElementById('map_feature_log').innerHTML += 'All selected features: '; 
         
        //Now, loop through the selected feature array 
        for(var i=0; i<vector_layer.selectedFeatures.length; i++){ 
                document.getElementById('map_feature_log').innerHTML += 
                    vector_layer.selectedFeatures[i].attributes.location + ' | '; 
            } 
      }
  14. Just one more thing now! We have to register the events to call those functions when a feature is selected or unselected:

    vector_layer.events.register('featureselected', this, selected_feature); 
    vector_layer.events.register('featureunselected', this, unselected_feature);
  15. All done! Open up your map and select some features (use Shift to select multiple features). You should see the log update:

What Just Happened?

We just demonstrated how to use the SelectFeature control with some feature data. We'll be doing much more with the SelectFeature control and features throughout the remainder of the book, so if you aren't totally comfortable with it don't sweat it too much. Try to create your own functions and features. To do that, you'll need to know a little bit more about the SelectFeature class and what some of the properties of it are. Let's quickly go over them.

Control.SelectFeature class

First we'll cover the properties then look at some methods of the SelectFeature class.

SelectFeature control properties

  • box: {Boolean} Specifies whether features can be selected by drawing a box. Set to false by default. If set to true, when activating the SelectFeature control object, you'll be able to draw a box to select features instead of clicking on features to select them.

  • clickout: {Boolean} Determines if features will be unselected when clicking outside of any feature. Default is false.

  • geometryType: {Array{String}} An array of strings which specify the only geometry types that the feature will be able to select. Each string should be the name of a Geometry class. By default, null is specified for this property, meaning all geometry types can be selected. For example, if you wanted the control to only allow the selection of Point objects, you would pass in this property like:

    geometryTypes: ['OpenLayers.Geometry.Point']
  • handlers: {Object} This contains a reference to handler object instances.

  • highlightOnly: {Boolean} This specifies whether features can be selected, or if features can only be highlighted. Set to false by default. If hover is set to true, this will do nothing.

  • hover: {Boolean} Set to false by default. If this is set to true, features will be selected (and added to the vector_layer.features array) when the user mouse overs a feature—clicking on a feature will do nothing, only mousing over them will.

  • layer: {OpenLayers.Layer.Vector} or {Array{OpenLayers.Layer.Vector}} Specifies the vector layer(s) the selectFeature control is associated with.

  • multiple: {Boolean} Controls whether or not multiple features will be selected by clicking on them. Default is false. This does not mean multiple features can never be selected (you can use the multipleKey to select multiple features even if this is set to false). If set to true, features will not be unselected when clicking on other features.

  • multipleKey: {String} Specifies a key to be used to allow for multiple selection of features. When holding down the key, multiple features can be selected. An example would be multipleKey: 'shiftKey' or 'altKey'. Default value is null.

  • onBeforeSelect: {Function} Function to be called before a feature is selected. By default, this is an empty function.

  • onSelect: {Function} Function to be called when a feature is selected. By default, this is an empty function.

  • onUnselect: {Function} Function to be called when a feature is unselected. By default, this is an empty function.

  • renderIntent: {String} Used to get the style to use from the style map of the layer. Styles are covered in Chapter 10.

  • selectStyle: {Object} Contains an object of styles. Styles are discussed later in this chapter.

  • toggle: {Boolean} Determines whether or not to unselect a selected feature when the feature is clicked. Default value is false. If the hover property is set to true, this will do nothing.

  • toggleKey: {String} Specifies a key that, when held down, will set the toggle property to true. When the key is released, the toggle property will be set back to false. An example would be multipleKey: 'altKey'. Default value is null.

These properties can be set when instantiating a SelectFeature control. To create a SelectFeature control object, the form for calling it is:

var select_feature_control = new OpenLayers.Control.SelectFeature(
  vector_layer, 
  {}
);

The {} is the optional options object which can be filled with the properties we just discussed. Now, let's take a look at some of the methods of the SelectFeature control.

SelectFeature control methods

Let's just take a look at a few methods that we'll be using throughout the rest of the book.

  • activate(): Activates the control, allowing us to use it.

  • deactivate(): Deactivates the control. After calling, features cannot be selected until the control is activated again.

  • highlight(feature): Draws the passed in feature with the feature's select style.

  • unhighlight(feature): Draws the passed in feature with the feature's normal style.

  • select(feature): Selects a passed in feature object, adding it to the layer's selectedFeature array, calling the onSelect method, and rendering the feature as selected (applying any styles, etc.).

  • unselect(feature): Unselects a passed in feature object, removing it from the layer's selectedFeature array, calling the onUnselect method, and rendering the feature back to its normal state (applying any styles, etc.).

  • unselectAll(options): Calling this will unselect all features currently selected by the control. If you wish to unselect everything except a specific feature, pass it in to the options parameter as an except property.

That ends our discussion of the Feature and Geometry classes. Next, we'll be diving into the Vector class again—but this time, we'll focus on the more advanced uses.