Table of Contents for
Mastering OpenLayers 3

Version ebook / Retour

Cover image for bash Cookbook, 2nd Edition Mastering OpenLayers 3 by Gábor Farkas Published by Packt Publishing, 2016
  1. Cover
  2. Table of Contents
  3. Mastering OpenLayers 3
  4. Mastering OpenLayers 3
  5. Credits
  6. About the Author
  7. About the Reviewer
  8. www.PacktPub.com
  9. Preface
  10. What you need for this book
  11. Who this book is for
  12. Conventions
  13. Reader feedback
  14. Customer support
  15. 1. Creating Simple Maps with OpenLayers 3
  16. Structure of OpenLayers 3
  17. Building the layout
  18. Using the API documentation
  19. Debugging the code
  20. Summary
  21. 2. Applying Custom Styles
  22. Customizing the default appearance
  23. Styling vector layers
  24. Customizing the appearance with JavaScript
  25. Creating a WebGIS client layout
  26. Summary
  27. 3. Working with Layers
  28. Building a layer tree
  29. Adding layers dynamically
  30. Adding vector layers with the File API
  31. Adding vector layers with a library
  32. Removing layers dynamically
  33. Changing layer attributes
  34. Changing the layer order with the Drag and Drop API
  35. Clearing the message bar
  36. Summary
  37. 4. Using Vector Data
  38. Accessing attributes
  39. Setting attributes
  40. Validating attributes
  41. Creating thematic layers
  42. Saving vector data
  43. Saving with WFS-T
  44. Modifying the geometry
  45. Summary
  46. 5. Creating Responsive Applications with Interactions and Controls
  47. Building the toolbar
  48. Mapping interactions to controls
  49. Building a set of feature selection controls
  50. Adding new vector layers
  51. Building a set of drawing tools
  52. Modifying and snapping to features
  53. Creating new interactions
  54. Building a measuring control
  55. Summary
  56. 6. Controlling the Map – View and Projection
  57. Customizing a view
  58. Constraining a view
  59. Creating a navigation history
  60. Working with extents
  61. Rotating a view
  62. Changing the map's projection
  63. Creating custom animations
  64. Summary
  65. 7. Mastering Renderers
  66. Using different renderers
  67. Creating a WebGL map
  68. Drawing lines and polygons with WebGL
  69. Blending layers
  70. Clipping layers
  71. Exporting a map
  72. Creating a raster calculator
  73. Creating a convolution matrix
  74. Clipping a layer with WebGL
  75. Summary
  76. 8. OpenLayers 3 for Mobile
  77. Responsive styling with CSS
  78. Generating geocaches
  79. Adding device-dependent controls
  80. Vectorizing the mobile version
  81. Making the mobile application interactive
  82. Summary
  83. 9. Tools of the Trade – Integrating Third-Party Applications
  84. Exporting a QGIS project
  85. Importing shapefiles
  86. Spatial analysis with Turf
  87. Spatial analysis with JSTS
  88. 3D rendering with Cesium
  89. Summary
  90. 10. Compiling Custom Builds with Closure
  91. Configuring Node JS
  92. Compiling OpenLayers 3
  93. Bundling an application with OpenLayers 3
  94. Extending OpenLayers 3
  95. Creating rich documentation with JSDoc
  96. Summary
  97. Index

Creating a raster calculator

Now that we are familiar with some of the most useful canvas manipulation methods, let's take a look at a renderer that is independent of any image manipulation. There is a very useful source object in the library that can take multiple sources as input and create a new image based on the provided operations. In this example, called ch07_rastcalc, we will use the ol.source.Raster class to build a basic RasterCalculator function.

Raster 101

To understand the limitations of raster manipulation in OpenLayers 3 or, basically, any web mapping application, we should discuss how rasters work in GIS. If you are familiar with the concept, you can skip this part. If not, this section can give you some basic, but valuable, information, which can help you evaluate better architectural patterns.

