Hugo H
Hugo H

Reputation: 6362

Leaflet: open popup at cursor position instead of LineString center

I have a leaflet map with a LineString.

// a GeoJSON LineString
var geojson = {
  "type": "Feature",
  "geometry": {
    "type": "LineString",
    "coordinates": [[-101.123, 40.2500], [-101.123, 40.2503]]
  }
};

// create map and add json
var map = L.map('map');
var geojsonLayer = new L.GeoJSON(geojson).addTo(map);
map.fitBounds(geojsonLayer.getBounds())

// add popup for the line
geojsonLayer.eachLayer(function (layer) {
  var popup = L.popup();
  popup.setContent('text');

  layer.bindPopup(popup);
  layer.on('click mouseover', function () {
    layer.openPopup();
  });
});

When I over it, a popup opens at the LineString center.

How can I make it open over at the cursor position?

Here is a simple working example: http://jsfiddle.net/wuu8Lv2t/1/

Upvotes: 2

Views: 6777

Answers (3)

JMers
JMers

Reputation: 185

The accepted answer (by @YaFred) is pretty good, what's key is the update function layer.on('mousemove'... . However, as written, closing and opening the popup every time your mouse moves, makes it flicker. Instead, in layer.('mousemove... you only need the line that updates the location:

// add popup for the layer
geojsonLayer.eachLayer(function (layer) {
  var popup = L.popup();
  popup.setContent('text');
  layer.bindPopup(popup);

  layer.on('mouseover', function (e) {
    var popup = e.target.getPopup();
    popup.setLatLng(e.latlng).openOn(map);
  });

  layer.on('mouseout', function(e) {
     e.target.closePopup();
  });

  // update popup location
  layer.on('mousemove', function (e) {
    popup.setLatLng(e.latlng).openOn(map);
  });
});

Upvotes: 2

Hugo H
Hugo H

Reputation: 6362

Here is a an answer from Per Liedman, a Leaflet maintainer:

You can achieve this by creating a new popup and adding at the desired location, instead of binding it. Since a bound popup can be opened by other means than a mouse click, it can't know where to open.

Here is the corresponding code:

// a GeoJSON LineString
var geojson = {
  "type": "Feature",
  "geometry": {
    "type": "LineString",
    "coordinates": [[-101.123, 40.2500], [-101.123, 40.2503]]
  }
};

// create map and add json
var map = L.map('map');
var geojsonLayer = new L.GeoJSON(geojson).addTo(map);
map.fitBounds(geojsonLayer.getBounds())

// add popup for the line
geojsonLayer.eachLayer(function (layer) {

  layer.on('click mouseover', function (e) {
    var popup = L.popup()
        .setLatLng(e.latlng)
        .setContent('text')
        .openOn(map);
  });
});

See here for a modified example: http://jsfiddle.net/uwdnvfy6/

Upvotes: 2

YaFred
YaFred

Reputation: 10008

Don't let the layer open the popup, instead use openOn(map) setting the position with the coordinates from the event e.latlng

// add popup for the line
geojsonLayer.eachLayer(function (layer) {
  var popup = L.popup();
  popup.setContent('text');
  layer.bindPopup(popup);

  layer.on('mouseover', function (e) {
    var popup = e.target.getPopup();
    popup.setLatLng(e.latlng).openOn(map);
  });

  layer.on('mouseout', function(e) {
     e.target.closePopup();
  });

  layer.on('mousemove', function (e) {
    e.target.closePopup();
    var popup = e.target.getPopup();
    popup.setLatLng(e.latlng).openOn(map);
  });
});

Note that in your question there is a mistake: you can't use the variable layer in the event hander, you have to use e.target (see doc).

Upvotes: 5

Related Questions