Table of Contents for
OpenLayers 3 : Beginner's Guide

Version ebook / Retour

Cover image for bash Cookbook, 2nd Edition OpenLayers 3 : Beginner's Guide by Erik Hazzard Published by Packt Publishing, 2015
  1. Cover
  2. Table of Contents
  3. OpenLayers 3 Beginner's Guide
  4. OpenLayers 3 Beginner's Guide
  5. Credits
  6. About the Authors
  7. About the Reviewers
  8. www.PacktPub.com
  9. Preface
  10. What you need for this book
  11. Who this book is for
  12. Sections
  13. Time for action – heading
  14. Conventions
  15. Reader feedback
  16. Customer support
  17. 1. Getting Started with OpenLayers
  18. Advantages of using OpenLayers
  19. What, technically, is OpenLayers?
  20. Anatomy of a web mapping application
  21. Connecting to Google, Bing Maps, and other mapping APIs
  22. Time for action – downloading OpenLayers
  23. Time for action – creating your first map
  24. Where to go for help
  25. OpenLayers issues
  26. OpenLayers source code repository
  27. Getting live news from RSS and social networks
  28. Summary
  29. 2. Key Concepts in OpenLayers
  30. Time for action – creating a map
  31. Time for action – using the JavaScript console
  32. Time for action – overlaying information
  33. OpenLayers' super classes
  34. Key-Value Observing with the Object class
  35. Time for action – using bindTo
  36. Working with collections
  37. Summary
  38. 3. Charting the Map Class
  39. Time for action – creating a map
  40. Map renderers
  41. Time for action – rendering a masterpiece
  42. Map properties
  43. Time for action – target practice
  44. Map methods
  45. Time for action – creating animated maps
  46. Events
  47. Views
  48. Time for action – linking two views
  49. Summary
  50. 4. Interacting with Raster Data Source
  51. Layers in OpenLayers 3
  52. Common operations on layers
  53. Time for action – changing layer properties
  54. Tiled versus untiled layers
  55. Types of raster sources
  56. Tiled images' layers and their sources
  57. Time for action – creating a Stamen layer
  58. Time for action – creating a Bing Maps layer
  59. Time for action – creating tiles and adding Zoomify layer
  60. Image layers and their sources
  61. Using Spherical Mercator raster data with other layers
  62. Time For action – playing with various sources and layers together
  63. Time For action – applying Zoomify sample knowledge to a single raw image
  64. Summary
  65. 5. Using Vector Layers
  66. Time for action – creating a vector layer
  67. How the vector layer works
  68. The vector layer class
  69. Vector sources
  70. Time for action – using the cluster source
  71. Time for action – creating a loader function
  72. Time for action – working with the TileVector source
  73. Time for action – a drag and drop viewer for vector files
  74. Features and geometries
  75. Time for action – geometries in action
  76. Time for action – interacting with features
  77. Summary
  78. 6. Styling Vector Layers
  79. Time for action – basic styling
  80. The style class
  81. Time for action – using the icon style
  82. Have a go hero – using the circle style
  83. Multiple styles
  84. Time for action – using multiple styles
  85. Style functions
  86. Time for action – using properties to style features
  87. Interactive styles
  88. Time for action – creating interactive styles
  89. Summary
  90. 7. Wrapping Our Heads Around Projections
  91. Time for action – using different projection codes
  92. Time for action – determining coordinates
  93. OpenLayers projection class
  94. Transforming coordinates
  95. Time for action – coordinate transforms
  96. Time for action – setting up Proj4js.org
  97. Time for action – reprojecting extent
  98. Time for action – using custom projection with WMS sources
  99. Time for action – reprojecting geometries in vector layers
  100. Summary
  101. 8. Interacting with Your Map
  102. Time for action – converting your local or national authorities data into web mapping formats
  103. Time for action – testing the use cases for ol.interaction.Select
  104. Time for action – more options with ol.interaction.Select
  105. Introducing methods to get information from your map
  106. Time for action – understanding the forEachFeatureAtPixel method
  107. Time for action – understanding the getGetFeatureInfoUrl method
  108. Adding a pop-up on your map
  109. Time for action – introducing ol.Overlay with a static example
  110. Time for action – using ol.Overlay dynamically with layers information
  111. Time for action – using ol.interaction.Draw to share new information on the Web
  112. Time for action – using ol.interaction.Modify to update drawing
  113. Understanding interactions and their architecture
  114. Time for action – configuring default interactions
  115. Discovering the other interactions
  116. Time for action – using ol.interaction.DragRotateAndZoom
  117. Time for action – making rectangle export to GeoJSON with ol.interaction.DragBox
  118. Summary
  119. 9. Taking Control of Controls
  120. Adding controls to your map
  121. Time for action – starting with the default controls
  122. Controls overview
  123. Time for action – changing the default attribution styles
  124. Time for action – finding your mouse position
  125. Time for action – configuring ZoomToExtent and manipulate controls
  126. Creating a custom control
  127. Time for action – extending ol.control.Control to make your own control
  128. Summary
  129. 10. OpenLayers Goes Mobile
  130. Using a web server
  131. Time for action – go mobile!
  132. The Geolocation class
  133. Time for action – location, location, location
  134. The DeviceOrientation class
  135. Time for action – a sense of direction
  136. Debugging mobile web applications
  137. Debugging on iOS
  138. Debugging on Android
  139. Going offline
  140. Time for action – MANIFEST destiny
  141. Going native with web applications
  142. Time for action – track me
  143. Summary
  144. 11. Creating Web Map Apps
  145. Using geospatial data from Flickr
  146. Time for action – getting Flickr data
  147. A simple application
  148. Time for Action – adding data to your map
  149. Styling the features
  150. Time for action – creating a style function
  151. Creating a thumbnail style
  152. Time for action – switching to JSON data
  153. Time for action – creating a thumbnail style
  154. Turning our example into an application
  155. Time for action – adding the select interaction
  156. Time for action – handling selection events
  157. Time for action – displaying photo information
  158. Using real time data
  159. Time for action – getting dynamic data
  160. Wrapping up the application
  161. Time for action – adding dynamic tags to your map
  162. Deploying an application
  163. Creating custom builds
  164. Creating a combined build
  165. Time for action – creating a combined build
  166. Creating a separate build
  167. Time for action – creating a separate build
  168. Summary
  169. A. Object-oriented Programming – Introduction and Concepts
  170. Going further
  171. B. More details on Closure Tools and Code Optimization Techniques
  172. Introducing Closure Library, yet another JavaScript library
  173. Time for action – first steps with Closure Library
  174. Making custom build for optimizing performance
  175. Time for action – playing with Closure Compiler
  176. Applying your knowledge to the OpenLayers case
  177. Time for action - running official examples with the internal OpenLayers toolkit
  178. Time for action - building your custom OpenLayers library
  179. Syntax and styles
  180. Time for action – using Closure Linter to fix JavaScript
  181. Summary
  182. C. Squashing Bugs with Web Debuggers
  183. Time for action – opening Chrome Developer Tools
  184. Explaining Chrome Developer debugging controls
  185. Time for action – using DOM manipulation with OpenStreetMap map images
  186. Time for action – using breakpoints to explore your code
  187. Time for action – playing with zoom button and map copyrights
  188. Using the Console panel
  189. Time for action – executing code in the Console
  190. Time for action – creating object literals
  191. Time for action – interacting with a map
  192. Improving Chrome and Developer Tools with extensions
  193. Debugging in other browsers
  194. Summary
  195. D. Pop Quiz Answers
  196. Chapter 5, Using Vector Layers
  197. Chapter 7, Wrapping Our Heads Around Projections
  198. Chapter 8, Interacting with Your Map
  199. Chapter 9, Taking Control of Controls
  200. Chapter 10, OpenLayers Goes Mobile
  201. Appendix B, More details on Closure Tools and Code Optimization Techniques
  202. Appendix C, Squashing Bugs with Web Debuggers
  203. Index

