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

Mouse events not working right on circle layers with sub-properties #9469

Open
rbrundritt opened this issue Mar 26, 2020 · 11 comments
Open

Mouse events not working right on circle layers with sub-properties #9469

rbrundritt opened this issue Mar 26, 2020 · 11 comments
Labels
bug 🐞 needs investigation 🔍 Issues that require further research (e.g. it's not clear whether it's GL JS or something else)

Comments

@rbrundritt
Copy link

mapbox-gl-js version: v1.9.0

browser: Chrome

Steps to Trigger Behavior

  1. Create a GeoJSON point feature that has sub-properties of properties (f.properties.subProperty)
  2. Create a circle layer with an expression that uses the sub-property for the radius.
  3. Add mouse enter/leave events that change the mouse cursor.
  4. Hover over the circle. You will find that the mouse events only work when really close to the center of the circle.

Link to Demonstration

https://jsbin.com/zahogipeqo/edit?html,output

Expected Behavior

Mouse events should work as soon as the mouse hits the edge of the circle.

Actual Behavior

The mouse events only work when really close to the center of the circle.

Additional information

I initially noticed this when using a a linear expression, but after simplifying this to simplifying grabbing the sub-property value and using it for the radius, I saw the same issue.

@rbrundritt rbrundritt changed the title Mouse events not working right on circle layers Mouse events not working right on circle layers with sub-properties Mar 26, 2020
@ryanhamley ryanhamley added bug 🐞 needs investigation 🔍 Issues that require further research (e.g. it's not clear whether it's GL JS or something else) labels Mar 26, 2020
@abhinavkumar985
Copy link

I am also facing the same issue and stuck after the implementation. Any update ?

@sg-code
Copy link

sg-code commented Sep 29, 2020

I am experiencing the same issue.

I suspect this has to do with Mapbox GL rendering nested properties as strings, rather than JSON objects. It appears that even though the circle will render to the canvas with the expected circle-radius (using a nested ["get"] expression), it does not transfer that information to the feature's event handler. Instead, the default circle-radius property is used (5px).

This information can be obtained by creating a map.on('click', ... event handler which sends the feature's layer object to the console.

map.on('click', 'layer-id', function(e) {
   console.log(e.features[0].layer.paint);
}

This bug appears to apply to any "paint" properties using nested ["get"] expressions.

It would be a great benefit to take advantage of nested properties, so I hope this issue can be sorted out fairly easily.

@jjgarrett0
Copy link

I would like to see a solution for this as well. I am also experiencing this issue.

@mikejcorey
Copy link

This is affecting me as well. I am able to somewhat get around it by putting a bigger, nearly transparent clickable circle layer behind the visible marker, but it's definitely not ideal as the radius of that invisible layer is sometimes overlapping with neighbors in order to have a fair chance of getting hit. This affects both on('click') and queryRenderedFeatures interactions.

@mikejcorey
Copy link

A user helpfully pointed out that the clickable area of circles seems to have a right-side bias. E.G., you can't click on the left side of circles, but you can on the right side. Maybe something wrong about the center/radius/origin math?

@AliFlux
Copy link

AliFlux commented Sep 23, 2022

Any solution for this yet?

@urschrei
Copy link

Just to note that this bug is still manifesting in v3.6.0, with the offset behaviour that @sg-code and @mikejcorey describe.

@stepankuzmin et al could you have a look?

@stepankuzmin
Copy link
Contributor

Hey everyone,

Unfortunately, GL JS doesn't support compound data types such as arrays and objects (i.e., nested properties) out of the box. See also #7796 (comment):

Taking a step back though, I'm not convinced that adding the ability to parse JSON fosters good vector tile design, since it usually means that you haven't spent much time thinking about your data model. You're right in pointing out that vector tiles currently don't support nested properties and arrays, which make some data models complicated to implement in vector tiles. However, instead of JSON support, we should work towards mapbox/vector-tile-spec#75.

@joshreed
Copy link

@stepankuzmin this behavior of circle layer mouse events not working properly for me happens WITHOUT any nesting within the JSON. I believe the original poster's use of the term "sub properties" may be confusing things from a terminology perspective, because they also mention f.properties.subProperty, which would be indicative of a feature-level property and not "true nesting."

The real problem is that hover/click events on circles is not actually representing the area of the circle shown on-screen, which leads to user confusion. I ultimately had to change it out for a symbol layer with a circle symbol to make it work properly/expectedly. However it seems unfortunate to have to reach towards this work-around.

Hopefully this clarifies things a bit.

@urschrei
Copy link

The real problem is that hover/click events on circles is not actually representing the area of the circle shown on-screen, which leads to user confusion. I ultimately had to change it out for a symbol layer with a circle symbol to make it work properly/expectedly. However it seems unfortunate to have to reach towards this work-around.

Yep, apologies for the confusion, this is exactly what I'm experiencing:

map.addSource('foo', {
    'type': 'geojson',
    'data': '…')
}).addLayer({
    'id': 'foocircles',
    'type': 'circle',
    'source': 'foo',
    'paint': score_style
}).on('click', 'foocircles', (e) => {
    // Get the features under the click event
    const features = e.features[0];
    const coordinates = e.features[0].geometry.coordinates.slice();
    
    // Extract 'school_id' and 'max_score' from the clicked feature's properties
    const schoolId = features.properties.name;
    const maxScore = features.properties.max_score;

    // Create a popup with the extracted information
    const description = `<div><${schoolId}</div><div>${maxScore}</div>`;
     
    // Ensure that if the map is zoomed out such that multiple
    // copies of the feature are visible, the popup appears
    // over the copy being pointed to.
    while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
        coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
    }
    new mapboxgl.Popup()
        .setLngLat(e.lngLat)
        .setHTML(description)
        .addTo(map);
})
// Change the cursor to a pointer when hovering over the circles
.on('mouseenter', 'foocircles', () => {
    map.getCanvas().style.cursor = 'pointer';
})
.on('mouseleave', 'foocircles', () => {
    map.getCanvas().style.cursor = '';
});

The popup works, but the hover and hit area is offset as described above.

@MarlonAACN
Copy link

Experiencing the same issue here. Switching to markers added to the HTML DOM is not an option for us, as we render thousands of circles on the map in our project.

To address this, I devised a workaround that allows us to continue using the circle layer. The solution involves adding another layer to the canvas, based on the same data source as the visible circles. The circles in the new layer are then adjusted to counteract the offset caused by Mapbox, effectively aligning them with the original positions.

    map
      .addLayer({
        id: 'clickable-circles',
        type: 'circle',
        source: 'circle-source',
        paint: {
          'circle-radius': 10, // Matching the radius of the visible circles
          'circle-color': 'rgba(0, 0, 0, 0)',
          'circle-translate': [-15, -15], // Offset for proper click area
        },
      })
      .on('click', 'clickable-circles', (e: MapMouseEvent) => {
         ...
      })

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🐞 needs investigation 🔍 Issues that require further research (e.g. it's not clear whether it's GL JS or something else)
Projects
None yet
Development

No branches or pull requests