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.
import 'ol/ol.css';
import MVT from 'ol/format/MVT';
import Map from 'ol/Map';
import VectorTileLayer from 'ol/layer/VectorTile';
import VectorTileSource from 'ol/source/VectorTile';
import View from 'ol/View';
import {Fill, Stroke, Style} from 'ol/style';
// lookup for selection objects
let selection = {};
const country = new Style({
stroke: new Stroke({
color: 'gray',
width: 1,
}),
fill: new Fill({
color: 'rgba(20,20,20,0.9)',
}),
});
const 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)',
}),
});
const 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,
});
const map = new Map({
layers: [vtLayer],
target: 'map',
view: new View({
center: [0, 0],
zoom: 2,
multiWorld: true,
}),
});
// Selection
const selectionLayer = new VectorTileLayer({
map: map,
renderMode: 'vector',
source: vtLayer.getSource(),
style: function (feature) {
if (feature.getId() in selection) {
return selectedCountry;
}
},
});
const 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;
}
const feature = features[0];
if (!feature) {
return;
}
const fid = feature.getId();
if (selectElement.value.indexOf('singleselect') === 0) {
selection = {};
}
// add selected feature to lookup
selection[fid] = feature;
selectionLayer.changed();
});
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vector Tile Selection</title>
<!-- Pointer events polyfill for old browsers, see https://caniuse.com/#feat=pointer -->
<script src="https://unpkg.com/elm-pep@1.0.6/dist/elm-pep.js"></script>
<!-- The lines below are only needed for old environments like Internet Explorer and Android 4.x -->
<script src="https://cdn.polyfill.io/v3/polyfill.min.js?features=fetch,requestAnimationFrame,Element.prototype.classList,TextDecoder"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/core-js/3.18.3/minified.js"></script>
<style>
.map {
width: 100%;
height:400px;
}
</style>
</head>
<body>
<div id="map" class="map"></div>
<form class="form-inline">
<label for="type">Action type </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="main.js"></script>
</body>
</html>
{
"name": "vector-tile-selection",
"dependencies": {
"ol": "6.13.1-dev"
},
"devDependencies": {
"parcel": "^2.0.0"
},
"scripts": {
"start": "parcel index.html",
"build": "parcel build --public-url . index.html"
}
}