Displaying maps with OpenLayers

865

Author: Justin Palk

Google Maps gives you a quick and easy way to add maps to your Web site, but when you’re using Google’s API, your ability to display other data is limited. If you have your own data you want to display, or data from sources other than Google, OpenLayers, an open source JavaScript library, can give you more options.

OpenLayers has been getting some high-profile usage lately, including on EveryBlock, the geographic news site run by Django creator Adrian Holovaty and others, and also as part of the mapping stack Barack Obama’s campaign used to help support his successful US presidential bid.

Geographic intelligence company MetaCarta originally developed the library, but eventually released it to the public under a BSD-style license. OpenLayers implements the Open Geospatial Consortium’sWeb Map Service (WMS) and Web Feature Service protocols. The library is in active development, and version 2.7 was released in September.

To use OpenLayers, you can either link to it, or download it from the OpenLayers Web site.

OpenLayers works either with data you’re serving yourself, using a package such as GeoServer or MapServer, or with data others are publishing via WMS. There is no easy way to search for WMS servers with data to display, although ExploreOurPla.net does offer a searchable index it claims includes more than 30,000 publicly accessible layers on more than 200 servers.

Maps and layers

NASA OnEarth makes some data, notably its Blue Marble Next Generation (BMNG) satellite imagery, available through WMS. To access the data, you need to know the URL of the WMS server and the name of the map layer you want to use. For this exercise, I used NASA’s WMS server and the Blue Marble Next Generation imagery.

At its simplest, an OpenLayers map consists of an OpenLayers.Map object and one or more OpenLayers.Layers objects. Here’s a simple OpenLayers script and the accompanying HTML to display the Blue Marble imagery in a Web page:

<html> <head> <title>OpenLayers tutorial</title> <script src="http://openlayers.org/api/OpenLayers.js"></script> <script type="text/javascript"> function setHTML(response) { document.getElementById('nodeList').innerHTML = response.responseText; } function init(){ var options = { minResolution: "auto", minExtent: new OpenLayers.Bounds(-1, -1, 1, 1), maxResolution: "auto", maxExtent: new OpenLayers.Bounds(-180, -90, 180, 90), }; var map = new OpenLayers.Map('map', options ); var NASAwms = new OpenLayers.Layer.WMS( "NASA WMS", "http://wms.jpl.nasa.gov/wms.cgi?", {layers: 'BMNG', format: 'image/png'}, {isBaseLayer: true}); map.addLayer(NASAwms); map.zoomToMaxExtent(); } </script> <style type="text/css"> #map { width: 500px; height: 250px; border: 1px solid black; } </style> </head> <body onload="init()"> <div id="map"></div> <div id="nodeList"></div> </body> </html>

This is a basic script that retrieves the imagery from NASA’s WMS server and displays it with the default pan and zoom controls. If you copy this code and open the page in a Web browser, you should see a blue and green satellite image of the Earth.

You aren’t restricted to displaying a single layer, however. NASA’s Blue Marble shows some gorgeous satellite imagery, but it’s lacking in details such as borders. The US Geological Survey also serves data via WMS. If you create another layer, you can retrieve US state boundaries using the States_Generalized layer.

If you add some code to display the USGS generalized states layer, your script will look like this:

<script src="http://openlayers.org/api/OpenLayers.js"></script> <script type="text/javascript"> function setHTML(response) { document.getElementById('nodeList').innerHTML = response.responseText; } function init(){ var options = { minResolution: "auto", minExtent: new OpenLayers.Bounds(-1, -1, 1, 1), maxResolution: "auto", maxExtent: new OpenLayers.Bounds(-180, -90, 180, 90), }; var map = new OpenLayers.Map('map', options ); var NASAwms = new OpenLayers.Layer.WMS( "NASA WMS", "http://wms.jpl.nasa.gov/wms.cgi?", {layers: 'BMNG', format: 'image/png'}, {isBaseLayer: true}); var USGSwms = new OpenLayers.Layer.WMS ("USGS WMS", "http://toposervices.cr.usgs.gov/wmsconnector/com.esri.wms.Esrimap/USGS_EDNA_geo?", {layers: 'States_Generalized', format: 'image/png'}, {isBaseLayer:false}); map.addLayer(NASAwms); map.addLayer(USGSwms); map.zoomToMaxExtent(); } </script>

