Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request: mouseenter/mouseleave for individual features #5539

Closed
bartcorremans opened this issue Oct 27, 2017 · 7 comments
Closed

Request: mouseenter/mouseleave for individual features #5539

bartcorremans opened this issue Oct 27, 2017 · 7 comments

Comments

@bartcorremans
Copy link

bartcorremans commented Oct 27, 2017

Motivation

A common use case for interactive maps is doing something on mouseenter/mouseleave of a geojson feature: highlighting the feature, showing a popup at its location (like in the official example), etc.

The problem I currently have with this is that layer mouseenter/mouseleave events are only fired when the cursor enters/leaves the layer, not individual features. This poses an issue when you have several adjacent features in the same layer with no visible gap between them; when moving the cursor over these features, a mouseenter event will only be fired for the first feature the cursor hovers over. This is insufficient when you want to update individual features or attach a popup at their precise location. The same is true for mouseleave, although it's easy to work around this when you get a new mouseenter event from the next feature.

It'd be a big help if we had something along the lines of a "featureenter" and "featureleave" event, which would fire for individual features.

Design Alternatives

Alternatively, the existing layer mouseenter/mouseleave events could be adapted with this new functionality, but it seems more interesting to me to have both separate use cases available.

With the API that is currently available, I'm not sure how I would go about implementing an elegant and performant "feature mouseenter" use case in my applications.

The only thing I can think of is attaching a mousemove listener on layer mouseenter, and every time it fires, checking which feature the cursor is over and comparing it to the previous one, either by requiring features to have a unique identifier or by checking their coordinates, but this seems neither elegant nor performant.

Ignoring mouseenter/mouseleave altogether and only relying on mousemove seems even worse. In the case of the popup example, this would create the weird effect of the popup anchor moving with the cursor.

If there already is a better way to do what I'm trying to achieve, then my apologies! I'd love to hear about alternative solutions.

Mock-Up

map.on('featureenter', layer, listener) would call the listener with a MapMouseEvent whenever the cursor enters a different feature.

map.on('featureleave', layer, listener) would do the same when the cursor leaves a feature, even if it enters a new feature at the same time.

I imagine this could also work with the 2-argument version of map.on, where the layer isn't specified.

@jfirebaugh
Copy link
Contributor

Hi @bartcorremans, thanks for the detailed and thought-out suggestion! I agree this would be a useful feature.

Attaching a mousemove listener on layer mouseenter, and every time it fires, checking which feature the cursor is over and comparing it to the previous one, either by requiring features to have a unique identifier or by checking their coordinates.

This is in fact how we would implement it at a library level too. It's similar to how the existing layer-oriented mouseenter and mouseleave events are implemented -- as a mousemove listener that queries features on every event and sends the enter or leave event when the results change polarity.

@stevage
Copy link
Contributor

stevage commented Oct 29, 2017

Yeah, I run into this fairly often. I always seem to forget that this isn't how mouseenter and mouseleave work, and am surprised that maps of contiguous polygons seem to be buggy. And then fall back to using mouseover and tracking what the last feature was.

The code usually looks like this:

var lastFeature;
map.on('mousemove', 'polys', e => {
            var f = map.queryRenderedFeatures(e.point)[0];
            if (f.properties.id !== lastFeature) {
                lastFeature = f.properties.id;

                // do something
            }
        });

@jfirebaugh
Copy link
Contributor

#6215

@jordymeow
Copy link

There is no solution or workaround for this yet?

@stevage
Copy link
Contributor

stevage commented Jun 7, 2018

See the workaround I posted three comments back.

@jordymeow
Copy link

@stevage Indeed, thank you, I overlooked the way queryRenderedFeatures is used. Cheers :)

@mvl22
Copy link
Contributor

mvl22 commented Nov 13, 2024

I have posted about the general meta-problem here, in #13326.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants