Using WMS with OpenLayers

From CUOSGwiki
Revision as of 00:02, 23 December 2013 by Scottpage (talk | contribs)
Jump to navigationJump to search

Introduction

The goal of this project is to use freely available Web Map Service (WMS) layers with OpenLayers to create a dynamic map for use within a web browser. In particular, the hope was to include a land use layer for Canada, and the user could browse to a desired location to determine how the land is being used. If the user knows the coordinates of the place they want to view, they can modify the source code by entering the chosen longitude, latitude, and zoom level. Then when loading the map the images will be centered within the map window at that location. For the following example, only GeoBase and Natural Resources Canada's Toporama WMS layers are used, and they can be accessed at no cost and without restrictions.

This tutorial contains a brief outline of WMS layers and OpenLayers, and then descriptions of the methods used to create the maps displayed in Section 4. This includes discussion of the important aspects of the HTML code that generated the resulting maps, as well as projection transformations and the computing of bounding boxes using PROJ.4.

Data and Mapping Tools

WMS Layers

WMS provides a HTTP interface for requesting geo-registered map images from one of more geospatial databases. A WMS request defines the geographic layer(s) and area of interest that will be processed.[1] There is then a response to the request where geo-registered map images (in the following example returned as a PNG) can be displayed within a browser.

If the user has included more than one WMS layer, they have the ability to specify which will be the base layer, and which will be overlay layers. If the user then wants multiple images to be combined, the overlay layers need to be designated transparent. This is not necessary, however, as the user may want only one layer to appear at a time. This can be done by making the transparent flag false for each of the overlay layers, and then the user can manually switch between layers through the web browser. With OpenLayers the ‘LayerSwitcher’ control, which can be added into the code, is a popup that allows the user to do this by simply selecting which layer they want to view.


There are six WMS layers being used in the following example. The first layer, which is being used as the base map is obtained from Geobase, and it contains foreign landmass boundaries. The additional overlay layers which encompass all of Canada are as follows:

Surface water network (layer name: hydrography). Obtained from: NRCan's Toporama

Landcover (layer name: landcover:csc2000): Geobase

Primary Roads (layer name: nrn:roadnetwork:roadseg_primary): Geobase

Secondary Roads (layer name: nrn:roadnetwork:roadseg_secondary): Geobase

Cities (layer name: populated_places): NRCan's Toporama


The GeoBase and Toporama WMS support mandatory GetCapabilities and GetMap operations as defined in the OGC WMS standard, version 1.1.1. Get Capabilities is an operation that produces a descriptive XML document that includes general information on the WMS, as well as descriptions of each data layer. An example of this type of request addressed to GeoBase is http://ows.geobase.ca/wms/geobase_en?service=wms&request=GetCapabilities&version=1.1.1, and to NRCan’s Toporama is http://wms.ess-ws.nrcan.gc.ca/wms/toporama_en?VERSION=1.1.1&request=GetCapabilities&service=wms. This was used for this project and it allowed the user to fully understand what each layer is representing.


OpenLayers

OpenLayers is an open source JavaScript library that is used to display map data in web browsers. It is an Open Source Geospatial Foundation (OSGeo) project that supports map data from any source that uses Open Geospatial Consortium (OGC) standards as WMS or Web Feature Service (WFS). The OpenLayers library and full documentation can be obtained from http://openlayers.org.


Methods

WMS Layers

The first step was to determine which WMS layers would be used for the project. Six layers were found using GeoBase and Natural Resources Canada’s Toporama data. Within the subsequent HTML code example, they are named ‘basemap,’ ‘water,’ ‘landcovercanada,’ ‘primary roads,’ ‘secondary roads,’ and ‘cities.’ What each layer represents is described below:

basemap – Foreign political boundaries at 1:10M scale

water – Surface water network of Canada

landcovercanada – Land cover information from 2000 for all of Canada. It is the result of vectorization of raster thematic data originating from Landsat 5 and Landsat 7 ortho-images, for agricultural and forest areas of Canada.

primaryroads – Primary roads include mainly the Highways and Expressways, although this may vary according to each province.

secondaryroads – Secondary roads include mainly the Arterial ways, although this may vary according to each province.

cities – Heavily populated areas


Further information regarding how the WMS layers are used within OpenLayers can be seen within the comments of the HTML code, such as how multiple WMS layers can be specified in a single OpenLayers layer. Also, note that the layers are placed in the reverse order in which they want to be viewed. In other words, ‘cities’ is placed as the last layer within the ‘layers’ variable so that it will be viewed on top of the other layers. If the landcover layer was instead placed as the final layer it would cover the others.