If you now refresh your browser, the map you see probably isn’t the map you were expecting to get. All you have is an outline of the states in the US, superimposed on a white background. In the initial script, you set the NASA imagery as the base layer for your map with the isBaseLayer: true option. Other layers will be stacked on top of the base layer, and can obscure it. To display both layers at the same time, you need to tell OpenLayers that the USGS layer should be transparent, by adding transparent: true: to the options for that layer.

While you’re at it, you might want to change how your map displays initially. Since you added the US state borders layer, it might be nice to focus on the US, since that’s where you have more detail now.

To do this, you can set a latitude and longitude, as well as the initial zoom level. To center your map on Washington, DC, create a pair of variables, lat and lon, and set them to 38.890000 and -77.020000, respectively. Create another variable, zoom, and set it to 3, which, with the map centered and zoomed in on Washington, DC, will display most of the United States’ eastern seaboard.

To complete the change, remove the line map.zoomToMaxExtent(); and replace it with map.setCenter(new OpenLayers.LonLat(lon, lat), zoom);.

The resulting script should look like this:

<script src="http://openlayers.org/api/OpenLayers.js"></script> <script type="text/javascript"> function setHTML(response) { document.getElementById('nodeList').innerHTML = response.responseText; } function init(){ var lat = 38.890000; var lon = -77.020000; var zoom = 3; var options = { minResolution: "auto", minExtent: new OpenLayers.Bounds(-1, -1, 1, 1), maxResolution: "auto", maxExtent: new OpenLayers.Bounds(-180, -90, 180, 90), }; var map = new OpenLayers.Map('map', options ); var NASAwms = new OpenLayers.Layer.WMS( "NASA WMS", "http://wms.jpl.nasa.gov/wms.cgi?", {layers: 'BMNG', format: 'image/png'}, {isBaseLayer: true}); var USGSwms = new OpenLayers.Layer.WMS ("USGS WMS", "http://toposervices.cr.usgs.gov/wmsconnector/com.esri.wms.Esrimap/USGS_EDNA_geo?", {layers: 'States_Generalized', format: 'image/png', transparent: true}, {isBaseLayer:false}); map.addLayer(NASAwms); map.addLayer(USGSwms); map.setCenter(new OpenLayers.LonLat(lon, lat), zoom); } </script>

Markers

Like Google Maps, OpenLayers has support for putting markers on your maps to identify points of interest. The simplest method for doing this is to create a text layer.

Text layers read out of tab-delimited text files containing the latitude and longitude, name, description, and icon to use for one or more points of interest. Once displayed on the map, clicking on a marker will open a text bubble showing the point’s name and description, the display of which can be controlled with HTML. Clicking on the marker a second time will close the text bubble.

A simple text layer file to mark the cities of Washington, DC, New York, NY, and Atlanta, Ga., with the default OpenLayers icons, would look like this:

point title description icon 38.905,-77.016 <h4>Washington DC</h4> Population: 588,292 40.664,-73.938 <h4>New York</h4> Population: 8,274,527 33.763,-84.423 <h4>Atlanta</h4> Population: 519,145

If you saved that text in a file named textlayer.txt, the code to display it on your map would look like this:

<script src="http://openlayers.org/api/OpenLayers.js"></script> <script type="text/javascript"> function init(){ var lat = 38.890000; var lon = -77.020000; var zoom = 3; var options = { theme: null, minResolution: "auto", minExtent: new OpenLayers.Bounds(-1, -1, 1, 1), maxResolution: "auto", maxExtent: new OpenLayers.Bounds(-180, -90, 180, 90) }; var map = new OpenLayers.Map('map', options ); var NASAwms = new OpenLayers.Layer.WMS( "NASA WMS", "http://wms.jpl.nasa.gov/wms.cgi?", {layers: 'BMNG', format: 'image/png'}, {isBaseLayer: true}); var USGSwms = new OpenLayers.Layer.WMS ("USGS WMS", "http://toposervices.cr.usgs.gov/wmsconnector/com.esri.wms.Esrimap/USGS_EDNA_geo?", {layers: 'States_Generalized', format: 'image/png', transparent: true}, {isBaseLayer:false}); map.addLayers([NASAwms, USGSwms]); map.setCenter(new OpenLayers.LonLat(lon, lat), zoom); var textlayer = new OpenLayers.Layer.Text( "text", { location:"./textlayer.txt"} ); map.addLayer(textlayer); } </script>

Controls

