OpenLayers

OpenLayers is a rapidly-developing library for building mapping applications in a browser. The library lets developers integrate data from a variety of sources, provides a friendly API, and results in engaging and responsive mapping applications.

This section will get you started with OpenLayers and then lead you through a number of modules to build a multi-layer map of NYC.

Background

OpenLayers is a client-side Javascript library without any dependencies on server-side scripts or software. As such, you can create various map applications with any server language, including plain html.

OpenLayers was originally built to provide an open source API for viewing tile-based map sources. While similar to applications like Google Maps, Yahoo! Maps, and Bing Maps, OpenLayers provides one important distinction. Commercial application use a server-hosted pyramid of image tiles behind their user interfaces. In contrast, OpenLayers allows developers to add layers based on OGC (Open Geospatial Consortium) standards, including WMS (Web Mapping Service) and WFS (Web Feature Service). In addition to OGC WMS and WFS, OpenLayers supports various geospatial API’s, including those of Google, Yahoo! and Bing.

Getting Started

For the following modules, we will use the copy of OpenLayers that is hosted at the OpenLayers site. Download the latest stable release at http://openlayers.org/download/OpenLayers-2.8.zip and export to your Apache document root.

While installing OpenLayers is as simple as unzipping a code archive into a web folder, its not required. Your web page can load the OpenLayer script directly from the OpenLayers site at http://openlayers.org/api/OpenLayers.js.

Basic Module

Displaying a map is at the heart of using OpenLayers, so let’s start by making a very simple map.

Begin by making folder named labs. Copy the following into a text editor and save it in the labs directory as basics.html.

<html>
  <head>
  <script type="text/javascript" src="http://openlayers.org/api/OpenLayers.js"></script>
    <script type="text/javascript">
      var map;
      function init() {
        map = new OpenLayers.Map('map');
        var wms = new OpenLayers.Layer.WMS(
              "NYC Street Map",
                  "http://maps.opengeo.org/geowebcache/service/wms",
                  { layers: 'openstreetmap', }
            );
        map.addLayers([wms]);
        map.zoomToMaxExtent();
      }
    </script>
  </head>
  <body onload="init()">
    <div id="map" style="width: 100%; height: 500px"></div>
  </body>
</html>