Time for action – first steps with Closure Library

Although we can download the library on our computer, to remain simple, we will use a remote JavaScript library version.

  1. Create an HTML page using your text editor and cut and paste the following code:
    <!DOCTYPE html>
    <html>
      <head>
        <title>Dom manipulation</title>
        <script src='https://rawgit.com/google/closure-library/master/closure/goog/base.js'></script>
        <script>
          goog.require('goog.dom');
    
         </script>
      </head>
      <body>
        <ul id="my_layers_list">
          <li>My first layer</li>
    
          <li>My second layer</li>
          <li>My third layer</li>
          <li>My background or base layer</li>
        </ul>
        <script>
          var my_layers_list = goog.dom.getElement('my_layers_list');
          var myTitle = goog.dom.createDom('h1');
          var myText = goog.dom.createTextNode("My simple layers list");
          goog.dom.append(myTitle, myText);
          goog.dom.insertSiblingBefore(myTitle, my_layers_list);
        </script>
      </body>
    </html>
  2. Open your browser to see the following result:
    Time for action – first steps with Closure Library

What just happened?

In order to understand the code, let's review the lines related to the Google Library:

<script src='https://rawgit.com/google/closure-library/master/closure/goog/base.js'>
</script>

Load the library base from a remote file. The code hosted on Github, needs to use a third-party website https://rawgit.com to be able to serve the .js files:

