Search code examples
javascriptopenlayersopenlayers-3

Adding event handler to feature in OpenLayers 3?


I am using the following code to add a feature to a vector layer in OpenLayers 3 (OL3):

marker = new ol.Feature({
    geometry: new ol.geom.Point([longitude, latitude]),
    name: "Location Marker"
});
markerStyle = new ol.style.Style({
  image: new ol.style.Icon({
    anchor: [0.5, 1.0],
    anchorXUnits: "fraction",
    anchorYUnits: "fraction",
    src: "Content/Images/OpenLayers/marker_trans.png"
  }),
  zIndex: 100000
});
marker.setStyle(markerStyle);
marker.on("click", function(e) {
  // do something
}, marker);
map.getSource().addFeature(marker);

The marker displays as expected, but the click event never fires. What am I doing wrong?

I should note that there is already a handler associated with "click" at the map level, i.e.

map.on("click", function(e) {
  // do something
}, marker);

Solution

  • First: Features don't fire clicks! For information on the events features do fire, check http://openlayers.org/en/master/apidoc/ol.Feature.html.

    For checking if a feature did get clicked, there is the .forEachFeatureAtPixel(pixel, callback) function of ol.Map. ( http://openlayers.org/en/master/apidoc/ol.Map.html#forEachFeatureAtPixel ) The callback is executed on every feature at the pixel. The callback gets passed 2 arguments: the feature and the layer the feature is in.

    Good to know is the .getEventPixel(event) function, if you don't work with openlayers event handlers but with handlers on the viewport. If your using openlayers eventhandler, the event has a property .pixel. (http://openlayers.org/en/master/apidoc/ol.Map.html#getEventPixel) The methods .getEventCoordinate(event) and .getCoordinateFromPixels(pixels) might be useful, too.

    So you would add it like this to your map.on("click", ... :

    map.on("click", function(e) {
        map.forEachFeatureAtPixel(e.pixel, function (feature, layer) {
            //do something
        })
    });
    

    Same thing with jQuery:

    $(map.getViewport()).on("click", function(e) {
        map.forEachFeatureAtPixel(map.getEventPixel(e), function (feature, layer) {
            //do something
        });
    });
    

    Same thing with pure JS:

    map.getViewport().addEventListener("click", function(e) {
        map.forEachFeatureAtPixel(map.getEventPixel(e), function (feature, layer) {
            //do something
        });
    });
    

    You might also want to check this example, there are two uses of this function, first with openlayers events, the second with jQuery events: http://openlayers.org/en/master/examples/icon.js

    Note

    There is also the possibility to do this with an ol.interaction.Select (http://openlayers.org/en/master/apidoc/ol.interaction.Select.html?unstable=true), but this is a little bit overpowered for this case. And it has some unintuitive caveats caused by openlayers internally moving the selected features to another so called unmanaged layer.

    Anyhow this works by adding a listener to the collection belonging to the interaction. The collection can be retrieved with .getFeatures().

    interaction.getFeatures().on("add", function (e) { 
        // do something. e.element is the feature which was added
    });