Open the file in your browser (on our system file:///Users/opengeo/labs/basics.html). When you open the page in your browser, it should look like this:

../_images/1-basics.png

Simple OpenLayers Map

Let’s look at the structure of our basic OpenLayers file.

1. Load the OpenLayers Library

<script type="text/javascript" src="http://openlayers.org/api/OpenLayers.js"></script>

This URL points to the location of a JavaScript file (OpenLayers.js) that loads OpenLayers. Because OpenLayers is open source, you can use debugging tools such as Firebug to explore the OpenLayers library right in your browser.

Note

It is also easy to compress OpenLayers into a single file that dramatically improves load time. For more information about how to set up a build profile, see http://trac.openlayers.org/wiki/Profiles.

2. Create a Container for the Map

<div id="map" style="width: 100%; height: 500px"></div>

This is a container for the map that we are creating in our page markup. Later, when we initialize the “map” object, we will give the id of this div element to the map’s constructor.

The size of the map is determined by the size of the element that contains it. Here, we have set the size of the map with an inline style declaration. (Note that these style declarations are better placed in a <style> element - we’re just putting them directly on the div element for simplicity here).

3. Create the Map Object

map = new OpenLayers.Map('map');

Maps in OpenLayers are represented by the Map class. Each map object represents a separate map on the page. We create a new map by using the JavaScript new keyword with the OpenLayers.Map constructor.

In this code, we have passed the Map constructor an argument that is the identifier (‘map’) of the element that we are using for the container of the map. The Map constructor can also take as an optional second argument an object containing more parameters for fine-tuning your map’s features.

For more information, the reference for the API documentation for the Map constructor can be found at http://dev.openlayers.org/apidocs/files/OpenLayers/Map-js.html#OpenLayers.Map.OpenLayers.Map

This code creates a new OpenLayers.Map object and gives it the variable name map. We have declared this variable outside the init function (see var map;) so that you can access it globally (for debugging purposes).

4. Create a Layer

var wms = new OpenLayers.Layer.WMS(
  "NYC Street Map",
  "http://maps.opengeo.org/geowebcache/service/wms",
  { layers: 'openstreetmap', }
);
map.addLayers([wms]);

OpenLayers organizes a single map into several layers. This code constructs one Open Street Maps layer (referred to by the name wms) and adds it to the map.

should go into this more.

Note

Layers Module will go into more detail on types of layers and how to create them. WMS layers will be described there.

5. Position the Map

map.zoomToMaxExtent();

OpenLayers maps need to be told what part of the world they should display before anything will appear on the page. Calling map.zoomToMaxExtent() tells the map to zoom out to its maximum extent, which by default is the entire world. Alternative ways offer more precision include zoomToExtent() and setCenter(). Find references to both of these map methods in the API documents: http://dev.openlayers.org/apidocs/files/OpenLayers/Map-js.html

6. Load the Map

<body onload="init()">

In order to ensure that your document is ready, it is important to make sure that the entire page has been loaded before the script creating the map is executed. We ensure this by putting the map-creating code in a function that is only called when the page’s <body> element receives the onload event.

The final file can be downloaded http://data.opengeo.org/topptalk/openlayers/basics.html

Layers Module

Every OpenLayers map has one or more layers. Layers contain all the geospatial data that the user sees on the map.

There are several different kinds of layers. Some layers request the data as tiles of images that cover the map. Two examples of this are WMS (Web Map Service) layers, which are requested using an OGC (Open Geospatial Consortium) open standard protocol, and also proprietary (“commercial”) layers, such as those provided by Google and Yahoo. Another kind of layer loads the raw data feature by feature. An example of this is a WFS (Web Feature Service) layer.

WMS Layers

The basics.html page created in Basic Module uses a WMS (Web Map Service) layer. WMS is standard protocol for requesting geospatial data dynamically rendered as an image. The images get returned as tiles which cover the area of the map container.

In OpenLayers, a WMS layer is generally create with three parameters.

See OpenLayer’s WMS layer class documentation for further reference: http://dev.openlayers.org/apidocs/files/OpenLayers/Layer/WMS-js.html

  1. name: Defines the layer name, e.g., NYC Street Map`
  2. url: The base url from which OpenLayers will request tiles. In 1-basics.html OpenLayers look to http://maps.opengeo.org/geowebcache/service/wms for the WMS layer.
  3. params: Key/value pairs that represent the GetMap query string parameters and parameter values. The layers parameters can set the layer names, image format and transparency. Since the WMS server has various data sets, the layers:'openstreetmap' parameter specifies that OpenLayers requests the openstreetmap data.

Note

For additional information, including an optional fourth parameter, see the OpenLayer WMS layer class documentation: http://dev.openlayers.org/apidocs/files/OpenLayers/Layer/WMS-js.html

Adding A Layer

In this section, we’ll add a GeoServer served layer to our previous module. These steps are outlined below.

  1. To begin, make a copy of basics.html and save it as wms-layers.html.
  2. As mentioned above, in order to add a layer to your map, you need to pass it at least three arguments–the name of the layer, the map url, and any relevant params. By default, WMS layers are base layers and not transparent. To overlay a layer onto a base layer, you need to add the key-pair``transparent: true``. Further, for rendering optimization, we also recommend the tiling option called, singleTile:true. Add the following, after constructing the wms layer.
subwaylines = new OpenLayers.Layer.WMS(
  "subway lines",
  "http://localhost:8080/geoserver/wms/", {
     layers: 'labs:nyc_subway_lines', transparent: true, format:'image/png',
   },
   { singleTile: true }
);

Note

Subwaylines is being served by a local instance GeoServer. As such, the URL should be the base WMS URL for that instance GeoServer..

  1. To view the previous OpenStreetMap base layer as well as the added subwaylines layer, a layer switcher control is required. In the map construction, we pass it Control.LayerSwitcher. In the following sections we’ll go into more detail on OpenLayers control options.
map = new OpenLayers.Map('map', {
  controls:[
  new OpenLayers.Control.LayerSwitcher()]
});

4 Add the subwaylines layer.

map.addLayers([wms, subwaylines]);
  1. Load wms-layers.html in a browser. You should see should the previous NYC StreetMap layer, an overlay of subway lines, and a layer switcher on the right. Expand the layer switcher with the “+” button and toggle between to turn on and off subway lines. You’ll notice that the sublway lines layer looks a bit. . .tiny compared to NYC StreetMap. We will reposition the map’s center and zoom in order to better view our layers.
../_images/2-wms-overlay2.png

Overlay of GeoServer Layer

The final file can be downloaded http://data.opengeo.org/topptalk/openlayers/wms-layers.html

Positioning a Map

By default, OpenLayers sets the initial extent to the world. Two common ways to reposition an extent, is to specify the map’s maximum extent (i.e., bounding box) and/or to specify the map’s center and zoom. In this example, we’ll be setting the maps center and zoom.

  1. Begin by making a copy of wms-layers.html, and saving it as wms-position.html.

  2. There are many ways to determining the center coordinates of a map layer. For this example, we’ll use the Firebug console. First, however, we need to pass the map constructor some additional controls:

    new OpenLayers.Control.Navigation(),
    new OpenLayers.Control.PanZoomBar()
    

The Navigation control handles map browsing with mouse events. When added to your map, you activate dragging, double-clicking, and scrolling actions.

The PanZoomBar control is a visible panel, typically in the upper left corner of the map. When added, you can, not surprisingly, zoom and pan your map.

  1. Load wms-position.html. You’ll notice that you now have the more common slippy map that allows you to dynamically pan and zoom. Using the additional controls, zoom and pan to a desired frame.
../_images/2-wms-frame2.png

Zoomed-in View of NYC Streets and subway lines

3. Open your Firebug console (Ctrl+Shift+L or CmdShift+L depending on your OS). In the console tab, enter the following:

>>> map.getCenter();

The resulting coordinate, in lon/lat, should be similar to:

center: lon=-73.953094482418,lat=40.7647705078
  1. Remove map.zoomToMaxExtent(); and add a map.setCenter(); function. The first parameters specifies the center coordinate for the maps. The second coordinates, in this case 12 sets the initial zoom level. Note there are 16 zoom levels by default.
map.setCenter(new OpenLayers.LonLat(-73.953094482418, 40.7647705078), 12);
  1. Load wms-position.html. The initial map should be identical to the zoomed/panned version set out with instruction 2.

The final file can be downloaded http://data.opengeo.org/topptalk/openlayers/wms-position.html.

Adding A Google Layer

In this section, we’ll add a Google Maps layer to our repositioned map. These steps are outlined below.

  1. To begin, make a copy of wms-position and save it as google.html.
  2. OpenLayers provides support for such commercial layers as Google Maps, Yahoo Maps, and Virtual Earth. These can be used as a background map for your own layers. Using any of the commercial layers requires a further parameter in the <script> section of the code–the commercial API key. The following Google key is for localhost, and should work with your GeoServer installation. Add the following to script, one line with no spaces.
<script src='http://maps.google.com/maps?file=api&amp;v=2&amp;key=ABQIAAAAjpkAC9ePGem0lIq5XcMiuhR_wWLPFku8Ix9i2SXYRVK3e45q1BQUd_beF8dtzKET_EteAjPdGDwqpQ'></script>

Note

You can sign up for your own Google Maps API key here: http://code.google.com/apis/maps/signup.html

  1. In order for our previous layers to display correctly on top of the Google layer, we will have to define three standard projection parameters.
    • The spherical mercator projection of Google Tiles: EPSG:900913
    • The maximum display resolution in one 256x256 pixel tile: 156543.03390625
    • The horizontal unit as meters: units: ‘m’

After the control parameters, pass the map constructor the following:

// Geoserver epsg code
projection: "EPSG:900913"
// Displays the globe in one 256x256 pixel tile
maxResolution: 156543.03390625,
// Map horizontal units are meters
units: 'm'
  1. For Google projects, we also need to set the set the bounding box in Google’s custom 900913 projection. Return to the browser and view wms-position.html at its initial position. To determine the bounds for a similar Google map, type the following in the Firebug console:
>>> map.getExtent().transform(new OpenLayers.Projection('EPSG:4326'), new OpenLayers.Projection('EPSG:900913'));

The resulting bounding box is our map extent. Append this parameter to the map constructor.

``maxExtent: new OpenLayers.Bounds(-2.003750834E7,-2.003750834E7,2.003750834E7,2.003750834E7)``
  1. As in the previous example, we need to center our map. Again, we use map.getCenter() in Firebug to retrieve our center coordinates:
>>> map.getCenter().transform(new OpenLayers.Projection('EPSG:4326'), new OpenLayers.Projection('EPSG:900913'));

The resulting coordinates are the center of our map, in 900913 projection. Replace the previous mapCenter values for something akin to:

map.setCenter(new OpenLayers.LonLat(-8238029, 4969397.25), 13);
  1. To define a Google layer as a base layer, you need to pass it at least two options–the name of the layer as it will appear in the legend (e.g., Google Satellite) and the map type (e.g., Google Satellite). To add Google satellite and street maps, append the following to your map definitions:
// create Google Satellite layer
  var gsat = new OpenLayers.Layer.Google(
  "Google Satellite", {
    type: G_SATELLITE_MAP, 'sphericalMercator': true
  }
);

//Create Google Mercator layers
var gmap = new OpenLayers.Layer.Google(
  "Google Streets", {
  'sphericalMercator': true
}
);
  1. Finally, add the Google layers to your map.
map.addLayers([gsat, gmap, wms, subwaylines]);

The resulting map should look like the following:

../_images/2-wms-google.png

Overlay of Google Layer

The final file can be downloaded http://data.opengeo.org/topptalk/openlayers/google.html

Events Module

The following example demonstrates the WMSGetFeatureInfo control for fetching information from the subwaylines layer. Results are displayed in a pop-up.

  1. Begin by copy and pasting google.html and save it as events.html in the geoserver www directory.
mv ~/labs/events.html /usr/local/geoserver/data_dir/www/
  1. We’ll be taking sample code from the OpenLayers example Feature Info in Popup and customizing it for our purposes.

Note

A number of openlayers examples can be found at http://openlayers.org/dev/examples/. If you’re familiar with JavaScript, try viewing the source of the examples to get an idea how the OpenLayers library is used.

  1. Add the control for event handling:
new OpenLayers.Control.Attribution()
  1. The example getfeatureinfo event has been modified in 2 ways. First, it only returns popups with body text, and second it removes an existing popups when requesting a second one. Append the following code after your layers declarations. Note that the url OpenLayers requests information from is local to our file: url: '/geoserver/wms/'.
var popup = null;
info = new OpenLayers.Control.WMSGetFeatureInfo({
  url: '/geoserver/wms/',
  title: 'Identify features by clicking',
  queryVisible: true,
  layers: [subwaylines],
  eventListeners: {
    getfeatureinfo: function(event) {
      if (!event.text.match(/<body>\s*<\/body>/)) {
        if (popup) {popup.destroy(); popup = null;}
          popup = new OpenLayers.Popup.FramedCloud(
        "popup",
        map.getLonLatFromPixel(event.xy),
        null,
        event.text,
        null,
        true
      );
   map.addPopup(popup);
 }
        }
  }
});
        map.addControl(info);
        info.activate();
  1. Load events.html at http://localhost:8080/geoserver/www/events.html. The map should look like the following:
../_images/3-events.png

Popup

The final file can be downloaded http://data.opengeo.org/topptalk/openlayers/events.html

Adding a Proxy

  1. Due to security restrictions in Javascript, it is not possible to retrieve information from remote domains via an XMLHttpRequest. For events that query a remote servers, you must install a proxy script. To begin, copy events.html and save it as eproxy.html.
  2. Since we’re going to be using our localhost, we need to save eproxy.html to our Apache root. On a mac, save eproxy to /Users/opengeo/Sites/eproxy.html.
  3. In System Preferences we need to enable web sharing. Go to Apple‣ System Preferences‣Sharing and check “guilabel: Web Sharing.
  4. Next we need to edit our proxy.cgi script to include our localhost:8080. Open proxy.cgi from /Library/WebServer/CGI-Executables/ and edit the allowed hosts to include localhost.
allowedHosts = ['www.openlayers.org', 'openlayers.org',
                'labs.metacarta.com', 'world.freemap.in',
                'prototype.openmnnd.org', 'geo.openplans.org',
                'sigma.openplans.org', 'demo.opengeo.org',
                'www.openstreetmap.org', 'sample.avencia.com', 'localhost:8080']
  1. Check to see if the proxy is working by going to http://localhost/cgi-bin/proxy.cgi.
  2. Now we have to add an OpenLayers.ProxyHost variable to our eproxy.html file.
OpenLayers.ProxyHost = "/cgi-bin/proxy.cgi?url=";
  1. Since we’re running the event from a different host than geoserver, we need to edit the WMS GetFeatureInfo url. Change url: '/geoserver/wms/', to http://maps.opengeo.org/geowebcache/service/wms.
  2. Load http://localhost/~opengeo/eproxy.html And Voila! The popup exists with proxy.

The final file can be downloaded http://data.opengeo.org/topptalk/openlayers/eproxy.html

Previous: GeoServer