maplibre / maplibre-gl-js

MapLibre GL JS - Interactive vector tile maps in the browser
https://maplibre.org/maplibre-gl-js/docs/
Other
6.01k stars 661 forks source link

Allow a "margin" for mouse over layer events #3045

Open PanierAvide opened 10 months ago

PanierAvide commented 10 months ago

User Story

As a map user with a mouse, I can easily click on small or fine vector features, so that I don't struggle when using the map.

(First time writing a single-sentence user story, sorry if that's bad :sweat_smile: ).

Rationale

As now, mouse events related on hovering a vector layer are only thrown if cursor is exactly over a vector feature. This is logical, but is limiting when you're rendering small points or fine lines. In that case, user should point very precisely on a feature so that any app logic can start.

As an exemple, here is a map showing pictures taken along roads : https://files.pavie.info/clients/panoramax/next_ui/#focus=map&map=6.24/47.185/-0.183&speed=250

(This is part of a wider project called GeoVisio / Panoramax, a fully free/open-source/self-hosted Google Street-View/Mapillary alternative).

I didn't find any documented workaround (but maybe I didn't search enough ?) in order to keep fine lines visually, but with a broader invisible thickness for triggering mouse over/enter/leave events.

I guess new style parameters could allow users to define this event hitbox :

Impact

This feature could help all kind of users, and maybe even more people suffering from hand tremors (like suffering from Parkinson disease) where click/hover interactions should not require a very precise mouse positioning. An invisible broader hitbox allows map designer to keep things beautiful, while user experience is made easier.

What if we do nothing? What is the impact to end-users if we don't implement this feature?

Not implementing this feature implies that:

Best regards

HarelM commented 10 months ago

I agree this can be improved, but generally speaking, you can use the map (not layer) hover event and query render features with margin. I'm not sure about performance, but I think it's possible, haven't tried it though.

PanierAvide commented 3 months ago

I cheated meanwhile to simulate this behaviour by adding a supplementary layer with transparent rendering and larger width:

        "paint": {
            "line-width": ["interpolate", ["linear"], ["zoom"], 0, 15, TILES_PICTURES_ZOOM+1, 30, TILES_PICTURES_ZOOM+2, 0],
            "line-opacity": 0,
            "line-color": "#ff0000",
        },
        "layout": {
            "line-cap": "square",
        }

This works as expected, but is more code to maintain as every event handler, style & co is duplicated.

wipfli commented 3 months ago

I usually place an invisible wider line over the line you what to get click events for. Just do something like this:

{
  "id": "my-invisible-click-event-line",
  "type": "line",
  "source": "my-source",
  "sourceLayer": "my-source-layer",
  "paint": {
    "line-opacity": 0.0,
    "line-width": 10
  }
}
wipfli commented 3 months ago

I hope it is not inadequate to advertise ChatGPT here, but it is just so good for maplibre style development...

https://chat.openai.com/share/d80fc2a4-806c-41eb-a059-79f1a61c513d