Table of Contents for
OpenLayers 3.x Cookbook - Second Edition

Version ebook / Retour

Cover image for bash Cookbook, 2nd Edition OpenLayers 3.x Cookbook - Second Edition by Antonio Santiago Perez Published by Packt Publishing, 2016
  1. Cover
  2. Table of Contents
  3. OpenLayers 3.x Cookbook Second Edition
  4. OpenLayers 3.x Cookbook Second Edition
  5. Credits
  6. About the Authors
  7. About the Reviewer
  8. www.PacktPub.com
  9. Preface
  10. What you need for this book
  11. Who this book is for
  12. Sections
  13. Conventions
  14. Reader feedback
  15. Customer support
  16. 1. Web Mapping Basics
  17. Creating a simple fullscreen map
  18. Playing with the map's options
  19. Managing the map's stack layers
  20. Managing the map's controls
  21. Moving around the map view
  22. Restricting the map's extent
  23. 2. Adding Raster Layers
  24. Using Bing imagery
  25. Using OpenStreetMap imagery
  26. Adding WMS layers
  27. Changing the zoom effect
  28. Changing layer opacity
  29. Buffering the layer data to improve map navigation
  30. Creating an image layer
  31. Setting the tile size in WMS layers
  32. 3. Working with Vector Layers
  33. Adding a GML layer
  34. Adding a KML layer
  35. Creating features programmatically
  36. Exporting features as GeoJSON
  37. Reading and creating features from a WKT
  38. Using point features as markers
  39. Removing or cloning features using overlays
  40. Zooming to the extent of a layer
  41. Adding text labels to geometry points
  42. Adding features from a WFS server
  43. Using the cluster strategy
  44. Reading features directly using AJAX
  45. Creating a heat map
  46. 4. Working with Events
  47. Creating a side-by-side map comparator
  48. Implementing a work-in-progress indicator for map layers
  49. Listening for the vector layer features' events
  50. Listening for mouse or touch events
  51. Using the keyboard to pan or zoom
  52. 5. Adding Controls
  53. Adding and removing controls
  54. Working with geolocation
  55. Placing controls outside the map
  56. Drawing features across multiple vector layers
  57. Modifying features
  58. Measuring distances and areas
  59. Getting feature information from a data source
  60. Getting information from a WMS server
  61. 6. Styling Features
  62. Styling layers
  63. Styling features based on geometry type
  64. Styling based on feature attributes
  65. Styling interaction render intents
  66. Styling clustered features
  67. 7. Beyond the Basics
  68. Working with projections
  69. Creating a custom control
  70. Selecting features by dragging out a selection area
  71. Transitioning between weather forecast imagery
  72. Using the custom OpenLayers library build
  73. Drawing in freehand mode
  74. Modifying layer appearance
  75. Adding features to the vector layer by dragging and dropping them
  76. Making use of map permalinks
  77. Index

Styling layers

To demonstrate some of the feature styling options that are available, we'll create a live editor in the side panel to style the features that are already loaded on to the map. To achieve this goal, we'll be using the jQuery UI library to create sliders and the jQuery plugin Spectrum for the color picker widget. The source code can be found in ch06/ch06-styling-layers. We'll end up with something that looks similar to the following screenshot:

Styling layers

For this recipe, we are going to apply styles at the layer level so that all features within a layer inherit the styling. The current state of all customizable styles will be reflected in the sidebar.

We'll be instantiating many instances of classes that belong to the ol.style object, such as ol.style.Stroke. Let's take a look at how this is implemented.

Getting ready

The source code has two main sections: one for HTML where all the controls are placed, and a second one for the JavaScript code.

The HTML section contains a lot of markup that gets converted to interactive widgets by the JavaScript, such as the slider and color picker. As mentioned earlier, we've also used the jQuery, jQuery UI (https://jqueryui.com) and Spectrum (https://bgrins.github.io/spectrum) libraries. As they're not the goal of this recipe, the HTML won't be listed out in the How to do it… section. I encourage you to take a look at the code in the code bundle of this book.

How to do it…

