In contrast to other JavaScript mapping libraries, OpenLayers allows working with a great number of projections.
Usually, we specify the desired projection for the map. Later when adding a vector layer to the map, we need to specify to the layer projection so that OpenLayers transforms features from the layer's projection to the map's projection.
But, by default, OpenLayers has a great limitation on projections: we can only use EPSG:4326 and EPSG:900913. Why? Because transforming between projections is not a simple task and there are other great projects that can make it.
So, when we want to work with projections other than EPSG:4326 and EPSG:900913, OpenLayers uses Proj4js Library (http://trac.osgeo.org/proj4js).
Teaching about projections is out of the scope of this book. The EPSG codes are simply a standardized way to classify and identify the great amount of available projections. EPSG:4326 corresponds to the WGS84 (World Geodetic System) and EPSG:900913 is the Spherical Mercator projection popularized by their use in Google Maps.
Let's go to see how we can integrate Proj4js with OpenLayers and how easy it is to make use of it. The idea is to create an application that shows a map and a text area that will show the coordinates of the clicked location:
We must place some of the available Proj4js files at our web application directory. To do so, perform the following steps:
proj4js-compressed.js
file and defs
folder within your web application folderProj4js
library:<script type="text/javascript" src="./js/proj4js-1.1.0/proj4js-compressed.js"></script>
<textarea id="textarea" name="textarea" data-dojo-type="dijit.form.SimpleTextarea" rows="4" cols="80"></textarea> <br/><br/> <div id="ch08_projections" style="width: 100%; height: 85%;"></div>
<script type="text/javascript"> // Create the click control OpenLayers.Control.Click = OpenLayers.Class(OpenLayers.Control, { defaultHandlerOptions: { 'single': true, 'double': false, 'pixelTolerance': 0, 'stopSingle': false, 'stopDouble': false }, initialize: function(options) { this.handlerOptions = OpenLayers.Util.extend({}, this.defaultHandlerOptions); OpenLayers.Control.prototype.initialize.apply(this, arguments); this.handler = new OpenLayers.Handler.Click( this, { 'click': this.trigger }, this.handlerOptions); },
trigger
function, add the following code to transform and show the coordinates in the textarea
object:trigger: function(e) { var lonlatS = map.getLonLatFromViewPortPx(e.xy); var lonlatT1 = lonlatS.clone().transform( map.getProjectionObject(), new OpenLayers.Projection("EPSG:41001") ); var lonlatT2 = lonlatS.clone().transform( map.getProjectionObject(), new OpenLayers.Projection("EPSG:4326") ); var message = "Click at: "+ "Lon: " + lonlatS.lon + " , Lat: "+lonlatS.lat + " ("+map.getProjection()+") " + "Lon: " + lonlatT2.lon + " , Lat: "+lonlatT2.lat + " (EPSG:4326) " + "Lon: " + lonlatT1.lon + " , Lat: "+lonlatT1.lat + " (EPSG:41001) "; dijit.byId("textarea").set('value', message); }, CLASS_NAME: "OpenLayers.Control.Click" });
var map = new OpenLayers.Map("ch08_projections"); var osm = new OpenLayers.Layer.OSM(); map.addLayer(osm); map.setCenter(new OpenLayers.LonLat(0,0), 2);
var click = new OpenLayers.Control.Click(); map.addControl(click); click.activate(); </script>
OpenLayers makes use of the Proj4js code internally when available. So as OpenLayers developers we do not need to use the Proj4js API directly, the only requirement is to add the Proj4js dependency in our application:
<script type="text/javascript" src="./js/proj4js-1.1.0/proj4js-compressed.js"></script>
When the user clicks at some place on the map, the click control (that we will see later) executes the trigger
function. The e
variable contains all the click event's information that includes the pixel's xy position.
trigger: function(e) { var lonlatS = map.getLonLatFromViewPortPx(e.xy); var lonlatT1 = lonlatS.clone().transform( map.getProjectionObject(), new OpenLayers.Projection("EPSG:41001") ); var lonlatT2 = lonlatS.clone().transform( map.getProjectionObject(), new OpenLayers.Projection("EPSG:4326") ); … ...
Given an OpenLayers.LonLat
instance, we can translate among projections using the tranform()
method.
Thanks to the OpenLayers.Map.getLonLatFromViewPortPx()
method we can go from OpenLayers.Pixel
to the OpenLayers.LonLat
instance.
Because the transform method modifies the current instance, we create a new one using the clone()
method to avoid modifying the source variable.
At this point, the trigger
method can construct a message string and place it within the text area.
Finally, let's briefly describe the click control used in the recipe.
The first step is to define the new control as a subclass of the OpenLayers.Control
class:
OpenLayers.Control.Click = OpenLayers.Class(OpenLayers.Control, {
The control will use an OpenLayers.Handler
, so here we will define some options:
defaultHandlerOptions: { 'single': true, 'double': false, 'pixelTolerance': 0, 'stopSingle': false, 'stopDouble': false },
The initialize
method is responsible to initialize the control instance. First, we create a set of options as a combination (using OpenLayers.Util.extend()
method) of the previously defined object and options passed by the user as arguments:
initialize: function(options) { this.handlerOptions = OpenLayers.Util.extend({}, this.defaultHandlerOptions); OpenLayers.Control.prototype.initialize.apply(this, arguments); this.handler = new OpenLayers.Handler.Click( this, { 'click': this.trigger }, this.handlerOptions); },
We have initialized an OpenLayers.Handler.Click
instance to execute the trigger
listener function every time it detects that the user has pressed the mouse button.
Finally, as a good practice we set the
CLASS_NAME
attribute with a string identifying our new control class:
CLASS_NAME: "OpenLayers.Control.Click" });
3.17.81.201