The capability to measure distances or areas is an important thing on many GIS applications.
In this recipe, we are going to see in action what the Measure control in OpenLayers offers to the developer.
The application will show a simple map with some buttons on top, as shown in the following screenshot. The Measure toggle button activates or deactivates the control, while the radio buttons bring us the possibility to select what to measure: a path or an area:
In addition, we can set two control options. The Geodesic control indicates if the distance of the area computation must be in geodesic metrics instead of planar. The Immediate option is useful to update the measure every time we move the mouse.
Here, we are going to write not the whole source code but only those pieces of code that are important for the recipe. So, we are avoiding putting here the HTML code required to build the measure button, checkboxes, options radio buttons, and the div
element that holds the map instance.
var map = new OpenLayers.Map("ch05_measure"); var osm = new OpenLayers.Layer.OSM(); map.addLayer(osm); map.addControl(new OpenLayers.Control.LayerSwitcher()); map.setCenter(new OpenLayers.LonLat(0, 0), 3);
measure
and measurepartial
:var measureControl = new OpenLayers.Control.Measure(OpenLayers.Handler.Path, { persist: true, eventListeners: { 'measure': measure, 'measurepartial': measurepartial } });
function measureClick(checked) { var path = dijit.byId('path').get('checked'), var polygon = dijit.byId('polygon').get('checked'), var regular = dijit.byId('regular').get('checked'), if(checked){ if(path) { measureControl.updateHandler(OpenLayers.Handler.Path, {persist: true}); } else if(polygon) { measureControl.updateHandler(OpenLayers.Handler.Polygon, {persist: true}); } else if(regular) { measureControl.updateHandler(OpenLayers.Handler.RegularPolygon, {persist: true}); } map.addControl(measureControl); measureControl.activate(); } else { measureControl.deactivate(); map.removeControl(measureControl); } dojo.byId('value').innerHTML = ""; }
measure
and measurepartial
control events:function measure(event) { var message = event.measure + " " + event.units; if(event.order>1) { message += "2"; } dojo.byId('value').innerHTML = message; } function measurepartial(event) { var message = event.measure + " " + event.units; dojo.byId('value').innerHTML = message; }
function changeImmediate(checked) { measureControl.setImmediate(checked); } function changeGeodesic(checked) { measureControl.geodesic = checked; }
Let's start analyzing how we initialized the measure control:
var measureControl = new OpenLayers.Control.Measure(OpenLayers.Handler.Path, { persist: true, eventListeners: { 'measure': measure, 'measurepartial': measurepartial } });
The only parameter we need to pass to the control is a handler to be used.
Like many other controls, the OpenLayers.Control.Measure
class makes use of handlers to interact with the map. In this case, the measure control can make use of any handler that allows to draw geometries. To summarize, the flow is as follows:
Actually, we have a limitation to use handlers that return geometries that implement the getArea()
or getLength()
methods. For example, if you try to use the OpenLayers.Handler.Box
handler with the measure control, once you activate the control and draw a box, you will get an error in the browser console. This is because the box handler returns an OpenLayers.Bounds
instance that neither has a getLength
nor getArea
method.
In our code we have initialized the measure control setting as follows:
persist
property to true
. This property indicates that the geometry created by the handler must remain on the map until a new measure starts.measure
and measurepartial
. The measure
event is triggered once the measure action has been finished. The measurepartial
is triggered on any measure update (only if the immediate
property is true).When the Measure toggle button is pressed, the
measureClick
function is executed. This function checks what kind of handler must be used for the measurement and sets it on the control.
This can be done by the
updateHandler
method on the Measure control. For example:
measureControl.updateHandler(OpenLayers.Handler.Polygon, {persist: true});
In addition, the measureClick
function adds the control to the map and activates when the button is toggled on, or deactivates and removes the control from the map when the button is toggled off.
For the control options buttons, we have set two listening functions associated to the checkboxes.
When the Immediate checkbox changes, the changeImmediate
function is executed. This, using the
setImmediate
method, changes the immediate
property of the control, which allows triggering events every time the measure updates with a mouse movement:
function changeImmediate(checked) { measureControl.setImmediate(checked); }
The Geodesic checkbox sets the value of the
geodesic
property. This time we can modify the property directly without the need of a setter function:
function changeGeodesic(checked) { measureControl.geodesic = checked; }
With the geodesic
property set to true
, the control will use a geodesic metric instead of a planar metric to compute the measures.
An important part of the measurement is done with the geometric instances.
All the geometry classes, such as OpenLayers.Geometry.Polygon
or OpenLayers.Geometry.LineString
, contain methods to compute their area or length.
Looking at the measure control source code, we can see how once its associated handler returns a geometry, it simply calls the geometry methods to get the area or length and triggers an event.
18.227.10.45