EXERCISE: Developing geo-web application with OpenLyers 3

Ivana Ivánová Milton Hirokazu Shimabukuro Barend öbben

September 1, 2015

Contents

1 Introduction2

2 Adding a to a website — using OpenLayers 32

3 Adding external web map services to a map5 3.1 Spatial reference systems in OpenLayers 3...... 9 3.2 Adding legend to a map...... 10 3.3 Setting the visibility of layers...... 11 3.4 Using the GetFeatureInfo operation with OpenLayers 3...... 12

4 Adding more layers 13

5 Summary 13

©FCT/UNESP This document may be freely reproduced for educa- tional use. It may not be edited or translated without the consent of the copyright holder. Objectives of this exercise In this exercise you will learn the how to: • create a simple website with HTML and JavaScript; • add spatial content ( and web map services to a website with Open- Layers 3; • add controls for manipulating the spatial content on a website;

NOTE: This exercise was developed using materials and tutorials available at Open- Layaer’s website (http://www.openlayers.org).

NOTE 2: Throughout the whole exercise, take care of this special character in the code listings: → — this is a line breaking character used by the typesetting environ- ment of this exercise document (if you must know ;-), it is the listing package of the LATEXtypesetting system). The → character means the line of the code should be typed without interruption (i.e. you should not type a return or enter in this place).

© Faculdade de Ciências e Tecnologia da Universidade Estadual Paulista “Júlio de Mezquita de Filho” 1 1 Introduction

Geo-web applications are websites with mapping content in them. Geo-web application is a website — this means it is written in a language interpretable to the web browser; this language is called the HyperText Markup Language (HTML). JavaScript language is used to allow user interaction in websites.

Geo-web applications are usually targeted to a specific user group which determines the selection of the spatial content itself — i.e. what kind of spatial data and in which data format is used. we will use the OpenLayers JavaScript library to put spatial content to our geo-web application.

2 Adding a map to a website — using OpenLayers 3

OpenLayers is a JavaScript library that allows putting dynamic mapping content to a website. Through an application programming interface it allows geo-web application developers putting spatial data in variety supported formats on a webpage.

We will explain how OpenLayers works using a complete working example from Open- Layer’s website1.

Task 1 : Create a new file and save it as . somewhere on your drive. Copy in the contents in listing1 to the new file, save and open it .html in a web browser. Ob- serve the indentation in this example file — indentation in the HTML and JavaScript language does not have syntactical nature, however, it improves the readability of the code tremendously.

Listing 1: map.html

Example OpenLayers3 page

1 http://openlayers.org/en/v3.1.1/doc/quickstart.html and http://openlayers.org/ ol3-workshop/basics/map.html

2 Ivana Ivánová

My Map

To include a map on a web page we will need three things:

1. Include the OpenLayers library, which allows us to put spatial content on a web- page:

This line includes the OpenLayers library to the webpage:

With this JavaScript code, a map object is created with a layer from the MapQuest tile server 2 zoomed on the Porte Maillot station in Neuilly, Paris (France). Let’s look closer at our script:

• The following line var map = new ol.Map({ ... }); creates an OpenLayers Map object. Just by itself, this does nothing since there is no layers or interaction attached to it. 2 http://www.mapquest.com/

4 Ivana Ivánová • We attach the map object to the

, with
the map object takes a target into arguments. The value is the id of the
: target: ’map’

• The layers: [ ... ] array is used to define the list of layers available in the map. The first and only layer right now is a tiled layer: layers: [ new ol.layer.Tile({ source: new ol.source.MapQuest({layer: ’sat’}) }) ]

Layers in OpenLayers 3 are defined with a type (Image, Tile or Vector) which contains a source. The source is the protocol used to get the map tiles. You can consult the list of available layer sources here: http://openlayers.org/en/v3. 8.2/apidoc/ol.source.html

• The next part of the Map object is the View. The view allows specifying the center, resolution, and rotation of the map. The simplest way to define a view is to define a center point and a zoom level. Note that zoom level 0 is zoomed out. view: new ol.View({ center: [254031,6254016], zoom: 16 })

Note that the center specified is in coordinates defined in the spatial reference system called Pseudo-Mercator (EPSG: 3857), which is native to OpenLayers.

3 Adding external web map services to a map

After creating a simple map page, we will learn how to add more layers to it. In previous exercises you published your own web map services, and now let’s see how to add these services to our map. For this exercise we will create a new web page.

Task 2 : Create a new file and save it as map2.html somewhere on your drive. Copy in the contents in listing2 to the new file.

Listing 2: map2.html

© Faculdade de Ciências e Tecnologia da Universidade Estadual Paulista “Júlio de Mezquita de Filho” 5 OpenLayers 3 Example

My Map of Thailand

This is a simple .html file prepared to hold our mapping content. Observe the in- clusion of layers.js script in the head (find line in the of your document). Because our OpenLayers JavaScript code will be a bit more complex (and because we want to adhere to the programming paradigm of separating concerns) we will store our JavaScript mapping code in a separate file.

Task 3 : Create a new file and save it as layers.js in the same directory where your map2.html ‘lives’. •

In the following tasks we will step-by-step build our layers.js. Adding a layer is defined through several steps:

• definition of layer’s a data source,

• definition of the ‘initial behavior’ of the map, and

• addition of the layer to the map.

Task 4 : Defining the layer’s data source:

In our example, we will define the OpenStreetMap as the data source for the layer. Add MapQuest’s ‘osm’ data as the source for your layer. The code for this is the following:

6 Ivana Ivánová var source1 = new ol.source.MapQuest({layer: ’osm’}); var osmlayer = new ol.layer.Tile({source: source1});

We will now specify the ‘initial behavior’ of our map — in other words, what should happen when we open the webpage which includes our map(map.html), what kind of data should be displayed, what controls should our map have and where the view should be zoomed. We already know that we are displaying the OpenStreetMap data, we want to have some indication of the scale and we want to zoom our view to Thailand.

Task 5 : Building the init() function: Add the following code to your .js file to define the ‘initial behavior’ of the map on a webpage: function init() { var view = new ol.View({ center: ol.proj.transform([100.50, 13.96], ’EPSG:4326’, ’→ EPSG:3857’), zoom: 5 });

var map = new ol.Map({ target: ’map’, controls: ol.control.defaults().extend([ new ol.control.ScaleLine({ units: ’metric’ }) ]), view: view, });

map.addLayer(osmlayer); }

Finally we need to write a script for adding our layer to the map. You can do this by adding map.addLayer(osmlayer); script to the init() function. The complete annotated code for creation a simple map containing one layer (the OpenStreetMap) centered to Thailand is here: // definition of the layer source var source1 = new ol.source.MapQuest({layer: ’osm’}); var osmlayer = new ol.layer.Tile({source: source1});

// init() function referenced in the

© Faculdade de Ciências e Tecnologia da Universidade Estadual Paulista “Júlio de Mezquita de Filho” 7 function init() { var view = new ol.View({ center: ol.proj.transform([100.5, 13.96], ’EPSG:4326’, ’→ EPSG:3857’), zoom: 5 });

var map = new ol.Map({ // map as a composition of the view and controls target: ’map’, // link to the HTML object in which the map should be→ displayed controls: ol.control.defaults().extend([ new ol.control.ScaleLine({ units: ’metric’ }) ]), view: view, });

// adding layers to the map map.addLayer(osmlayer); }

Let’s now add more layers — once we are in zoomed to Thailand, we can add the web map services created during previous exercises. One of the possible data sources in OpenLayers 3 is ‘TileWMS’ object, which is the connector to the layer source for tile data servers. The ‘TileWMS’ is defined by the URL, several parameters (‘params’ in which at least the ‘LAYER’, holding the name of the layer, parameter is required) and the ‘serverType’

Task 6 : Create a new layer with Thailand’s forests:

• the URL to the service is: http://localhost:8080/geoserver//wms,

• the name of the layer is: :forest

• the server type is:

Add the following code to your .js file (NOTE: replace ‘’ with the name of your own workspace on GeoServer where you published your web services): var source2 = new ol.source.TileWMS({ url: ’http://localhost:8080/geoserver//wms’, params: {’LAYERS’: ’

var forestlayer = new ol.layer.Tile({ extent: → [97.3036041259766,5.54177093505859,105.680480957031,20.5437793731689],→

8 Ivana Ivánová source: source2 });

NOTE: the extent defined for the layer is the spatial extent in the spatial reference system you defined for your web map service on GeoServer. You can find these values in your WMS’s Capabilities document. •

And of course, do not forget to add your new layer to the map.

Task 7 : Include map.addLayer(forestlayer); script into the definition of your init() function (after you added the OSM layer to the map). •

After saving your updated script and reloading the map2.html in the browser, you may observe the changes. What happened? Most probably nothing. . . Let’s explain, why is this.

3.1 Spatial reference systems in OpenLayers 3

OpenLayers 3 default spatial reference systems (SRS) is the WGS84/Pseudo-Mercator (EPSG:3857) (also known as the Spherical Mercator). This is the projected coordinate system used for rendering maps in , OpenStreetMap, etc.3. As you may already know, there are many more spatial reference systems in the world (at least one per country). Moreover, our ‘Thailand’s web map services are defined in a spatial reference system, WGS84, which is different from the OpenLayer’s default system. This explains why nothing happened when you added your WMS layer to the map.

To make sure, a spatial layer is placed on the correct location, we want to be in control of using the layer’s proper spatial reference system. We can do this in two ways: 1. define one more SRS for a web map service published on our GeoServer, or 2. transform WMS’s current reference system to the reference systems of OpenLay- ers. Although option 1 is easy, and absolutely valid solution to our problem, we will now go for option 2. This is easily possible, because in addition to its default SRS, the Open- Layers 3 library also includes the definition of the World Geodetic system 84 (EPSG: 4326) together with the transformation parameters between these two systems. This is why we were able to transform ‘on-the-fly’ the coordinates of our view’s center in our first example zoomed to Thailand.

OpennLayers 3 has two methods allowing transformation between reference systems: 3 http://epsg.io/3857

© Faculdade de Ciências e Tecnologia da Universidade Estadual Paulista “Júlio de Mezquita de Filho” 9 1. ol.proj.transform for transforming coordinates, and

2. ol.proj.transformExtent for transforming spatial extent

We used the first for transforming the maps’s view coordinates, and now we need the second for transforming the spatial extent in which our forest layer is defined.

Let’s now repair our map by telling it to display our forest layer which is in WGS84, on top of the OSM layer:

Task 8 : Re-write your layer’s definition as follows: extent: ol.proj.transformExtent→ ([97.3036041259766,5.54177093505859,105.680480957031,20.5437793731689], ’EPSG→ :4326’, ’EPSG:3857’. This addition completes our forest layer definition to the fol- lowing code: var source2 = new ol.source.TileWMS({ url: ’http://localhost:8080/geoserver//wms’, params: {’LAYERS’: ’:forest’}, serverType: ’geoserver’, }); var forestlayer = new ol.layer.Tile({ extent: ol.proj.transformExtent→ ([97.3036041259766,5.54177093505859,105.680480957031,20.5437793731689],→ ’EPSG:4326’, ’EPSG:3857’), source: source2 });

When you refresh your map now, you should now see a a forest map layer on top of the OpenStreetMap layer. This is all fine, but it would be even better, if we’d have some clue that would help us interpreting the colors on the map — let’s see how can we add a map legend...

3.2 Adding legend to a map

OpenLayers 3 does not have an explicit ‘legend’ object, the reason probably is that the library was developed for putting dynamic spatial content on a website by making the web program understand that there are special — spatial — objects that are displayed. OpenLayers 3 provides some of the controls for interaction with the dynamic spatial content, such as the zoom buttons, that come by default with the ‘map’ object and the ‘scaleline’ which can be added manually. It does not deal with all other map decorations as we know them from the cartographic principles — legend is one of these decorations not provided by the OpenLayers 3.

Fortunately, our layers are Web Map Services which, are able to provide their own legend — the GetLegendGraphic service operation helps doing this, it returns an

10 Ivana Ivánová image with the layer’s legend. Having a URL to the layer’s legend, we can display the legend in the map, best, doing this with a placeholder (

) in the .html document.

Task 9 : Check in your WMS layer’s capabilities document if the web map service provides legend for your layer — note the legend’s URL. In your .html create a new placeholder (

) that will dosplay the legend, you may decide about its placement on the webpage and placeholder’s dimensions. For illustration, here is our example (NOTE: replace with the your own workspace name):
:→ forest&format=image/png&width=20&height=20">

OL3 OL3 We now have have two layers in our map, however, we cannot decide which one to see and which one not to see — can we fix this too?

3.3 Setting the visibility of layers

There are two parts of the solution to ths challenge:

1. a script (in our .js file) initiating the layer’s visibility status, and 2. an interactive placeholder for layers visibility switcher in our .html file.

Let’s write these codes:

Task 10 : In your .js file (at the end of the file) write a new function defining the initial status of the layer’s visibility — the code for this function is available here: function layerVis (value) { // function invoking the initial status of the→ layers’ visibility

if (value == "osmlayer" ) { osmlayer.setVisible(document.getElementById("1").checked); } else if (value == "forestlayer") { forestlayer.setVisible(document.getElementById("2").checked); } }

In your .html code create a new placeholder for layer visibility switcher — the example code is here:

© Faculdade de Ciências e Tecnologia da Universidade Estadual Paulista “Júlio de Mezquita de Filho” 11

Layer visibility switcher:

MapQuest-OpenStreetMap
Forest layer

Our map is almost ready, we want to include one more nice tool which will enhance our map’s usability. This is the tool will provide additional information about the spatial data displayed on the map and will use the GetFeatureInfo operation every web map service offers to write it.

3.4 Using the GetFeatureInfo operation with OpenLayers 3

As we already know, the GetFeatureInfo is a very handy operation web map services offer. It allows displaying additional, non-spatial attributes of our map layers upon users’ request executed by clicking on a feature of interest. OpenLayers 3 supports this operation as well, and here is how we can use it: • we need to include a function in our .js file allowing queries to the feature information related to our layers, and • we need to create a placeholder in our .html file for displaying this information.

Task 11 : Write a new function in your .js file for retrieving the feature information from a layer. This code will be part of the init() function — insert the code below your view definition: map.on(’singleclick’, function(evt) { // a click on a map allowing → displaying non-spatial attributes of the feature document.getElementById(’info’).innerHTML = → ’’; var viewResolution = /** @type {number} */ (→ view.getResolution()); var url = source2.getGetFeatureInfoUrl( evt.coordinate, viewResolution, ’→ EPSG:3857’, {’INFO_FORMAT’:’text/html’} ); if (url) { document.getElementById(’info’).innerHTML =

12 Ivana Ivánová ’’; } } );

Create a placeholder in your .html file for displaying features information — the code for this is here:

Click at the map to see additional information...
 

4 Adding more layers

You now know everything you need to execute the final task of this exercise: adding your own layers to your map.

Task 12 : Add WMS layers you published to the GeoServer to your map. Allow switching the visibility of the new layers, display layers’ legend and display layers’ non-spatial attributes upon request. •

5 Summary

In this exercise we practiced creating simple geo-web application with HTML5 and OpenLayers 3 and you should now be able to: • create a simple website with HTML and JavaScript; • add spatial content (maps and web map services) to a website with OpenLayers 3; • add controls for manipulating the spatial content on a website;

© Faculdade de Ciências e Tecnologia da Universidade Estadual Paulista “Júlio de Mezquita de Filho” 13