OpenLayers Viewer

To build an OpenLayers viewer requires crafting HTML in which the viewer will be seen. This is done through the statement on line 14 of the code in Figure 1. OpenLayers supports putting a map inside almost any HTML block element on the page. Also required is a script tag which includes the OpenLayers library to the page. This is shown in line 15 of Figure 1.

Openlayersviewercode.png

Figure 1. Displaying the HTML code required to craft the OpenLayers viewer and include the OpenLayers library to the page.


HTML Code

The following HTML code was used to produce Figure 2 shown below. Within the code there are comments (<!-- -->) that describe what the subsequent pieces of code are accomplishing.


<!DOCTYPE html>
<html>
 <head>
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
   <meta name="apple-mobile-web-app-capable" content="yes">
   <title>OpenLayers WMS Test</title>
   <link rel="stylesheet" href="../theme/default/style.css" type="text/css">
   <link rel="stylesheet" href="style.css" type="text/css">
 </head>
 <body onload="init()">
   <h1 id="title">OpenLayers WMS Example</h1>
   <div id="shortdesc">Displaying WMS layers:</div>
   <div id="map" class="mediummap"></div>
   <script type="text/javascript" src="OpenLayers.js"></script>
   <script type="text/javascript"> 
     
      <!-- Enter the desired center location of the map as well as the zoom level. These will be called after the map has been 
created using the map.setCenter control. --> 
     var lon = 1511889.26697;
     var lat = -171308.32032;
     var zoom = 9;
     var map, layer;
       function init() {
        <!-- Define the WMS layers that will be used to generate the map. Multiple WMS layers can be placed in a single OpenLayers 
        layer, as is the case here. --> 
        <!-- Each layer could also be set up as its own variable, and then all of the variables could be called at the end during 
        the map.addLayers() step. Both methods will work. --> 
        <!-- The multiple WMS layers within the single OpenLayers layer is all one statement, and the first WMS layer listed will 
        be considered the base layer. -->  
        <!-- The other layers are then considered the overlay layers. These must be made transparent. Note the transparent flag is 
        set as true within each WMS layer. --> 	
        <!-- Note the isBaseLayer flag within each of the overlay layers, which is set as false. The first layer does not 
        need this flag as it is understood to be the base layer. --> 
        <!-- Note the use of png images, which support transparency. --> 	
           var layers = 
               [
                   new OpenLayers.Layer.WMS(
                       "basemap",
                       "http://ows.geobase.ca/wms/geobase_en",
                       {
                           layers: 'reference:landmass:international_10m'
                       }),
                   new OpenLayers.Layer.WMS(
                       "water",
                       "http://wms.ess-ws.nrcan.gc.ca/wms/toporama_en",
                       {
                           layers: 'hydrography',
                           transparent: 'true',
                           format: 'image/png'
                       },
                       {
                           isBaseLayer: false
                       }),
                   new OpenLayers.Layer.WMS(
                       "landcovercanada",
                       "http://ows.geobase.ca/wms/geobase_en",
                       {
                           layers: 'landcover:csc2000',
                           transparent: 'true',
                           format: 'image/png'
                       },
                       {
                           isBaseLayer: false
                       }),
                   new OpenLayers.Layer.WMS(
                       "primaryroads",
                       "http://ows.geobase.ca/wms/geobase_en",
                       {
                           layers: 'nrn:roadnetwork:roadseg_primary',
                           transparent: 'true',
                           format: 'image/png'
                       },
                       {
                           isBaseLayer: false
                       }),
                   new OpenLayers.Layer.WMS(
                       "secondaryroads",
                       "http://ows.geobase.ca/wms/geobase_en",
                       {
                           layers: 'nrn:roadnetwork:roadseg_secondary',
                           transparent: 'true',
                           format: 'image/png'  
                       },
                       {
                           isBaseLayer: false
                       }),
                   new OpenLayers.Layer.WMS(
                       "cities",
                       "http://wms.ess-ws.nrcan.gc.ca/wms/toporama_en",
                       {
                           layers: 'populated_places',
                           transparent: 'true',
                           format: 'image/png'
                       },
                       {
                           isBaseLayer: false
                       })
               ]; 
           <!-- Define the projection of the map. Codes, their associated projections, and documentation can be found at 
           http://trac.osgeo.org/proj/ (PROJ.4) or http:spatialreference.org --> 
           var mapprojection = new OpenLayers.Projection("EPSG:42304");
           
           <!-- Creating bounds for the layers in projected coordinates --> 
           var full = new OpenLayers.Bounds(-2300000, -1000000, 2700000, 3500000);
           var init = new OpenLayers.Bounds(300000, -800000, 1300000, 200000);
           
           <!-- Set up a variable to hold the map object, and create the map. --> 
           var map = new OpenLayers.Map('map', 
               {
                   projection: mapprojection,
                   maxExtent: full,
                   restrictedExtent: full
               });
           <!-- Add the layers to the map. In this case only 'layers' has to be called because multiple WMS layers were placed in
           a single OpenLayers layer --> 
           map.addLayers(layers);
           map.zoomToExtent(init);
           map.setCenter(new OpenLayers.LonLat(lon, lat), zoom);
           //map.addControl(new OpenLayers.Control.PanZoomBar);//
           //map.addControl(new OpenLayers.Control.MousePosition())//
           //map.addControl( new OpenLayers.Control.LayerSwitcher() );//
       };
   </script>
 </body>
