Mapbox-gl-js: Track popups to mouse cursor

Created on 15 Jan 2019  路  8Comments  路  Source: mapbox/mapbox-gl-js

Motivation

I've seen many use cases (in Studio's data inspector, in my own demos, and from others) where we'd want a popup "inspector" to follow the mouse, rather than any static lnglat. I've usually built these from scratch, but would be ideal to extend the current popup API for this.

Design Alternatives

Can simulate this with the current popup by detecting mouse position on every mousemove, projecting that to lnglat, and setLngLat to the popup. On mouseout and mouseenter of the map element, the popup would hide and show itself, respectively.

But it would be nice to one-line this.

Design/Mockup

Some API ideas:

  • popup.setLngLat({trackCursor: true}) : would expand the current method accept object literals
  • popup.trackCursor(): would add a new method to the Popup class, that along with setLngLat would mutually overwrite each other.
  • Have mouse tracking as the default behavior if setLngLat is not called. May be the easiest to implement, but weirdest to use in practice.
feature

All 8 comments

I think this would be pretty similar to the draggable marker code, the meat of which is https://github.com/mapbox/mapbox-gl-js/blob/master/src/ui/marker.js#L371-L375 It's also important to account for any offset between the cursor position and the position of the element being moved around the screen which is calculated here https://github.com/mapbox/mapbox-gl-js/blob/master/src/ui/marker.js#L441

Another use case for this would be working with multiple, stacked fill extrusions and querying them to show a popup with information as you move to various "floors" of the stacked extrusions. Could be useful for things like real estate apps or terrain applications with raster-dem tiles.

I think this would be pretty similar to the draggable marker code

@ryanhamley exactly, though can we short-circuit the mouse pixel 鉃★笍 lnglat 鉃★笍 popup translation pixel dance, and just keep everything in px? Cursor offset straight to popup's CSS translate 馃

You mean because there wouldn't be a LatLng for the popup in the case where it's following the cursor? I think that makes sense. I just wonder if leaving latLng undefined or null would cause unexpected issues elsewhere. It's definitely something you could explore. My guess is the main argument against cutting out the conversion to/from LatLng in this case is one of consistency within the API.

mouse cursor popup I do this way:

popup(event) {
  const canvas = this.map.getCanvas();
  const node = document.querySelector('#map-popup');
  if (event) {
    canvas.style.cursor = 'pointer';
    node.textContent = event.features[0].properties.title;
    node.style.left = `${event.originalEvent.clientX}px`;
    node.style.top = `${event.originalEvent.clientY}px`;
    node.style.display = 'block';
  } else {
    canvas.style.cursor = '';
    node.style.display = 'none';
    node.textContent = '';
  }
}
this.map.on('mousemove', layer, event => this.popup(event));
this.map.on('mouseleave', layer, () => this.popup());

Using CSS you can center it with translate (you don't need to know actual width / height of popup node).

Example:
jan-18-2019 17-24-35

Interesting, I always do it external to GL JS.

Where tooltip is a div element:

/* update the tooltip location based on where the cursor is */
window.onmousemove = function (e) {
    var x = e.clientX,
        y = e.clientY;
    tooltip.style.top = (y + 10) + 'px';
    tooltip.style.left = (x + 10) + 'px';
};

Then I watch the GL JS mousemove event and either set the tooltip display style to none or block.

Though I'm :+1: for making this a one-liner in GL JS core, it's a common use case.

Y'all (@andrewharvey and @bravecow) can just follow mapbox's guide to display a popup on hover, but set the popup's lngLat to the mapbox event's lngLat property.

popup.setLngLat(e.lngLat)
.setHTML(description)
.addTo(map);

Should this be included as a hint in the official example, rather than a completely new implementation?

@peterqliu your PR for this fix just needs to have a couple of conflicts resolved and then it can be merged and this issue can be closed

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mollymerp picture mollymerp  路  3Comments

aendrew picture aendrew  路  3Comments

Scarysize picture Scarysize  路  3Comments

yoursweater picture yoursweater  路  3Comments

rasagy picture rasagy  路  3Comments