24

I managed to add interactivity to a feature layer added from a remote GeoJSON resource. When I click on a feature I get its ID, fire an AJAX request and display some relevant info about the feature, on the page outside of the map area.

I used a Select interaction.

I would like to make it even clearer to the user that he can click on the features on the map. Is there any way I can change the mouse cursor to "cursor" of "hand" when the mouse hovers a feature contained in a ol.layer.Vector ?

I couldn't find anything in the doc, on this site or by googling.

Joel
  • 7,401
  • 4
  • 52
  • 58
Pierre Henry
  • 16,658
  • 22
  • 85
  • 105
  • 5
    There is an example: http://openlayers.org/en/v3.0.0/examples/icon.html. To be honest I'm trying to use the same method in my map but without success: **Uncaught TypeError: Cannot set property 'cursor' of undefined** – Azathoth Sep 25 '14 at 11:26
  • @Azathoth `getTarget` gives you what to give to the map target: either string or HTMLElement. Should be HTMLElement, like in the example, if you want to change its style. – tonio Sep 26 '14 at 12:38
  • @tonio I think I copied all the code usend in the example but **console.log(map.getTarget());** prints a string containing "map" – Azathoth Sep 26 '14 at 16:47
  • @Azathoth : see my answer on how to deal with the string value you get – Pierre Henry Sep 29 '14 at 14:57
  • `map.getTargetElement().style.cursor = 'pointer';` worked for me – Pratik Goenka Apr 22 '15 at 04:47

12 Answers12

32

It can be done as well without jQuery:

map.on("pointermove", function (evt) {
    var hit = this.forEachFeatureAtPixel(evt.pixel, function(feature, layer) {
        return true;
    }); 
    if (hit) {
        this.getTargetElement().style.cursor = 'pointer';
    } else {
        this.getTargetElement().style.cursor = '';
    }
});
Pablo
  • 1,604
  • 16
  • 31
  • 7
    In 3.17.1 this code works. But not with this.getTarget(), use this.getTargetElement() – David Jul 08 '16 at 07:22
18

Here is another way to do it:

map.on('pointermove', function(e){
  var pixel = map.getEventPixel(e.originalEvent);
  var hit = map.hasFeatureAtPixel(pixel);
  map.getViewport().style.cursor = hit ? 'pointer' : '';
});
VXp
  • 11,598
  • 6
  • 31
  • 46
Robert M
  • 185
  • 1
  • 5
13

If that doesn't work, try a combination of the 2, seemed to work for my vector popup...

var target = map.getTarget();
var jTarget = typeof target === "string" ? $("#" + target) : $(target);
// change mouse cursor when over marker
$(map.getViewport()).on('mousemove', function (e) {
    var pixel = map.getEventPixel(e.originalEvent);
    var hit = map.forEachFeatureAtPixel(pixel, function (feature, layer) {
        return true;
    });
    if (hit) {
        jTarget.css("cursor", "pointer");
    } else {
        jTarget.css("cursor", "");
    }
});
Icarus
  • 1,627
  • 7
  • 18
  • 32
ohjeeez
  • 559
  • 4
  • 6
10

Thanks to the example link provided by Azathoth in the comments I worked a solution out:

  • using OL3 pointermove event
  • using jQuery to get the target element and change its cursor style

Here is the code :

var cursorHoverStyle = "pointer";
var target = map.getTarget();

//target returned might be the DOM element or the ID of this element dependeing on how the map was initialized
//either way get a jQuery object for it
var jTarget = typeof target === "string" ? $("#"+target) : $(target);

map.on("pointermove", function (event) {
    var mouseCoordInMapPixels = [event.originalEvent.offsetX, event.originalEvent.offsetY];

    //detect feature at mouse coords
    var hit = map.forEachFeatureAtPixel(mouseCoordInMapPixels, function (feature, layer) {
        return true;
    });

    if (hit) {
        jTarget.css("cursor", cursorHoverStyle);
    } else {
        jTarget.css("cursor", "");
    }
});

Here is the link to the example on OpenLayers site : http://openlayers.org/en/v3.0.0/examples/icon.html

Pierre Henry
  • 16,658
  • 22
  • 85
  • 105
4

For me it worked like this:

