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.
We'll be adding a vector layer, some features, and a SelectFeature control. The file will be referred to as chapter9_selectFeature.html
.
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;
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>
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);
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' } );
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' } );
Now we add the features to the map:
vector_layer.addFeatures([feature_point_1, feature_point_2, feature_polygon]);
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.
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);
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();
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:
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 + ' | '; } }
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 + ' | '; } }
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);
All done! Open up your map and select some features (use Shift to select multiple features). You should see the log update:
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.
First we'll cover the properties then look at some methods of the SelectFeature class.
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.
Let's just take a look at a few methods that we'll be using throughout the rest of the book.
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.