Edit

Vector Tile Selection

vectortiles selection

Select features from vector tiles.

Click a rendered vector-tile feature to highlight it on the map. Click on an empty spot (ocean) to reset the selection. By changing the action type to "Multi Select" you can select multiple features at a time. With "Single Select on hover", features will be higlighted when the pointer is above them.

The selection layer is configured with `renderMode: 'vector'` for better performance on frequent redraws, i.e. when 'Single select on hover' is selected.

index.html<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Vector Tile Selection</title>
    <!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
    <script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=fetch,requestAnimationFrame,Element.prototype.classList,URL"></script>
    <style>
      .map {
        width: 100%;
        height:400px;
      }
    </style>
  </head>
  <body>
    <div id="map" class="map"></div>
    <form class="form-inline">
      <label>Action type &nbsp;</label>
      <select id="type" class="form-control">
        <option value="singleselect" selected>Single Select</option>
        <option value="multiselect">Multi Select</option>
        <option value="singleselect-hover">Single Select on hover</option>
      </select>
    </form>
    <script src="index.js"></script>
  </body>
</html>
index.jsimport 'ol/ol.css';
import Map from 'ol/Map';
import View from 'ol/View';
import MVT from 'ol/format/MVT';
import VectorTileLayer from 'ol/layer/VectorTile';
import VectorTileSource from 'ol/source/VectorTile';
import {Fill, Stroke, Style} from 'ol/style';

// lookup for selection objects
var selection = {};

var country = new Style({
  stroke: new Stroke({
    color: 'gray',
    width: 1
  }),
  fill: new Fill({
    color: 'rgba(20,20,20,0.9)'
  })
});
var selectedCountry = new Style({
  stroke: new Stroke({
    color: 'rgba(200,20,20,0.8)',
    width: 2
  }),
  fill: new Fill({
    color: 'rgba(200,20,20,0.4)'
  })
});

var vtLayer = new VectorTileLayer({
  declutter: true,
  source: new VectorTileSource({
    maxZoom: 15,
    format: new MVT({
      idProperty: 'iso_a3'
    }),
    url: 'https://ahocevar.com/geoserver/gwc/service/tms/1.0.0/' +
      'ne:ne_10m_admin_0_countries@EPSG%3A900913@pbf/{z}/{x}/{-y}.pbf'
  }),
  style: country
});

var map = new Map({
  layers: [
    vtLayer
  ],
  target: 'map',
  view: new View({
    center: [0, 0],
    zoom: 2,
    multiWorld: true
  })
});

// Selection
var selectionLayer = new VectorTileLayer({
  map: map,
  renderMode: 'vector',
  source: vtLayer.getSource(),
  style: function(feature) {
    if (feature.getId() in selection) {
      return selectedCountry;
    }
  }
});

var selectElement = document.getElementById('type');

map.on(['click', 'pointermove'], function(event) {
  if (selectElement.value === 'singleselect-hover' && event.type !== 'pointermove' ||
      selectElement.value !== 'singleselect-hover' && event.type === 'pointermove') {
    return;
  }
  vtLayer.getFeatures(event.pixel).then(function(features) {
    if (!features.length) {
      selection = {};
      selectionLayer.changed();
      return;
    }
    var feature = features[0];
    if (!feature) {
      return;
    }
    var fid = feature.getId();

    if (selectElement.value.startsWith('singleselect')) {
      selection = {};
    }
    // add selected feature to lookup
    selection[fid] = feature;

    selectionLayer.changed();
  });
});
package.json{
  "name": "vector-tile-selection",
  "dependencies": {
    "ol": "6.3.1"
  },
  "devDependencies": {
    "parcel": "1.11.0"
  },
  "scripts": {
    "start": "parcel index.html",
    "build": "parcel build --experimental-scope-hoisting --public-url . index.html"
  }
}