goog.require('goog.dom'); 

This line is the way to say make available the function from goog.dom namespace of the library. If you forget this call, every function call starting with goog.dom will fail. This call adds a call to <script src='https://rawgit.com/google/closure-library/master/closure/goog/base.js'> and must be separated in a dedicated <script> tag.

The goal here is to load only required functions and to keep your JavaScript clean with namespacing. Namespace enables separation of functions based on a common name. The chosen namespace for the Google Library is goog, so every function based on the library will start with goog. In this case, the goog.dom namespace is created. To discover the available functions in the namespace, you can use your JavaScript debugger and type goog.dom var my_layers_list = goog.dom.getElement('my_layers_list');. This line selects from DOM the element with an attribute ID, 'my_layer_lists'.

var myTitle = goog.dom.createDom('h1'); creates an <h1> tag in an HTML fragment, an element separated from the DOM, which you plan to add later to the web page DOM:

var myText = goog.dom.createTextNode("My simple layers list");

The following code line adds a text node, the visible element in HTML you will see in a web page.

goog.dom.append(myTitle, myText);

Add the text node to the <h1> tag. That is, the two previous floating elements <h1> </h1> and My simple layers list became: <h1>My simple layers list</h1>

goog.dom.insertSiblingBefore(myTitle, my_layers_list); 

Add the combined fragment to the DOM: it will be visible in your browser. We choose to use the insertSiblingBefore method. Its purpose is to add a fragment in the DOM before a reference DOM element. So, the text with <h1> tags will appear before the list.

With this example, we have reviewed a small subset of the goog.dom functions.

You will need them, for example, for interactivity like displaying an element with a color change, or for having an application that reacts to a click of a button.

Note

Google library is an ever evolving JavaScript library

In a real context, outside experimentations such as the first Closure Library code example, you will need to retrieve it using an SCM (Source Code Management) software. Its goal is to follow every change in the code. It is one of the most useful tools for developers. The one you need is called Git. Don't worry about it at the moment, we will need it in the Installing the OpenLayers development environment section. For now, just remember the URL to get the code from https://github.com/google/closure-library

To give you an overview of the most useful functions, we have mentioned below some statistics on the most used namespaces and sub-namespaces' functions in the OpenLayers 3 library. We also chose to keep the functions at the first level such as goog.require(. You can make the distinction between functions and namespaces with the open parenthesis. We also ordered the list in the following table:

Namespace and sub-namespaces

Numbers of occurrences