In order to create your own customized layer styling, follow these instructions:

  1. After creating the HTML file, including OpenLayers dependencies and other library dependencies (refer to the Getting ready section for the HTML code), create a custom JavaScript file and instantiate a new map instance, as follows:
    var map = new ol.Map({
      view: new ol.View({
        zoom: 10, center: [-12036691, 4697972]
      }),
      target: 'js-map',
      layers: [
        new ol.layer.Tile({
          source: new ol.source.MapQuest({layer: 'osm'})
        })
      ]
    });
  2. Create a vector layer for the source instance that loads in a GeoJSON file of features:
    var vectorLayer = new ol.layer.Vector({
      source: new ol.source.Vector({
        url: 'features.geojson',
        format: new ol.format.GeoJSON({
          defaultDataProjection: 'EPSG:3857'
        })
      })
    });
  3. Set up the function that brings the styling together so that it can be used to set the complete vector layer styling, as follows:
    var setStyles = function() {
      vectorLayer.setStyle(new ol.style.Style({
        stroke: strokeStyle(),
        fill: fillStyle(),
        image: new ol.style.Circle({
          fill: fillStyle(),
          stroke: strokeStyle(),
          radius: 8
        })
      }));
    };
  4. Set up the stroke-width and fill-opacity sliders with the jQuery UI. The handlers for the slide action call our setStyles method, and they display the relevant value in the DOM for the user to see, as follows:
    $('#js-stroke-width').slider({
      min: 1, max: 10, step: 1, value: 1,
      slide: function(event, ui) {
        $('#js-stroke-width-value').text(ui.value);
        setStyles();
      }
    });
    $('#js-fill-opacity').slider({
      min: 0, max: 100, step: 1, value: 50,
      slide: function(event, ui) {
        $('#js-fill-opacity-value').text(ui.value + '%');
        setStyles();
      }
    });
  5. Convert the markup for the stroke and fill colors to interactive color pickers with the help of the Spectrum jQuery plugin. When a new color is chosen, call our setStyles method:
    $('#js-stroke-color, #js-fill-color').spectrum({
      color: 'black', change: setStyles
    });
  6. Listen for changes in the stroke line style select menu and call our setStyles method:
    $('#js-stroke-style').on('change', setStyles);
  7. Set up the function that returns the fill style, as follows:
    var fillStyle = function() {
      var rgb = $('#js-fill-color').spectrum('get').toRgb();
      return new ol.style.Fill({
        color: [
          rgb.r, rgb.g, rgb.b,
          $('#js-fill-opacity').slider('value') / 100
        ]
      });
    };
  8. Set up the function that returns the stroke style, as follows:
    var strokeStyle = function() {
      return new ol.style.Stroke({
        color: $('#js-stroke-color').spectrum('get').toHexString(),
        width: $('#js-stroke-width').slider('value'),
        lineDash: $('#js-stroke-style').val() === 'solid'
          ? undefined : [8]
      });
    };
  9. Finish off by calling the setStyles function and add the vector layer to the map instance, as follows:
    setStyles();
    map.addLayer(vectorLayer);

How it works…

There's a lot of JavaScript to cover here if we take it line by line. What we're going to do instead is pluck out enough of the key functionality that will allow you to make sense of the overall code yourself:

var setStyles = function() {
  vectorLayer.setStyle(new ol.style.Style({
    stroke: strokeStyle(),
    fill: fillStyle(),
    image: new ol.style.Circle({
      fill: fillStyle(),
      stroke: strokeStyle(),
      radius: 8
    })
  }));
};

We create a function, namely setStyles, that'll be called from multiple places in the code when the user customizes the styling in the side panel. When this method is called, it returns a completed instance of the ol.style.Style object and passes it to the vector layer's setStyle method. This, in turn, causes the features on the map to be rerendered with the latest styling configuration.

The stroke property of ol.style.Style is assigned the value of the stroke style that is generated by the strokeStyle method, and the fill property is generated by the fillStyle method.

The image property is an instance of the ol.style.Circle styling object, which is the geometry type that point geometries are presented with. We repeat our usage of the fill and stroke methods to provide the values for the fill and stroke properties. We set a static radius of 8 for the circle style.

$('#js-stroke-width').slider({
  min: 1, max: 10, step: 1, value: 1,
  slide: function(event, ui) {
    $('#js-stroke-width-value').text(ui.value);
    setStyles();
  }
});

