I added a function to display a popup on hover to the feature layer but it doesn't work very well.

Here my code:

map.on('pointermove', function(evt) {
  if (evt.dragging) {

  var info = $('#info');
  var pixel = map.getEventPixel(evt.originalEvent);
  var feature = map.forEachLayerAtPixel(pixel, function(feature) { return true; }, null, function(layer) { return layer === pmfeatlayer; });
  var viewResolution = map.getView().getResolution();
  var coordinate = evt.coordinate;
  url = pmfeatlayer.getSource().getGetFeatureInfoUrl(coordinate, viewResolution, projection, {'INFO_FORMAT': 'text/html'});

  if (feature && url) {

      left: pixel[0] + 'px',
      top: pixel[1] + 'px'
//    setTimeout(function() {
    var xhttp = new XMLHttpRequest();
    xhttp.open("GET", url, true);
    xhttp.onreadystatechange = function (aEvt) {
      if (xhttp.readyState == 4 && xhttp.status == 200) {

          var parser = new window.DOMParser();
          var res = parser.parseFromString(xhttp.responseText, "text/xml");
          var myitems = res.getElementsByTagName('item');

          if(res.getElementsByTagName('item').length != 0){
            info.html("<div class='hoverPopup'>" + hover(xhttp.responseText) + "</div>").delay( 1000 ).fadeIn( 400 );
          } else {

       } // end if 4 && 200
     }; // end onreadystatechange
 //}, 1000);
   } // end if (feature && url)
 }); // end pointermove

As you can see I'm using map.on('pointermove'... But it's not the exact event, What can I use to detect that the cursor is above the feature layer and it's not moving, for example, .5 seconds?

I tried to add a delay function but still, it doesn't work properly, it made a lot of requests and the popup display buggy due to the delay and the cursor can be on other parts of the map at the time is displayed.


You can try a debounce or throttle function to delay the calls for the popup.

A very simple way could look like this:

var stillMoving = [];
function delayPopup() {
    stillMoving.push(true);          // add my call to array

    setTimeout(function() {
        stillMoving.shift();         // remove my call from array

        // check if more calls are pending
        // if yes stop propagation
        if ( stillMoving[ 0 ] ) {
        else {
            // load the popup here
    }, 500);
  • I'm still having the same issue, even with a timeout (your version and my version) it load a lot of http request when you stop moving the mouse, and it seems it remember all the coordinates from the last time the mouse enter till it stops, it creates a couple of popups. – Sebastiano Jan 31 '18 at 13:35
  • And as you can see from the example, pretty different from mine but same concept, they don't use delay. openlayers.org/en/latest/examples/kml-earthquakes.html – Sebastiano Jan 31 '18 at 13:40
  • In the example you are referreing to they use a vector which means they do not have to send all those requests, because the data is already in the client (loaded with the vector source KML). With the code I added all requests while moving should be filtered except the last one, which will then fire and show the popup. – bennos Jan 31 '18 at 13:53
  • I wrapped from var info to //end if (feature && url) and inserted in your else where you call loadPopup(), but it doesn't work properly, I have more popup that just the last one. And I change the call of your function with anonimus and IIFE – Sebastiano Jan 31 '18 at 13:58
  • Can you create a simple fiddle with the problem? – bennos Jan 31 '18 at 14:01

I am doing something similar and found a way to delay based on mouse position:

    $.pixelDistance = 0.01;
    $.pastPixel = undefined;
    map.on('pointermove', function(evt) {
        if (evt.dragging) {
        var pixel = map.getEventPixel(evt.originalEvent);
        $.pastPixel = pixel;
            console.log((pixel=== $.pastPixel));
                var feature1 = map.forEachLayerAtPixel( $.pastPixel, function(feature1) { return true; }, null, function(layer) { return layer === vector; });
                console.log(feature1); // end if (feature && url)
                console.log( $.pastPixel); // end if (feature && url)
        }, 1000);

    }); // end pointermove

There is a simpler method by canceling the delayed execution whenever the mouse is moved again.

var LastTimeoutRequest;
var LastLonLat;

function DisplayInfo(){    
    console.log('executed now');
    document.getElementById("pointerposition").innerHTML = '<b>' + LastLonLat + '</b>'; 

map.on('pointermove', function(evt) {
    if (evt.dragging) return;

    if (typeof LastTimeoutRequest !== 'undefined') { // cancel timeout when the mouse moves

    LastLonLat = ol.proj.transform(evt.coordinate, 'EPSG:3857', 'EPSG:4326');
    document.getElementById("pointerposition").innerHTML = LastLonLat ;

    LastTimeoutRequest = setTimeout(DisplayInfoAtPosition, 2000);        

This example will display the mouse postition and turn it in bold it it does not move for 2000 ms.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.