I faced the same problem. I used another approach:
First add a feature overlay to your selected feature:
var avlFeatureOverlay = new ol.FeatureOverlay({
style: function(feature, resolution) {
return avlGetStyle(feature, resolution, true);
}
});
Second add a click event to your map:
map.on('click', function(event) {
var resolution = map.getView().getResolution();
var result = avlSelectSWObject(event.coordinate, resolution);
}
});
Third create a function "avlSelectSWObject" to handle your event:
var avlSelectSWObject = function(coordinate, resolution){
var distance = 15 * resolution; // Your tolerance for a point feature
avlFeatureOverlay.removeFeature(avlFormerFeature);
// avlVectorSource is my vector source rename to your own
var closestFeature = avlVectorSource.getPointFeatureInDistance(coordinate, distance);
if(closestFeature == null) {
distance *= 5; // bigger tolerance for line or polygons. Use your own unit
closestFeature = avlVectorSource.getFeatureInDistance(coordinate, distance);
}
if(closestFeature == null){
return false;
}
avlFeatureOverlay.addFeature(closestFeature); // Add feature to overlay
avlDisplayProperties(closestFeature);
return true;
};
Fourth create two new function on ol.source.vector to calculate distance for a feature
with a point geometry or a feature with any geometry type.
Why testing for points first? Because if your line and your point shares a equal position,
you will always get the line.
The function to catch a feature with a point geometry:
ol.source.Vector.prototype.getPointFeatureInDistance = function(coordinate, distance) {
// Find the closet feature with Point as geometry type with in the given distance
// created from ol.source.Vector.prototype.getClosestFeatureToCoordinate
var x = coordinate[0];
var y = coordinate[1];
var closestFeature = null;
var previousCityBlockDistance = Infinity;
var extent = [x-distance, y-distance, x+distance, y+distance];
this.forEachFeatureInExtent(extent,function(feature) {
var geometry = feature.getGeometry();
var ext = geometry.getExtent();
if(ext[0] == ext[2] && ext[1] == ext[3])
{
var minCityBlockDistance = Math.abs(x - ext[0]) + Math.abs(y - ext[1]);
if (minCityBlockDistance < previousCityBlockDistance) {
previousCityBlockDistance = minCityBlockDistance;
closestFeature = feature;
}
}
});
return closestFeature;
};
The function to catch a feature with any geometry in a distance (tolerance):
ol.source.Vector.prototype.getFeatureInDistance =
function(coordinate, distance) {
// Find the closet feature with in the given distance
// created from ol.source.Vector.prototype.getClosestFeatureToCoordinate
var x = coordinate[0];
var y = coordinate[1];
var closestFeature = null;
var previousCityBlockDistance = Infinity;
var extent = [x-distance, y-distance, x+distance, y+distance];
this.forEachFeatureInExtent(extent,function(feature) {
var geo = feature.getGeometry();
var coord = geo.getClosestPoint(coordinate);
var minCityBlockDistance = Math.abs(x - coord[0]) + Math.abs(y - coord[1]);
if (minCityBlockDistance <= distance &&
minCityBlockDistance < previousCityBlockDistance) {
previousCityBlockDistance = minCityBlockDistance;
closestFeature = feature;
}
});
return closestFeature;
};
In relation to the comment below. You can return multiple values as a vector:
return [closestFeature,previousCityBlockDistance];
and get them in the calling function:
var result = avlVectorSource.getPointFeatureInDistance(coordinate, distance);
var closestFeature = result[0];
var mindistance = result[1];
See also: https://stackoverflow.com/questions/2917175/return-multiple-values-in-javascript
ol.interaction.Select
orol.Map#forEachFeatureAtPixel
, right? Unfortunately there currently is no way to configure a selection tolerance. I hope this is something we will add in the near future.