OpenLayers also gives you the ability to choose what controls you put on your maps.

You can add controls to your map either with the addControl() method on an OpenLayers.Map object, or by specifying a list of controls in the options for an OpenLayers.Map object when you create it.

Map controls are all subclasses of the OpenLayers.Control class, and include features such as pan and zoom controls, with OpenLayers.Control.PanZoom(); layer display boxes, with OpenLayers.Control.LayerSwitcher; scale bars, with OpenLayers.Control.ScaleLine(); and an automatic display of your mouse pointer’s latitude and longitude, with OpenLayers.Control.MousePosition().

By default, the latitude and longitude for the mouse pointer and the mile and kilometer measurements in the scale bar will display as black text. This doesn’t display well against the dark blue of the ocean on the Blue Marble layers, but you can use CSS to control how OpenLayers elements are displayed. To do this, link to OpenLayers’ default CSS file, then override the defaults with your own CSS, either in your Web page or another linked CSS file. You also need to specify theme: null in your map options.

<html> <head> <title>OpenLayers tutorial</title> <link rel="stylesheet" href="http://openlayers.org/api/theme/default/style.css" type="text/css" /> <style type="text/css"> p { width: 500px; } div.olControlMousePosition { font-family: Times; font-size: 0.75em; color: red; } div.olControlScaleLine { font-family: Times; font-size: 0.75em; color: red; } </style> <script src="http://openlayers.org/api/OpenLayers.js"></script> <script type="text/javascript"> function init(){ var lat = 38.890000; var lon = -77.020000; var zoom = 3; var options = { theme: null, minResolution: "auto", minExtent: new OpenLayers.Bounds(-1, -1, 1, 1), maxResolution: "auto", maxExtent: new OpenLayers.Bounds(-180, -90, 180, 90), controls: [ new OpenLayers.Control.LayerSwitcher({'ascending':false}), new OpenLayers.Control.MousePosition(), new OpenLayers.Control.PanZoom(), new OpenLayers.Control.ScaleLine() ] }; var map = new OpenLayers.Map('map', options ); var NASAwms = new OpenLayers.Layer.WMS( "NASA WMS", "http://wms.jpl.nasa.gov/wms.cgi?", {layers: 'BMNG', format: 'image/png'}, {isBaseLayer: true}); var USGSwms = new OpenLayers.Layer.WMS ("USGS WMS", "http://toposervices.cr.usgs.gov/wmsconnector/com.esri.wms.Esrimap/USGS_EDNA_geo?", {layers: 'States_Generalized', format: 'image/png', transparent: true}, {isBaseLayer:false}); USGSwms.setVisibility(false); map.addLayers([NASAwms, USGSwms]); map.setCenter(new OpenLayers.LonLat(lon, lat), zoom); var textlayer = new OpenLayers.Layer.Text( "text", { location:"./textfile.txt"} ); map.addLayer(textlayer); } </script> <style type="text/css"> #map { width: 500px; height: 250px; border: 1px solid black; } </style> </head> <body onload="init()"> <div id="map"></div> <div id="nodeList"></div> </body> </html>

Google Maps

OpenLayers can also display data from Google Maps. You must first sign up for a Google Maps API key. Google Maps have their own class, OpenLayers.Layer.Google, which defaults to the standard Google road map, or you can choose from either of the G_SATELLITE_MAP or G_HYBRID_MAP types.

<script src="http://openlayers.org/api/OpenLayers.js"></script> <script src="http://maps.google.com/maps?file=api&v=2&key=your_key_here" type="text/javascript"></script> <script type="text/javascript"> function setHTML(response) { document.getElementById('nodeList').innerHTML = response.responseText; } function init(){ var google = new OpenLayers.Layer.Google( "Google", { type: G_HYBRID_MAP } ); var options = { minResolution: "auto", minExtent: new OpenLayers.Bounds(-1, -1, 1, 1), maxResolution: "auto", maxExtent: new OpenLayers.Bounds(-180, -90, 180, 90), }; var map = new OpenLayers.Map('map', options ); map.addLayer(google); map.zoomToMaxExtent(); } </script>

Conclusion

This is just a small part of what you can do using OpenLayers. Although the examples presented above all rely on the OGC’s Web Map Service protocol, OpenLayers also lets you supplement your map with feature data obtained from a Web Feature Service server, GeoRSS, or a KML file.

Category:

  • Internet & WWW