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 – creating interactive styles

Now we have the knowledge we need to build our final example. We will add some interactivity to our countries layer by highlighting the country under the mouse with a different style—specifically, we will:

  • Draw the highlighted country with a red outline and semitransparent fill
  • Draw an icon at the center of the highlighted country representing its flag
  • Draw the country's name next to the flag
  1. First, we'll need a new file. Let's start again with the basic country vector layer:
    var countries = new ol.layer.Vector({
      source: new ol.source.GeoJSON({
        projection: 'EPSG:3857',
        url: '../assets/data/countries.geojson'
      })
    });
    var center = ol.proj.transform([0, 0], 'EPSG:4326', 'EPSG:3857');
    var view = new ol.View({
      center: center,
      zoom: 1,
    });
    var map = new ol.Map({
      target: 'map',
      layers: [countries],
      view: view
    });
  2. Next, we'll set up some styles for our highlighted features. This code can go right after the map is defined. Don't worry if you don't remember what everything does—we'll review the code at the end:
    var baseTextStyle = {
      font: '12px Calibri,sans-serif',
      textAlign: 'center',
      offsetY: -15,
      fill: new ol.style.Fill({
        color: [0,0,0,1]
      }),
      stroke: new ol.style.Stroke({
        color: [255,255,255,0.5]
        width: 4
      })
    };  
    var highlightStyle = new ol.style.Style({
      stroke: new ol.style.Stroke({
        color: [255,0,0,0.6],
        width: 2
      }),
      fill: new ol.style.Fill({
        color: [255,0,0,0.2]
      }),
      zIndex: 1
    });
  3. We'll be using a style function with our feature overlay because we need to dynamically create styles for the feature being rendered:
    function styleFunction(feature, resolution) {
      var style;
      var geom = feature.getGeometry();
      if (geom.getType() == 'Point') {
        var text = feature.get('text');
        baseTextStyle.text = text;
        var isoCode = feature.get('isoCode').toLowerCase();
        style = new ol.style.Style({
          text: new ol.style.Text(baseTextStyle),
          image: new ol.style.Icon({
            src: '../assets/img/flags/'+isoCode+'.png'
          }),
          zIndex: 2
        });
      } else {
        style = highlightStyle;
      }
      return [style];
    }
  4. We also need to create the feature overlay itself. It's pretty straightforward as the style function is doing all the work for us:
    var featureOverlay = new ol.FeatureOverlay({
      map: map,
      style: styleFunction
    });
  5. Finally, the interactive part. We'll add a handler for the map's pointermove event and manage the features in our feature overlay based on where the mouse is. This is a pretty big function that exercises our knowledge of geometries from the previous chapter:
    map.on('pointermove', function(browserEvent) {
      featureOverlay.getFeatures().clear();
      var coordinate = browserEvent.coordinate;
      var pixel = browserEvent.pixel;
      map.forEachFeatureAtPixel(pixel, function(feature, layer) {
        if (!layer) {
          return; // ignore features on the overlay
        }
        var geometry = feature.getGeometry();
        var point;
        switch (geometry.getType()) {
        case 'MultiPolygon':
          var poly = geometry.getPolygons().reduce(function(left, right) {
            return left.getArea() > right.getArea() ? left : right;
          });
          point = poly.getInteriorPoint().getCoordinates();
          break;
        case 'Polygon':
          point = geometry.getInteriorPoint().getCoordinates();
          break;
        default:
          point = geometry.getClosestPoint(coordinate);
        }
        textFeature = new ol.Feature({
          geometry: new ol.geom.Point(point),
          text: feature.get('name'),
          isoCode: feature.get('iso_a2').toLowerCase()
        });
        featureOverlay.addFeature(textFeature);
        featureOverlay.addFeature(feature);
      });
    }
  6. Load this in your browser and try it out! You should see something like the following screenshot when you move the mouse over a country:
    Time for action – creating interactive styles

What just happened?

As you can see, feature overlays make it very simple to create an interactive experience with vector layers. There are a few new concepts in this example, as well as some old ones, so let's review the code step by step.

Step 1 should be pretty familiar to you now—we are creating a vector layer with a GeoJSON source, and adding it to a map with a view centered on 0,0.

In step 2, we set up some styles for our feature overlay to use. There are two styles—one for text and one for polygon highlighting. Notice that the baseTextStyle is an object literal, not a new instance of ol.style.Text. When you create an instance of ol.style.Text, the text to be drawn needs to be passed to that object and you can't change the text after it has been created. The style function allows us to create text styles with the text of the current feature, but we'll need to specify the other options. Since all labels will share the other text options, we can set them up once and just refer to them later in the style function. The options we've specified here are to center align the text, offset it up by 15 pixels (recall that a positive offsetY moves the text down), and provide a fill and stroke color. For the text, the stroke is rendered around the outside of each character so we set a wide, semitransparent stroke to make the text stand out from the map beneath it.

The highlightStyle is straightforward— a fill and stroke style for the highlighted polygon.

The style function needs to be defined before we can use it to create the feature overlay, so in step 3, we defined it. Recall that the style function receives the feature being rendered as the first argument. We drew two types of features, points, and polygons, with two different styles. So, the first thing we did was get the feature's geometry and check to see whether it was a point. If it is a point, we create a new text style and a new icon style specific to the current feature. We got the feature's text property and combined it with the baseTextStyle object to create the text style. Next, we got the isoCode property and used it to create a URL to the flag for the country (the flag icons are conveniently named using the two-letter ISO country code) for a new icon style. Then, we created a new style object for the current feature. If the feature is a polygon, it's much simpler—all we need to do is return the highlightStyle object. Finally, we returned an array containing the style (recall that style functions are required to return arrays for performance reasons).

Step 4, by comparison, was very short! We created a new feature overlay and configured it with the map object and style function. It's really the style function, and step 5, that do all the work.

Step 5 added a handler for the map's pointermove event; so, we could find the feature closest to the mouse and add it to the feature overlay. We actually wanted to highlight two features— the polygon itself and a point at the center of the polygon. It turns out that getting this center point is a bit tricky. Let's review the code carefully.

Line 1 of code in the handler clears any existing features in the feature overlay. It is much easier to retrieve the collection and clear it than to remove individual features in our case.

The browserEvent object provides us with the map coordinate and pixel that the event happened at. We used the pixel location with ol.Map classes forEachFeatureAtPixel function on the next line to retrieve all features at that location from our vector layer. This function invokes a callback function for every feature at the pixel location, providing both the feature and the layer that the feature was found on. The layer parameter may be null if the feature was found on a FeatureOverlay.

Inside our callback function, we tested first to see if the feature was actually on a layer before proceeding. Then we needed to find both the geometry and the center point of the geometry. If all the country features were polygons, we could simply call getInteriorPoint() to retrieve the center and we would be done. Unfortunately, we didn't know what type of features we were dealing with—some of the features in the country data were actually MultiPolygons, and we needed to handle them differently. The switch statement chooses a path based on the type of the feature. Let's look at each case separately.

The first case was for MultiPolygon. As the name suggests, a MultiPolygon class contains multiple polygons (a country and some islands perhaps) and there isn't a convenient way to determine the center of a group of polygons. Instead, a MultiPolygon class has several centers, one for each of its constituent polygons. The getInteriorPoints() method returns the center points for us. We only really wanted a single label though. One way is to get all the interior points and use the first one. The problem with this approach is that there is no particular order to the polygons, and it looks odd to label some random island off the coast rather than the major landmass of a given country. To get around this, we wanted our label to appear at the center of the largest polygon. To get the largest polygon, we first got the array of polygons and then reduced that array to a single value with a function that compared two polygons based on their area. The reduce method is a standard method of JavaScript arrays. Once we've found the largest polygon, we can ask for its interior point.

The second case is for polygon, and was much simpler— we just needed the interior point of the polygon and we were done!

The final case was the default case. While it isn't strictly needed, it is good practice to include a default case in switch statements. The getClosestPoint() method is available on all geometry types and is a safe fallback for our default case.

Now that we had a point coordinate at the best location we could determine for the feature under the mouse, we created a new Feature and provided the point geometry for its location. We also added two properties—text (that we displayed at the point) and isoCode (that we will use to find the flag icon for the country).

Finally, we added both features to the feature overlay so that when the map is next rendered, the country under the mouse will be highlighted in red and display the flag and country name at the center.