When developing a web mapping application, the use of OpenLayers is only a piece among the set of tools that we need to use. Adding other components, such as buttons, images, lists, and so on, and interacting with them are other tasks that we must work on.
Interacting with a OpenLayers.Map
instance or OpenLayers.Layer
subclass is easy because they trigger specific events, but what if we want to listen for events on a button or any DOM
element?
For this purpose, OpenLayers offers us the OpenLayers.Event
class (do not get confused with the plural OpenLayers.Events
class). This is a helper class, which, among other things, allows us to listen for events in non-OpenLayers elements in a browser-independent way.
Unfortunately the way to register event listeners in JavaScript is not the same in all browsers. Also, Microsoft differs from W3C (the WWW Consortium) in the way to register listeners. You can find more information at http://www.quirksmode.org/js/events_advanced.html.
If your project uses a library or framework such as jQuery, Dojo, or ExtJS, you will probably use their features to access DOM elements, register for events, and so on.
If you are working on a simpler project without the aforementioned libraries, it is a good idea to register events through the OpenLayers.Event
class, because it is browser-independent, which means your application will be compatible with more browsers.
In addition, there is one more reason to read this recipe and the reason is that OpenLayers uses the OpenLayers.Event
class internally to implement many handlers and controls, which we will see in the future chapters.
Let's have a look at how we can listen for events on HTML elements through the OpenLayers.Event
class.
The idea is to create six buttons and add six point features to a vector layer. Then highlight the feature when mouse enters a button or unselect if mouse leaves it.
To listen for non-OpenLayers events, follow the next steps:
<style> .square { border: 1px solid #888; background-color: #0099FF; color: #fff; padding: 3px; } .square:hover { background-color: #0086d2; } </style>
span
element with an identifier:<table> <tr> <td><span id="f0" class="square">Feature 1</span></td> <td><span id="f1" class="square">Feature 2</span></td> <td><span id="f2" class="square">Feature 3</span></td> <td><span id="f3" class="square">Feature 4</span></td> <td><span id="f4" class="square">Feature 5</span></td> <td><span id="f5" class="square">Feature 6</span></td> </tr> </table> <br/>
div
element to hold the map:<div id="ch04_dom_events" style="width: 100%; height: 100%;"></div>
<!-- The magic comes here --> <script type="text/javascript"> // Create left map var map = new OpenLayers.Map("ch04_dom_events"); var osm = new OpenLayers.Layer.OSM(); // Create a vector layer with one feature for each previous SPAN element var vectorLayer = new OpenLayers.Layer.Vector("Features");
var pointFeatures = []; for(var i=0; i< 6; i++) { // Create the ID var id = "f"+i; // Regiter listeners to handle when mouse enters and leaves the DOM element OpenLayers.Event.observe(OpenLayers.Util.getElement(id), 'mouseover', mouseOverListener); OpenLayers.Event.observe(OpenLayers.Util.getElement(id), 'mouseout', mouseOutListener); // Create a random point var px = Math.random()*360-180; var py = Math.random()*160-80; var pointGeometry = new OpenLayers.Geometry.Point(px, py); OpenLayers.Projection.transform(pointGeometry, new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913")); var pointFeature = new OpenLayers.Feature.Vector(pointGeometry, { elem_id: id }); pointFeatures.push(pointFeature); } vectorLayer.addFeatures(pointFeatures); map.addLayers([osm, vectorLayer]); map.setCenter(new OpenLayers.LonLat(0, 0), 1);
// Listeners function mouseOverListener(event) { var id = event.target.id; var feature = vectorLayer.getFeaturesByAttribute('elem_id', id); vectorLayer.drawFeature(feature[0], "select"); } function mouseOutListener(event) { var id = event.target.id; var feature = vectorLayer.getFeaturesByAttribute('elem_id', id); vectorLayer.drawFeature(feature[0], "default"); } </script>
We have created six buttons, identified from f0
to f5
, and we want to create six features that represent them. To do this, in the for
loop, first we create a string with an identifier:
var id = "f"+i;
Then, register an event listener function for the mouseover
and mouse
out
events:
OpenLayers.Event.observe(OpenLayers.Util.getElement(id), 'mouseover', mouseOverListener); OpenLayers.Event.observe(OpenLayers.Util.getElement(id), 'mouseout', mouseOutListener);
This is done by using the OpenLayers.Event.observe
method, which requires three parameters. These parameters are as follows:
elementParam
: The DOM
element reference, or its identifier, which we want to listen to for tis
eventsname
: The event you want to listen toobserver
: The function that will act as a listenerBecause we need to pass the DOM
element reference, we need to get it first. To get an element reference when its identifier is available, we can use the helper method OpenLayers.Util.getElement
.
From the elementParam
definition, you can see that the use of OpenLayers.Util.getElement
is not strictly necessary. If we pass an ID, the OpenLayers.Event.observe
method will internally use the OpenLayers.Util.getElement
function to get the element reference, so the next two lines will have the same result:
OpenLayers.Event.observe(id, 'mouseover', mouseOverListener); OpenLayers.Event.observe(OpenLayers.Util.getElement(id), 'mouseover', mouseOverListener);
Once the listeners are registered, we create a random point feature and add it to the vector layer:
var px = Math.random()*360-180; var py = Math.random()*160-80; var pointGeometry = new OpenLayers.Geometry.Point(px, py);
Remember to transform the point coordinates to the projection used by the map. In this case, because the base layer is OSM and the map has no specified projection property, the OSM projetion will be used:
OpenLayers.Projection.transform(pointGeometry, new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913")); var pointFeature = new OpenLayers.Feature.Vector(pointGeometry, { elem_id: id }); pointFeatures.push(pointFeature);
We have created the feature by passing a custom attribute elem_id
, which will store the identifier of the button that represents the feature. This way we have a reference to connect the feature and the button.
The following screenshot shows how custom attributes are stored within the feature attributes
property:
At this point we have six buttons and six features, which store the corresponding button identifiers as the custom attributes. Now, the task is to implement the listener function. Let's have a look at the mouseOverListener
function.
function mouseOverListener(event) { var id = event.target.id; var feature = vectorLayer.getFeaturesByAttribute('elem_id', id); vectorLayer.drawFeature(feature[0], "select"); }
From the event, which is a browser MouseEvent
, we get the identifier of the target element that has triggered the event:
var id = event.target.id;
Next, using the OpenLayers.Layers.Vector.getFeatureByAttribute
method, we get an array of features within the vector layer that has the elem_id
with the value id
. Of course, here it will always return an array with only one element:
var feature = vectorLayer.getFeaturesByAttribute('elem_id', id);
Now, we have the feature. Simply redraw it with a different render intent. Select to highlight the feature as selected and put its style back to default:
vectorLayer.drawFeature(feature[0], "select");
We will see more about styling features in Chapter 7, Styling Features. Meanwhile, consider render intents as predefined styles to render features.
OpenLayers defines a global variable $
, which points to the OpenLayers.Util.getElement
function, if it does not exist. This way we can get a reference to an element in a short way.
For example, the next two lines have the same result:
$("some_ID") OpenLayers.Util.getElement("some_ID")
Be careful with the use of the $
function. Many JavaScript libraries, one of the most known is jQuery library (http://jquery.com), also define the global $
object as a common way to operate with it. So, check twice the order in which you have imported libraries on your application and where the $
function really points.
As a curiosity, while getting an element reference by its identifier with OpenLayers.Util.getElement
written:
$("some_ID")
jQuery library requires you to use the #
character:
$("#some_ID")
We can be interested in observing some event, in the same way, we can also have a desire to stop observing it.
Similar to the
OpenLayers.Event.observe
method, given an element reference or a string identifier, the OpenLayers.Event.stopObservingElement
method allows us to stop observing some DOM
element.
3.133.158.32