map.on('pointermove', function(e) {
          if (e.dragging) return;
          var pixel = e.map.getEventPixel(e.originalEvent);
          var hit = e.map.forEachFeatureAtPixel(pixel, function (feature, layer) {
              return true;
          });
          e.map.getTargetElement().style.cursor = hit ? 'pointer' : '';
        });

I also added a layer filter:

map.on('pointermove', function(e) {
      if (e.dragging) return;
      var pixel = e.map.getEventPixel(e.originalEvent);
      var hit = e.map.forEachFeatureAtPixel(pixel, function (feature, layer) {
          return layer.get('name') === 'myLayer';
      });
      e.map.getTargetElement().style.cursor = hit ? 'pointer' : '';
    });

I had to select a new solution as the old one I had use for the layer filter before did not work anymore:

var hit = e.map.hasFeatureAtPixel(e.pixel, function(layer){
             return layer.get('name') === 'myLayer';
          });
winnewoerp
  • 161
  • 6
  • Interesting idea, but don't forget to mention that a layer has no native 'name' attribution, and this has to be set (here, on layer creation). `var myLayer = new ol.layer.Vector({ source: mySource, style: myStyle, name: "myLayerName" });` – Josef M. Schomburg Jul 08 '17 at 08:18
3

Another way (combined from parts of above answers, but even simpler):

map.on("pointermove", function (evt) {
    var hit = map.hasFeatureAtPixel(evt.pixel);
    map.getTargetElement().style.cursor = (hit ? 'pointer' : '');
});
JustAC0der
  • 2,871
  • 3
  • 32
  • 35
2

I did it with the following code:

var target = $(map.getTargetElement()); //getTargetElement is experimental as of 01.10.2015
map.on('pointermove', function (evt) {
    if (map.hasFeatureAtPixel(evt.pixel)) { //hasFeatureAtPixel is experimental as of 01.10.2015
        target.css('cursor', 'pointer');
    } else {
        target.css('cursor', '');
    }
});
NoRyb
  • 1,472
  • 1
  • 14
  • 35
2

Uncaught TypeError: Cannot set property 'cursor' of undefined.

Fixed with: map.getTargetElement()s.style.cursor = hit ? 'pointer' : ''; instead of map.getTarget().style.cursor = hit ? 'pointer' : '';

Chait
  • 1,052
  • 2
  • 18
  • 30
cinthyasm
  • 21
  • 3
1

Simple way to get target element

var target = map.getTarget();

target = typeof target === "string" ?
    document.getElementById(target) : target;

target.style.cursor = features.length > 0) ? 'pointer' : '';
Nurlan
  • 720
  • 7
  • 12
  • Reason for downvote: use map.getTargetElement() (https://openlayers.org/en/latest/apidoc/ol.Map.html#getTargetElement). – Corey Alix May 08 '17 at 17:33
1

If you guys are using Angular 2 you must use the following code:

this.map.on("pointermove", function (evt) {
    var hit = evt.map.hasFeatureAtPixel(evt.pixel);
    this.getTargetElement().style.cursor = hit ? 'pointer' : '';
});

If the map variable is a member class you refer to it as "this.map", instead if it is declared inside the current function it can be refered to as "map". But above all, you don't write

map.getTargetElement()

but you write

this.getTargetElement()
nix86
  • 2,837
  • 11
  • 36
  • 69
0

I tried to minimize pointermove event closure, by avoiding to update style when not necessary, because it calls so very often:

Example-1: uses jQuery:

var cursorStyle = "";
map.on("pointermove", function (e) {
    let newStyle = this.hasFeatureAtPixel(e.pixel) ? "pointer" : "";
    newStyle !== cursorStyle && $(this.getTargetElement()).css("cursor", cursorStyle = newStyle);
});

Example-2: no jQuery:

var cursorStyle = "";
map.on("pointermove", function (e) {
    let newStyle = this.hasFeatureAtPixel(e.pixel) ? "pointer" : "";
    if (newStyle !== cursorStyle) {
        this.getTargetElement().style.cursor = cursorStyle = newStyle;
    }
});
AamirR
  • 11,672
  • 4
  • 59
  • 73
0

Easy way

map.on('pointermove', (e) => {
      const pixel = map.getEventPixel(e.originalEvent);
      const hit = map.hasFeatureAtPixel(pixel);
      document.getElementById('map').style.cursor = hit ? 'pointer' : '';
    });
}