First of all, every raster can be translated to a simple matrix. Rasters have a resolution and consist of uniform cells. Therefore, if we know the resolution of a raster, we can handle the underlying data as a matrix, which we can also place in a coordinate reference system if we know the coordinates of one of its corners. Traditionally, this corner is the lower-left one. A raster can only contain one value for every cell it contains. This value can represent anything from elevation to any sort of statistical data. This type of value must be numeric but the subtype is not specified (although it must be uniform for the entire raster).

The main problem when working with rasters in browsers is that browsers can only think in the RGB color space. A browser cannot interpret raster data in its natural form; therefore, map servers convert rasters to a well-recognized RGB format (such as png, jpeg, or gif) and send images in these formats to the client. This way, we can only access the converted RGB values for every pixel of the raster, and without knowing the transformation method exactly, we cannot transform them back to their original values. We can transform them to single band values, making raster calculations possible and showing visually appealing results, but they will not represent the truth.

To sum it up, we can make raster calculations possible in the browser. However, as we do not know the original values by default, just the transformed RGB values, our transformations can only be proportionally correct. This can yield to visually appealing results, but the calculations can only be used to create previews. We can create a preview for an otherwise resource-intensive server-side calculation, thus making users not load the server when the result is clearly dissatisfying.

Operating with pixels

For this example, we will build a static calculator control. This control picks out shades of red from the first map (urban areas in the land classification layer) and keeps the second layer (elevation) only according to the pixels of first layer. In simpler terms, we will mask the elevation layer with the urban areas of the land classification layer. First, we will create the basics of our new control:

ol.control.RasterCalculator = function (opt_options) {
    var options = opt_options || {};
    var _this = this;
    var controlDiv = document.createElement('div');
    controlDiv.className = options.class || 'ol-rastercalc ol-unselectable ol-control';
    var controlButton = document.createElement('button');
    controlButton.textContent = options.label || 'R';
    controlButton.title = options.tipLabel || 'Calculate Raster';

Next, we have to write a filter function that checks an input pixel from the mask layer, and if the criteria for this pixel is met, it returns the pixel value of the second layer. If not, it sends back a fully transparent pixel:

    var filterPixel = function (pixels) {
        var inputPixel = pixels[0];
        var maskPixel = pixels[1];
        if (maskPixel[0] > maskPixel[1] && maskPixel[0] > maskPixel[2] && Math.abs(maskPixel[1] - maskPixel[2]) < 25) {
            return inputPixel;
        }
        return [0, 0, 0, 0];
    };

Tip

The value of 25 for the absolute difference in green and blue values is a sensitive default. If you set it to 50 or 100, brownish colors will also get picked.

Next, we add an event listener to the button. If we click on it, our control creates a new layer with a raster source and calculates the layer based on two input layers:

    controlButton.addEventListener('click', function (evt) {
        var layer = _this.getMap().getLayers().item(0);
        var mask = _this.getMap().getLayers().item(1);
        if (layer && mask) {
            var raster = new ol.source.Raster({
                sources: [layer.getSource(), mask.getSource()],
                operationType: 'pixel',
                operation: function (pixels, data) {
                    return filter(pixels);
                },
                lib: {
                    filter: filterPixel
                }
            });
            _this.getMap().addLayer(new ol.layer.Image({
                source: raster,
                name: 'Urban elevation'
            }));
        }
    });

For the raster source, we have to provide an array of source objects. If we set the operationType attribute to pixels, we will get an array for the operation function with the overlapping pixel values of every provided source. The lib property is optional; however, it is utterly useful. We can separate the most resource-intensive calculations in separate functions and define them in the lib object. OpenLayers 3 can thread these functions via web workers but only if they are defined.

Tip

You can refer to a function provided in the lib object with any function name in the operation function until it is mapped out correctly.

Finally, we finish our control with some routine commands and include it in our map constructor:

    controlDiv.appendChild(controlButton);
    ol.control.Control.call(this, {
        element: controlDiv,
        target: options.target
    });
};
ol.inherits(ol.control.RasterCalculator, ol.control.Control);
[…]
var map = new ol.Map({
    […]
    controls: [
        […]
        new ol.control.RasterCalculator({
            target: 'toolbar'
        })
    […]
});

If you save the code and try it in a browser, you will see our raster calculator in action. You can also try to perform more complex calculations on input images:

Operating with pixels