How to make Leaflet popups follow the position of the cursor?

1.7k views Asked by At

My popups are set to open on mouseover, and the icons on my map are very large. Right now, when the cursor travels over the icon, the popup remains static in the middle of the icon. Is it possible to have the popup travel with the cursor's movements while the cursor is inside the relevant icon?

I'm trying to achieve an effect like this example from the NYT, but with Leaflet and the markerCluster plugin.

Relevant code:

var markers = L.markerClusterGroup( {
....

    iconCreateFunction: function (cluster) {

        cluster.bindPopup(stateBlurb, {offset: new L.Point(0, -15)});
       
        cluster.on('mouseover', function (e) {
            this.openPopup();
        });

        cluster.on('click', function (e) {
            this.openPopup();
        });

        cluster.on('clickout', function (e) {
            this.closePopup();
        });

        return L.divIcon({ 
          html: '<div><span>' + stateName + '</span></div>', 
          className: `cluster ${classNameSize} ${classNameColor}`,  
          iconSize: null,
        });

    },

});

1

There are 1 answers

1
IvanSanchez On

There are a few approaches to this; one of them would be to rely on the openPopup(latlng) method together with the latlng property of Leaflet-decorated mouse events and the mousemove event, e.g.:

var circle = L.circleMarker([0,0], {radius: 200}).addTo(map);
circle.bindPopup('Hello circle');

circle.on('mouseover', function(ev){ circle.openPopup(ev.latlng); });
circle.on('mousemove', function(ev){ circle.openPopup(ev.latlng); });
circle.on('mouseout', function(){ circle.closePopup(); });

This has the disadvantage that, if/when the user moves the pointer to over the popup itself, that fires a mouseout event, effectively flickering the popup. This can be worked around by leveraging the pointer-events CSS property, e.g.:

/* JS */
circle.bindPopup('Hello circle', {className: 'popup-with-no-events'});

/* CSS */
.popup-with-no-events {
    pointer-events: none;
}

See a working example.