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

Mapping interactions to controls

In this example, called ch05_select, we fill the gap between interactions and controls, and create a simple feature selecting the control. As we need to inform the user about the control's status, we create some CSS rules for active controls. Activated controls will have a nice orange color, which won't change, if we hover over them. We also extend the ol-unselectable class to our controls:

.layertree,.toolbar .ol-unselectable {
[…]
.toolbar .ol-control button.active {
    background-color: rgba(234,129,8,1);
}
.toolbar .ol-control button.active:hover {
    background-color: rgba(234,129,8,1);
}

Creating the control

Next, we can go on and build a custom control that has only one job: managing the underlying interaction. Firstly, we set up the control's properties and GUI elements based on the supplied options:

ol.control.Interaction = function (opt_options) {
    var options = opt_options || {};
    var controlDiv = document.createElement('div');
    controlDiv.className = options.className || 'ol-unselectable ol-control';
    var controlButton = document.createElement('button');
    controlButton.textContent = options.label || 'I';
    controlButton.title = options.tipLabel || 'Custom interaction';
    controlDiv.appendChild(controlButton);
    var _this = this;
    controlButton.addEventListener('click', function () {
        if (_this.get('interaction').getActive()) {
            _this.set('active', false);
        } else {
            _this.set('active', true);
        }
    });
    var interaction = options.interaction;

We create a standard OpenLayers 3 control button: a button element inside a div element. We set up its style, title, and content; then, we add a listener to it. If we click on it in an active status, we deactivate it and vice versa.

Note

Interactions in OpenLayers 3 can be activated and deactivated by default. This is not true for controls; therefore, we have to implement it via giving the control an active property and registering listeners to it.

Next, we call the original control constructor with our custom control setting it up. This is one of the two key steps in extending a class in OpenLayers 3. Only after this step, we can use the control's factory methods.

After we set up the control, we can set its properties. This is where we give it a toggle type. We also store the associated interaction in the control and a function that will remove the interaction from the map, if the control is removed:

    ol.control.Control.call(this, {
        element: controlDiv,
        target: options.target
    });
    this.setProperties({
        interaction: interaction,
        active: false,
        type: 'toggle',
        destroyFunction: function (evt) {
            if (evt.element === _this) {
                this.removeInteraction(_this.get('interaction'));
            }
        }
    });

Next, we close our control with a listener on its active property. If the control is activated, we activate the interaction and add the active class to it's class list. Finally, we copy the prototype chain of ol.control.Control to our control with ol.inherits method. This is the second key step in extending an OpenLayers 3 class:

    this.on('change:active', function () {
        this.get('interaction').setActive(this.get('active'));
        if (this.get('active')) {
            controlButton.classList.add('active');
        } else {
            controlButton.classList.remove('active');
        }
    }, this);
};
ol.inherits(ol.control.Interaction, ol.control.Control);

Note

The ol.inherits method is a simple reference to the Closure Library's goog.inherits. It takes two constructor functions; let's call them A and B. It simply copies the constructor B's prototype to the constructor A's prototype.constructor property. This not only exposes the constructor B's and all its parents' methods to the constructor A, but also makes an A instance of B and all its parents. One constructor can only have one inheritance with this method, it cannot be used as a mixin.

Adding and removing the control

As our control has an underlying interaction, we have to make sure that it is correctly added to the map on addition and removed on removal. For this purpose, we already created a function that will act as an event listener on the map's control collection. However, as we add an event listener to an object, which doesn't get destroyed, we have to manually take care of unlistening on the removal of the control, thus, cleaning up after ourselves:

ol.control.Interaction.prototype.setMap = function (map) {
    ol.control.Control.prototype.setMap.call(this, map);
    var interaction = this.get('interaction');
    if (map === null) {
        ol.Observable.unByKey(this.get('eventId'));
    } else if (map.getInteractions().getArray().indexOf(interaction) === -1) {
        map.addInteraction(interaction);
        interaction.setActive(false);
        this.set('eventId', map.getControls().on('remove', this.get('destroyFunction'), map));
    }
};

Control objects have a setMap public method that can be overridden. This method gets the map object, the control is added to, and takes care of every map-related initialization. By calling the original method first, we can extend this functionality to our own needs.

If the control is added to a map or removed from it, this method gets invoked with the map object or a null value, respectively. This way, we can easily add the underlying interaction to the map, if it hasn't been added yet. However, we will have a hard time on the removal, as we don't have a reference to the map object then.

To overcome this problem, we register a listener to our map's control collection. If the listener detects that our control has been removed, it removes the associated interaction. If we save the key returned by the listener in a variable or a property (eventId), we can call the ol.Observable.unByKey static function with the key to remove the listener. This way, we do not need to have a reference to our map object.

Adding a selection control

Now that we have a fully operational custom control for mapping interactions to control buttons, we can add a simple selection control to our map. We leave everything on their default values and pass only an ol.interaction.Select method to the constructor, which can select any feature from any vector layer when it is clicked on:

tools.addControl(new ol.control.Interaction({
    interaction: new ol.interaction.Select()
}));

If you save the code and open it in your favorite browser, you will see our new control in action:

Adding a selection control