| Author: | Christopher Schmidt |
|---|---|
| Date: | 10 February, 2008 |
| Status: | Under Development |
OpenLayers is a pure JavaScript library for displaying map data in most modern web browsers, with no server-side dependencies. OpenLayers implements a JavaScript API for building rich web-based geographic applications, similar to the Google Maps and MSN Virtual Earth APIs, with one important difference -- OpenLayers is Free Software, developed for and by the Open Source software community.
This document describes the Spherical Mercator projection, what it is, and when you should use it. It includes some background information, demonstration of using the code with just a commercial layer, and how to add a WMS over the top of that layer, and how to reproject coordinates within OpenLayers so that you can reproject coordinates inside of OpenLayers. It is expected that readers of this tutorial will have a basic understanding of reprojection, and will have read and understood the Getting Started with OpenLayers tutorial.
Spherical Mercator is a de facto term used inside the OpenLayers community -- and also the other existing Open Source GIS community -- to describe the projection used by Google Maps, Microsoft Virtual Earth, Yahoo Maps, and other commercial API providers.
This term is used to refer to the fact that these providers use a Mercator projection which treats the earth as a sphere, rather than a projection which treats the earth as an ellipsoid. This affects calculations done based on treating the map as a flat plane, and is therefore important to be aware of when working with these map providers.
In order to properly overlay data on top of the maps provided by the commerical API providers, it is neccesary to use this projection. This applies primarily to displaying raster tiles over the commercial API layers -- such as TMS, WMS, or other similar tiles.
In order to work well with the existing commercial APIs, many users who create data designed for use within Google Maps will also use this projection. One prime example is OpenStreetMap, whose raster map tiles are all projected into the 'spherical mercator' projection.
The first thing to do with the Spherical Mercator projection is to create a map using the projection. This map will be based on the Microsoft Virtual Earth API. The following HTML template will be used for the map.
<html>
<head>
<title>OpenLayers Example</title>
<script src='http://dev.virtualearth.net/mapcontrol/v3/mapcontrol.js'></script>
<script src="http://openlayers.org/api/OpenLayers.js"></script>
</head>
<body>
<div style="width:100%; height:100%" id="map"></div>
<script defer='defer' type='text/javascript'>
// Code goes here
</script>
</body>
</html>
Ex. 1: HTML Template
The next step is to add the default Microsoft Virtual Earth layer as a base layer to the map.
var map = new OpenLayers.Map('map');
var layer = new OpenLayers.Layer.VirtualEarth("Virtual Earth",
{ sphericalMercator: true });
map.addLayer(layer);
map.zoomToMaxExtent();
This creates a map. However, once you have this map, there is something very important to be aware of: the coordinates that you use in setCenter are not longitude and latitude! Instead, they are in projected units -- meters, in this case. This map will let you drag around, but without understanding a bit more about spherical mercator, it will be difficult to do anything more with it.
Thankfully, OpenLayers now provides tools to help you reproject your data on the client side. This makes it possible to transform coordinates from Longitude/Latitude to Spherical Mercator as part of your normal operation. First, we will transform coordinates for use within the setCenter and other calls. Then we will show how to use the displayProjection option on the map to modify the display of coordinate data to take into account the projection of the base map.
To do this, first create a projection object for your default projection. The standard latitude/longitude projection string is "EPSG:4326" -- this is latitude/longitude based on the WGS84 datum. (If your data lines up correctly on Google Maps, this is what you have.)
You will then be creating an object to hold your coordinates, and transforming it.
var proj = new OpenLayers.Projection("EPSG:4326");
var point = new OpenLayers.LonLat(-71, 42);
point.transform(proj, map.getProjectionObject());
The point is now projected into the spherical mercator projection, and you can pass it to the setCenter method on the map:
map.setCenter(point);
This can also be done directly in the setCenter call:
var proj = new OpenLayers.Projection("EPSG:4326");
var point = new OpenLayers.LonLat(-71, 42);
map.setCenter(point.transform(proj, map.getProjectionObject()));
In this way, you can use latitude/longitude coordinates to choosing a center for your map.
Several controls display map coordinates to the user, either directly or built into their links. The MousePosition and Permalink control (and its companion control, ArgParser) both use coordinates which match the internal projection of the map -- which in the case of Spherical Mercator layers is projected. To prevent user confusion, OpenLayers allows one to set a 'display' projection. When these controls are used, transformation is made from the map projection to the display projection.
To use this option, when creating your map, you should specify the projection and displayProjection options. Once this is done, the controls will automatically pick up this option from the map.
var map = new OpenLayers.Map("map", {
projection: new OpenLayers.Projection("EPSG:900913"),
displayProjection: new OpenLayers.Projection("EPSG:4326")
});
map.addControl(new OpenLayers.Control.Permalink());
map.addControl(new OpenLayers.Control.MousePosition());
You can then add your layer as normal.
When creating projected maps, it is possible to reproject vector data onto a basemap. To do so, you must simply set the projection of your vector data correctly, and ensure that your map projection is correct.
var map = new OpenLayers.Map("map", {
projection: new OpenLayers.Projection("EPSG:900913")
});
map.addLayer(myBaseLayer);
var myGML = new OpenLayers.Layer.GML("GML", "mygml.gml", {
projection: new OpenLayers.Projection("EPSG:4326")
});
map.addLayer(myGML);
Note that you can also use this setup to load any format of vector data which OpenLayers supports, including WKT, GeoJSON, KML and others. Simply specify the format option of the GML layer.
var geojson = new OpenLayers.Layer.GML("GeoJSON", "geo.json", {
projection: new OpenLayers.Projection("EPSG:4326"),
format: OpenLayers.Format.GeoJSON
});
map.addLayer(geojson);
The way to serialize vector data in OpenLayers is to take a collection of data from a vector layer and pass it to a Format class to write out data. However, in the case of a projected map, the data that you get from this will be projected. To reproject the data when converting, you should pass the internal and external projection to the format class, then use that format to write out your data.
var format = new OpenLayers.Format.GeoJSON({
'internalProjection': new OpenLayers.Projection("EPSG:900913"),
'externalProjection': new OpenLayers.Projection("EPSG:4326")
});
var jsonstring = format.write(vector_layer.features);
One of the reasons that the Spherical Mercator projection is so important is that it is the only projection which will allow for overlaying image data on top of commercial layers like Google Maps correctly. When using raster images, in the browser, it is not possible to reproject the images in the same way it might be in a 'thick' GIS client. Instead, all images must be in the same projection.
How to create Spherical Mercator projected tiles depends on the software you are using to generate your images. MapServer is covered in this document.
MapServer uses proj.4 for its reprojection support. In order to enable reprojection to Spherical Mercator in MapServer, you must add the definition for the projection to your proj.4 data directories.
On Linux systems, edit the /usr/share/proj/epsg file. At the bottom of that file, add the line:
<900913> +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs
After you do this, you must add the projection to your wms_srs metdadata in your map file:
map
web
metadata
wms_srs "EPSG:4326 EPSG:900913"
end
end
# Layers go here
end
This will allow you to request tiles from your MapServer WMS server in the Spherical Mercator projection, which will align with commercial provider data in OpenLayers.
var options = {
projection: new OpenLayers.Projection("EPSG:900913"),
units: "m",
maxResolution: 156543.0339,
maxExtent: new OpenLayers.Bounds(-20037508.34, -20037508.34,
20037508.34, 20037508.34)
};
map = new OpenLayers.Map('map', options);
// create Google Mercator layers
var gmap = new OpenLayers.Layer.Google(
"Google Streets",
{'sphericalMercator': true}
);
// create WMS layer
var wms = new OpenLayers.Layer.WMS(
"World Map",
"http://world.freemap.in/tiles/",
{'layers': 'factbook-overlay'},
{
'isBaseLayer': false
}
);
map.addLayers(gmap, wms);
WMS layers automatically inherit the projection from the base layer of a map, so there is no need to set the projection option on the layer.