Listening for non-OpenLayers events

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.

Note

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.

Listening for non-OpenLayers events

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.

How to do it...

To listen for non-OpenLayers events, follow the next steps:

  1. Create an HTML with OpenLayers library dependency. Start adding some CSS styles for the buttons. The following code defines a style when the buttons are not selected (the mouse is out) and also a style with different background color when mouse is hovered over the buttons:
    <style>
        .square {
            border: 1px solid #888;
            background-color: #0099FF;
            color: #fff;
            padding: 3px;
        }
        .square:hover {
            background-color: #0086d2;
        }
    </style>
  2. Create a table to hold the six buttons. A button will be represented by a 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/>
  3. Add a div element to hold the map:
    <div id="ch04_dom_events" style="width: 100%; height: 100%;"></div>
  4. Now, add the JavaScript code required to instantiate the map object, set a base layer, and add a vector layer:
    <!-- 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");
  5. Populate the vector layer with six features. Each one will contain the identifier of the button that represents it:
        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);
  6. Finally, add the code that implements the event listeners:
        // 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>

How it works...

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 events
  • name: The event you want to listen to
  • observer: The function that will act as a listener

Because 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);

Note

The OpenLayers.Util class has plenty of methods to help in working with the DOM elements, arrays, and many more functions. We encourage you to take a look.

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:

How it works...

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");

Note

We will see more about styling features in Chapter 7, Styling Features. Meanwhile, consider render intents as predefined styles to render features.

There's more...

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")

Stop observing

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.

See also

  • The Creating features programmatically recipe in Chapter 3, Working with Vector Layers
  • The Styling features using symbolizers recipe in Chapter 7, Styling Features
  • The Creating a side-by-side map comparator recipe
  • The Listening for vector layer features' events recipe
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.158.32