Let's take a look at just one of the jQuery slider setups for the stroke width. Once you're familiar with this slider function, you'll be able to ascertain how the other slider function for the fill opacity fits into the implementation of this recipe yourself.

We've limited the width to lie between 1 and 10, inclusive (with the min and max properties), and the default width is 1. We register a handler for the slide action that displays the updated value in the ($('#js-stroke-width-value').text(ui.value)) sidebar; this does not influence the style of the actual features against the map yet.

We then call our setStyles method, as we want the latest styling to be immediately reflected on the map.

$('#js-stroke-color, #js-fill-color').spectrum({
  color: 'black', change: setStyles
});

The other widget type that we'll cover in this chapter is for the color picker (we won't cover the handler for the stroke style select menu as it should be easy enough to follow).

Within the jQuery selector, we selected both color input elements for fill and stroke, passing in a default color of black and a handler that calls our setStyles method when a new color is selected.

var fillStyle = function() {
  var rgb = $('#js-fill-color').spectrum('get').toRgb();
  return new ol.style.Fill({
    color: [
      rgb.r, rgb.g, rgb.b,
      $('#js-fill-opacity').slider('value') / 100
    ]
  });
};

The fill color (from the color picker) was retained by Spectrum when we initialized the widget from the DOM element and whenever it's updated by the user. To dynamically retrieve the latest color, we access the same DOM element and call the get method followed by the toRgb method—both from Spectrum, storing the result in the rgb variable. The result is an object with the red value assigned to the r property, and so on for the green and blue values.

We both instantiate and return an instance of ol.style.Fill, which accepts a single object property of color. This value can be an array of OpenLayer's type ol.Color ([red, green, blue, alpha]). We retrieve and populate the array with the RGB values, followed by the alpha value.

The alpha value is taken from the jQuery UI slider DOM element (slider('value')). This number is transformed into a float. For example, 55; in this case, we divide 55 by 100 (0.55). This is important, as the ol.Color type array expects the alpha to be a float value from 0-1, inclusive.

As we saw earlier in this recipe, our setStyles method uses the fillStyle method to populate some of its properties.

var strokeStyle = function() {
  return new ol.style.Stroke({
    color: $('#js-stroke-color').spectrum('get').toHexString(),
    width: $('#js-stroke-width').slider('value'),
    lineDash: $('#js-stroke-style').val() === 'solid'
      ? undefined : [8]
  });
};

Similar to our fillStyle function, an instance of the stroke style constructor (ol.style.Stroke) is both returned and instantiated at the same time. More properties are available for stroke styling, from which we populate the color, width, and lineDash properties with values.

For the color property, we once again utilize Spectrum to retrieve the value of the latest color picker DOM element, but this time, we pass it through the toHexString library method, producing the color in string hex format. The color property for ol.style.Stroke can also accept an ol.Color array as well.

For the width property, we simply grab the value directly from the jQuery slider DOM element.

The value for the lineDash property is inferred from the user's selection. If a user has selected None (which has an option value of solid) from the select menu, then we pass in undefined, which means that no dash is required for the stroke instance. Otherwise, we pass in an array with a single number entry of 8.

When you pass in an array of numbers, you're defining a dashed pattern. The numbers represent the length of the alternating dashes and gaps. So, 8 on its own, as we've done here, is the equivalent of [8, 8] (the gap is assumed to be the same length as the dash).

You can design far more complex patterns at your own discretion. I encourage you to play around with other options. Mozilla has a useful guide on stroke dash arrays at https://developer.mozilla.org/en/docs/Web/SVG/Attribute/stroke-dasharray.

The ol.style.Stroke constructor accepts other properties, such as lineCap, and lineJoin, that you may find interesting.

There's more…

A question that can arise here is, what takes precedence when styling, a rule applied to a vector layer or styles applied directly to a single feature?

The answer is that styles go from bottom to top. This means that if we have specified a style directly on a feature, then this will be used to render it. Otherwise, any styles assigned to the vector layer will be applied to its features.

See also

  • The Styling based on feature attributes recipe
  • The Styling interaction render intents recipe