Adding event handler to feature in OpenLayers 3?
Asked Answered
N

3

16

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);
Naylor answered 15/10, 2014 at 20:8 Comment(0)
N
52

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
});
Nicknickel answered 16/10, 2014 at 15:19 Comment(9)
According to openlayers.org/en/v3.0.0/apidoc/ol.Feature.html#on such a handler can be added. Any ideas what events are support for this? Is it just the "change" and "change:geometry" events? Your comment about features not being part of the DOM helps me understand why "click" doesn't fire on a feature. With OL2 I could add "hover" event to features/markers. Is the new approach the same as you describe for the "click" event, i.e., use map.on("onmouseover", function(e){map.forEachFeatureAtPixel(...)}}Naylor
Sure you can add such a handler, but it never it gets fired ... as you can read in the documentation, just below the description of the constructor. And nope there aren't any not documented ones - i checked the code for you, too :P (the documentation is quite complete btw - if you untick the stable only checkbox). I don't think ol.Map fires an event called "onmouseover", but you could do that with jquery or basic js. $(map.getViewport()).on("mousemove", function(e){map.forEachFeatureAtPixel(map.getEventPixel(e), ...)} please check the example.Nicknickel
I have marked this as the answer as it addresses my question regarding the particular click interaction I wanted. However, for other feature interactions, like 'hover', I think that openlayers.org/en/v3.0.0/examples/select-features.html provides a better approach using ol.interactionNaylor
If map has interactions, more cleaner way would be to use ol.interaction instance's getFeatures() method instead of forEachFeatureAtPixel()Pangermanism
I am getting a different event type when using map.on and jquery's $(map.getViewport()).on("click", is it possible to get the coordinates with this jquery eventStamen
with map.getEventPixel(event) you get the pixels and with map.getCoordinateFromPixel(pixel) you can get the coordinateNicknickel
Or just use .getEventCoordinate(event).Nicknickel
Is it possible to make forEachFeatureAtPixel stop after the first feature?Overestimate
openlayers.org/en/master/apidoc/… says: To stop detection, callback functions can return a truthy value.Nicknickel
H
3

If you just want a click on a map, this will work for you.

  var map = new ol.Map({
    target: 'map',
    layers: [
      new ol.layer.Tile({
        source: new ol.source.MapQuest({layer: 'sat'})
      })
    ],
    view: new ol.View({
      center: ol.proj.transform([37.41, 8.82], 'EPSG:4326', 'EPSG:3857'),
      zoom: 4
    })
  });

map.on("click", function(evt) {
    var coord = ol.proj.transform(evt.coordinate, 'EPSG:3857', 'EPSG:4326');
    var lon = coord[0];
    var lat = coord[1];
    alert(lon);
    alert(lat);
});
Haldes answered 16/5, 2015 at 8:56 Comment(0)
Z
2

If you just need to add a marker on your map which is clickable, you can use overlays. In your HTML header define your marker's style:

<style>
    #marker {
        width: 20px;
        height: 20px;
        border: 1px solid #088;
        border-radius: 10px;
        background-color: #0FF;
        opacity: 0.5;
    }
</style>

then in script part of your file, after the map is created:

    // add marker
    var pos = ol.proj.fromLonLat([0.01123, 0.00612]);
    var marker = new ol.Overlay({
        position: pos,
        positioning: 'center-center',
        element: $('<div id="marker" title="Marker"></div>')
            .popover({
                'placement': 'top',
                'html': true,
                'content': '<strong>anything...</strong>'
            })
            .on('click', function (e) { $(".location-popover").not(this).popover('hide'); }),
        stopEvent: false
    });
    map.addOverlay(marker);
Zomba answered 26/8, 2015 at 19:42 Comment(1)
The question is specific to ol.FeatureMenology

© 2022 - 2024 — McMap. All rights reserved.