goog.require(

1436

goog.asserts

812

goog.isDef(

765

goog.isNull(

349

goog.provide(

295

goog.object

289

goog.base(

196

goog.inherits(

168

goog.events, goog.vec

136

goog.dom

113

goog.array

100

goog.exportProperty(

81

goog.math

72

goog.isDefAndNotNull(

68

goog.getUid(

39

goog.style

35

goog.isString(

22

goog.bind(

21

goog.string

14

goog.partial(

13

goog.isArray

12

goog.global

11

goog.addSingletonGetter(, goog.dispose(

9

goog.log, goog.uri.utils

5

goog.functions, goog.Uri, goog.now(

4

goog.net, goog.isFunction(, goog.isObject(

3

goog.async, goog.isNumber(

2

goog.color, goog.debug, goog.fs, goog.fx, goog.json, goog.userAgent, goog.isBoolean(, goog.Uri(

1

Let's talk about goog.require and goog.provide. The Google Library, and hence the OpenLayers internal code, manages dependencies using these two declarations. In a file, goog.require helps declaring required functions needed in the application code, whereas the goog.provide is the opposite: it permits declaring that some functions are within a file. These declarations combined with Closure Compiler usage help solve dependencies between the various library files and also with the application code. Reusing these dependencies will enable combining code for production.

Other important functions are goog.inherits and goog.base: you will find them to apply inheritance concepts already evoked in Appendix A, Object-oriented Programming – Introduction and Concepts.

With previous functions, you might think that some functions not at the top of the list are not useful, but you shouldn't. In fact, we invite you to review them because the code for the core of a JavaScript library differs from the code application to use it. In particular, look at goog.userAgent functions or goog.style.

Note

To have an overview of the available functions, the recommended way is to visit the official website, https://developers.google.com/closure/library/, to review the API, http://docs.closure-library.googlecode.com/git/index.html. For samples, look at the available demos you have to use at https://github.com/google/closure-library/tree/master/closure/goog/demos/. It's a great complementary help to the API, in particular to get an overview of the goog.ui components.

Next, let's head to an example to make your own component using Closure Library.

Custom components

When a component is not available, you will have to write some application code or for reuse purpose, make your own. In this section, we will first review some of the concepts of JavaScript applied with Google Closure Library. After this, we will see one of the official sample code to understand how to use the library to create your own customized component.

Inheritance, dependencies, and annotations

Let's start with the inheritance. It should ring a bell; otherwise, you should review Appendix A, Object-oriented Programming – Introduction and Concepts. This example will be enough to introduce you to other key concepts of the library:

<!DOCTYPE html>
<html>
  <head>
    <title>Inheritance</title>
    <script src='https://rawgit.com/google/closure-library/master/closure/goog/base.js'></script>
  </head>
  <body>
  <script>
    //Parent Class
    goog.provide('myNamespace.layer.Layer');
    /**
     * @constructor
     */
    myNamespace.layer.Layer = function (options) {
        this.color_ = options.color || 'grey';
    }
    myNamespace.layer.Layer.prototype.getColor = function () {
        return this.color_;
    }
    //Sub Class
    goog.provide('myNamespace.layer.Vector');
    /**
     * @constructor
     * @extends {myNamespace.layer.Layer}
     */
    myNamespace.layer.Vector = function (options) {
        goog.base(this, options);
        if (options.style) {
           this.style_ = options.style;
        }
    }
    goog.inherits(myNamespace.layer.Vector, myNamespace.layer.Layer);
    //Create a new instance of Vector layer and call to method from parent class.
    var myVector = new myNamespace.layer.Vector({
       color: 'white',
       style: 'myStyle'
    });
    console.log(myVector.getColor());
  </script>
  </body>
</html>

Launch it in your browser with the debugger, like Google Developer Tools, opened.

Let's review the code for the main lines:

<script src='http://closure-library.googlecode.com/svn/trunk/closure/goog/base.js'>
</script>

This inserts the call to Closure Library:

goog.provide('myNamespace.layer.Layer');

This declares the parent namespace (and class) with goog.provide:

/**
* @constructor
*/
myNamespace.layer.Layer = function (options) {
    this.color_ = options.color || 'grey';
}

This declares the parent constructor:

myNamespace.layer.Layer.prototype.getColor = function () {
    return this.color_;
}

This adds a method to the prototype of the object:

goog.provide('myNamespace.layer.Vector');

This declares the children's namespace (and class) with goog.provide:

/**
* @constructor
* @extends {myNamespace.layer.Layer}
*/
myNamespace.layer.Vector = function (options) {
  goog.base(this, options);
  if (options.style) {
    this.style_ = options.style;
  }
}

This declares the children's constructor and specifies who the parent is, in comments with @extends.

In the function, goog.base(this, options); can be replaced with myNamespace.layer.Layer.call(this, options); for a pure JavaScript alternative. It says to call the options from the current constructor:

goog.inherits(myNamespace.layer.Vector, myNamespace.layer.Layer);

This makes myNamespace.layer.Vector inherit from its parent myNamespace.layer.Layer.

var myVector = new myNamespace.layer.Vector({
    color: 'white',
    style: 'myStyle'
});
console.log(myVector.getColor());

This instantiates myNamespace.layer.Vector with options and makes a console call to get the method call to the parent class in order to retrieve the color.

Until now, we mainly covered Closure Library, but this knowledge can be reused in OpenLayers. You will see that OpenLayers application code can really look like Closure Library.

Have a go hero – analyze a real OpenLayers case

To see the similarity between Closure Library and OpenLayers application code, we will review inheritance in a real OpenLayers context. So, we will ask you to review an official example available at http://openlayers.org/en/v3.0.0/examples/custom-controls.html.

It will also be a good opportunity to review inheritance knowledge from Chapter 2, Key Concepts in OpenLayers; Chapter 9, Taking Control of Controls and Appendix A, Object-oriented Programming – Introduction and Concepts.

This example contains the following JavaScript content:

/**
 * Define a namespace for the application.
 */
window.app = {};
var app = window.app;

//
// Define rotate to north control.
//

/**
 * @constructor
 * @extends {ol.control.Control}
 * @param {Object=} opt_options Control options.
 */
app.RotateNorthControl = function(opt_options) {

  var options = opt_options || {};

  var anchor = document.createElement('a');
  anchor.href = '#rotate-north';
  anchor.innerHTML = 'N';

  var this_ = this;
  var handleRotateNorth = function(e) {
    // prevent #rotate-north anchor from getting appended to the url
    e.preventDefault();
    this_.getMap().getView().setRotation(0);
  };

  anchor.addEventListener('click', handleRotateNorth, false);
  anchor.addEventListener('touchstart', handleRotateNorth, false);

  var element = document.createElement('div');
  element.className = 'rotate-north ol-unselectable';
  element.appendChild(anchor);

  ol.control.Control.call(this, {
    element: element,
    target: options.target
  });

};
ol.inherits(app.RotateNorthControl, ol.control.Control);

//
// Create map, giving it a rotate to north control.
//

var map = new ol.Map({
  controls: ol.control.defaults({
    attributionOptions: /** @type {olx.control.AttributionOptions} */ ({
      collapsible: false
    })
  }).extend([
    new app.RotateNorthControl()
  ]),
  layers: [
    new ol.layer.Tile({
      source: new ol.source.OSM()
    })
  ],
  renderer: exampleNS.getRendererFromQueryString(),
  target: 'map',
  view: new ol.View({
    center: [0, 0],
    zoom: 2,
    rotation: 1
  })
});

These questions are for improvement:

  • Where does the code instantiate the RotateNorthControl component?
  • What is the parent class?
  • Where are the constructors and its methods?
  • What is the difference between the two methods (hint in the comments)?
  • Where do you declare inheritance (hint: ol.inherits is an alias to goog.inherits)?

Until now, we focused on Closure Library. However, as we mentioned at the start of this chapter, for performance, we need to use Closure Compiler as well. It is time to do it!