</html>


Projections

As shown within the HTML code, the projection of the map is EPSG:42304. EPSG refers to European Petroleum Survey Group, which is now-defunct, but has been absorbed into the International Association of Oil and Gas Producers (OGP) Geomatics Committee. They are an authority for maintaining map projection codes in order for there to be a standard directory of projections [2].

As for the code EPSG:42304, this refers to the Lambert Conformal Conic projection, based on the NAD83 datum. The bounds that have been specified for this map were created using these projected coordinates. The bounds are then used to generate the WMS requests by the OpenLayers library.

In order to complete transformations, PROJ.4 can be used. It is a Free and Open Source Software (FOSS) library that allows users to perform conversions between cartographic projections. However, it should be noted that the software only transforms from either projected coordinates to unprojected lat/long coordinates, or from unprojected lat/long coordinates to projected coordinates. Thus if you want to transform the data from one projected coordinate system to another, you must undertake a two-step process where you first transform to unprojected lat/long, then transform again to the desired coordinate system.


Computing Bounding Boxes

If a user wants to recompute bounding boxes from EPSG:42304 (or any other projection) to unprojected lat/long coordinates (EPSG:4269), PROJ.4 can be used. Instructions regarding installation can be found here.

First, the user should change the projection code in the HTML code. In this case, changing it from EPSG:42304 (Projected Lambert Conformal Conic) to EPSG:4269 (unprojected lat/long). Now the user can computer new 'full' and 'init' unprojected bounding boxes using PROJ.4. The lines within the HTML code that contain the bounding box numbers are shown below:


Boundingboxcode.png


In order, the numbers refer to: (left limit, bottom limit, right limit, top limit). The left limit and bottom limit numbers give you the (x,y) coordinates of the bottom left corner, and the right limit and top limit give you the (x,y) coordinates of the top right corner. For each of these points, you can use PROJ.4 to computer inverse projections from those coordinates. This will give you new bounding box numbers in unprojected lat/long angular coordinates. If you then want to transform back to a projected coordinate system, you can complete a forward projection transformation, once again generating new bounding box numbers that are new rectangular coordinates. Full documentation regarding how this is done with PROJ.4 can be found at ftp://ftp.remotesensing.org/proj/proj.4.3.pdf


Resulting Maps

Openlayersmapzoom9.2.png

Figure 2. Displaying the OpenLayers map window created by the above HTML code.


Figure 2 is the result of the HTML code in Section 3.3. It shows the land cover make-up of the Ottawa area. As this image is rather zoomed in, the land cover, water and roads layers are visible. Figure 3 is included because it shows the Ottawa area at a lower zoom level. From this level, all of the overlay layers are visible, including the populated places layer. This is useful for those who do not know the coordinates of the location they may want to view, or if they want to browse the area surrounding their desired location.


The data product specifications regarding the land cover layer can be found here, and the land cover classification legend can be found here.


Additionally, the two maps do not have OpenLayers controls added to the map window. These could include a PanZoomBar, mouse position coordinates, and a layer switcher option. If the user desires these controls, the code required to insert them can be found here.



Openlayersmapzoom7.png

Figure 3. Displaying the OpenLayers map window of the same area as Figure 2, but at a lesser zoom level.


Access to Testing Example

The OpenLayers WMS example used in this tutorial is available to download here.


References

OGC WMS Standards http://www.opengeospatial.org/standards/wms

OGP Geomatics Committee http://www.epsg.org