Example using the hitTolerance parameter.
By default, the map.forEachFeatureAtPixel() function only considers features that are directly under the provided pixel. This can make it difficult to interact with features on touch devices. To consider features within some distance of the provided pixel, use the hitTolerance option. For example, map.forEachFeatureAtPixel(pixel, callback, {hitTolerance: 3}) will call the callback with all features that are within three pixels of the provided pixel.
import 'ol/ol.css';
import Feature from 'ol/Feature';
import LineString from 'ol/geom/LineString';
import Map from 'ol/Map';
import View from 'ol/View';
import {OSM, Vector as VectorSource} from 'ol/source';
import {Stroke, Style} from 'ol/style';
import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer';
const raster = new TileLayer({
source: new OSM(),
});
const style = new Style({
stroke: new Stroke({
color: 'black',
width: 1,
}),
});
const feature = new Feature(
new LineString([
[-4000000, 0],
[4000000, 0],
])
);
const vector = new VectorLayer({
source: new VectorSource({
features: [feature],
}),
style: style,
});
const map = new Map({
layers: [raster, vector],
target: 'map',
view: new View({
center: [0, 0],
zoom: 2,
}),
});
let hitTolerance;
const statusElement = document.getElementById('status');
map.on('singleclick', function (e) {
let hit = false;
map.forEachFeatureAtPixel(
e.pixel,
function () {
hit = true;
},
{
hitTolerance: hitTolerance,
}
);
if (hit) {
style.getStroke().setColor('green');
statusElement.innerHTML = 'A feature got hit!';
} else {
style.getStroke().setColor('black');
statusElement.innerHTML = 'No feature got hit.';
}
feature.changed();
});
const selectHitToleranceElement = document.getElementById('hitTolerance');
const circleCanvas = document.getElementById('circle');
const changeHitTolerance = function () {
hitTolerance = parseInt(selectHitToleranceElement.value, 10);
const size = 2 * hitTolerance + 2;
circleCanvas.width = size;
circleCanvas.height = size;
const ctx = circleCanvas.getContext('2d');
ctx.clearRect(0, 0, size, size);
ctx.beginPath();
ctx.arc(
hitTolerance + 1,
hitTolerance + 1,
hitTolerance + 0.5,
0,
2 * Math.PI
);
ctx.fill();
ctx.stroke();
};
selectHitToleranceElement.onchange = changeHitTolerance;
changeHitTolerance();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hit Tolerance</title>
<!-- Pointer events polyfill for old browsers, see https://caniuse.com/#feat=pointer -->
<script src="https://unpkg.com/elm-pep"></script>
<!-- The line below is 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,URL,TextDecoder,Number.isInteger"></script>
<style>
.map {
width: 100%;
height:400px;
}
</style>
</head>
<body>
<div id="map" class="map"></div>
<span id="status">Try to click the line in the map.</span>
<form class="form-inline">
<label for="hitTolerance">Hit tolerance for selecting features: </label>
<select id="hitTolerance" class="form-control">
<option value="0" selected>0 Pixels</option>
<option value="5">5 Pixels</option>
<option value="10">10 Pixels</option>
</select>
Area:
<canvas id="circle" style="vertical-align: middle" />
</form>
<script src="main.js"></script>
</body>
</html>
{
"name": "hit-tolerance",
"dependencies": {
"ol": "6.6.1"
},
"devDependencies": {
"parcel": "^2.0.0-beta.1"
},
"scripts": {
"start": "parcel index.html",
"build": "parcel build --public-url . index.html"
}
}