Canvas renderer mouseover event precedence is incorrect when features have overlapping pixels
See original GitHub issueHow to reproduce
- Leaflet version I’m using: 1.0.1
- Browser I’m using: Chrome
- OS/Platform I’m using: Windows 10
What behaviour I’m expecting and which behaviour I’m seeing
I expect that when two features render with overlapping pixels (which does not necessarily mean overlapping geometries) the feature that renders on top will be the only feature to receive mouseover events. The default SVG renderer handles overlapping features in this way. The canvas renderer triggers mouseover events on all layers that contain the mouseover point. It’s a bit hard to put into words so for the sake of brevity here are two gifs
SVG (expected):
Canvas: (unexpected)
I believe that this was introduced (or at least made more apparent) by https://github.com/Leaflet/Leaflet/commit/609a79279272c88f1089bc2119d309b18c169110 which removes the break statement.
Minimal example reproducing the issue
- A jsfiddle with a very simple example: http://jsfiddle.net/jcollin6/6k05szap/7/
Possible solution
I would be willing to put up a PR for this but I don’t know how. I tested these changes by directly modifying my local copy of leaflet.
_handleMouseHover: function(e, point) {
var id, layer, drawnLayerKeys;
// reverse the keys so that we check layers from the top down
drawnLayerKeys = Object.keys(this._drawnLayers).concat().reverse();
for (var i = 0; i < drawnLayerKeys.length; i++) {
id = drawnLayerKeys[i];
layer = this._drawnLayers[id];
if (layer.options.interactive && layer._containsPoint(point)) {
L.DomUtil.addClass(this._container, 'leaflet-interactive'); // change cursor
if (this._hoveredLayer && (this._hoveredLayer._leaflet_id.toString() !== id.toString())) {
// If we find a match but another layer is already 'hovered'
// then trigger mouseout on that layer
this._fireEvent([this._hoveredLayer], e, 'mouseout');
}
this._fireEvent([layer], e, 'mouseover');
this._hoveredLayer = layer;
// MUST break so that lower layer mouseover events are not triggered
break;
}
}
if (this._hoveredLayer) {
this._fireEvent([this._hoveredLayer], e);
}
}
Issue Analytics
- State:
- Created 7 years ago
- Comments:6 (5 by maintainers)
Top GitHub Comments
@perliedman @IvanSanchez Thanks for the quick turnaround on this guys! The hovering in my fiddle works great now!
This is what i’ve been using since https://github.com/Leaflet/Leaflet/issues/4495 , it’s not great since it keeps firing the mouseout and mouseover events but at least in my app it’s working because it’s firing the mouseout events that I really needed. https://playground-leaflet.rhcloud.com/rix/edit?html,js,console,output