Leaflet: Canvas renderer obscure other interactive overlays

Created on 11 Jan 2016  路  9Comments  路  Source: Leaflet/Leaflet

A side effect of #3946.

If a vector feature rendered in a <canvas> is partially overlapping some other overlay layer (e.g. an image overlay), then the canvas will capture all events, and will take precedence when it comes to the mouse pointer (i.e. mouse pointer doesn't change to the "hand with finger" when hovering the partially overlapped overlay).

Wondering about the real impact of this, given that nowadays the SVG renderer is supported in all major browsers and canvas is seldom used.

brainmelt bug needs investigation

All 9 comments

Any plans to fix this ? I am using 1.3.1 and mouse events are not propagated if the canvas pane z-index is bigger, even outside the layers of the canvas. As described in #4378

I've been looking at doing the same thing, I find multiple canvas layers convenient.

I've tried several simple things that would require me to change no existing code but all of the changes were not possible or required too much inflexibility.

I think the design with the renderers is not fitting. Especially the on-the-fly linked-list data structure used, which prevents adding layers to different renderers, + lack of performance on mouse events if there's a lot of elements rendered.

It would be nice if stuff drawn on canvas is layered in a single data structure (so that mouse events on transparent parts of canvas work for elements rendered in canvases below).

I'd make a single layer that would listen to mouse events, query the data structure to find elements on that mouse position and fire event on the appropriate layer.

I've just run into this one. Canvas gives a nice performance boost over SVG when rendering lots of layers. Unfortunately, this kills the ability to stack/prioritize panes using zIndex while maintaining mouse interaction. The SVG renderer can cripple the browser really quickly which makes the map useless.

Same thing here. Moved my markers to canvas because they were too many, but now I can't fire click events on the layers below, even I am not exactly clicking on a marker of the canvas. I think this is also related to this: https://github.com/Leaflet/Leaflet/issues/5886

Also, other layers started also being rendered on a canvas. Why can't preferCanvas be applied to specific FeatureGroups instead of everything in the map? 馃

It's possible to do it properly:

  • Create your own leaflet canvas layer
  • During creation of canvas panes/layers you have to somehow know which canvas layer is above which (by setting z-index and similar, DOM layers between canvas layers are a no-no)
  • Create a main top canvas layer that will be empty and that will propagate the mouse events in the correct display order (first the events will go to the top canvas, if hit, then you found the element, if not hit, you propagate the events to canvas below)

You have to have a top layer that is empty and that will propagate the events to lower layers.

It should be about 1k loc. If you are not bound to Leaflet and need performance, use mapbox-gl.
Mouse events in leaflet hit elements with linear search. Meaning if you have a bunch of elements (millions) it's going to get slow. There's extensions for leaflet that use rtrees but that will also need additional work to really get all leaflet functionality.

Hi @vjeranc. Thanks so much for your help! My case is not in the millions but more like thousands. 5k tops. I will take a look at mapbox-gl, but I fear I won't be able to use it because i need the create/editing features of leaflet-draw. I will also try your "non-interactive parent canvas" solution.

I have similar issue and I couldn't understand what was the problem. I set "preferCanvas: true," and then I tried using L.Circle with different panes. Only objects in the last added pane received mouse events even if other panes had higher zindex. Inspection tool shows that the last added pane has a size of ~2500x700 while other panes are 0x0.
So I just write this in case somebody tries to google this bug.

It appears the bug is more complicated than that
Left circle on top canvas: https://jsfiddle.net/b1g8mjhu/
Right circle on top canvas: https://jsfiddle.net/b1g8mjhu/1/
Canvasprefer set to false - everything works: https://jsfiddle.net/b1g8mjhu/2/

In my observations Canvas behave well only if there is single instance: we just put it behind all other features, and all work as expected.
So initial issue as reported by @IvanSanchez may be considered as a "feature".

Multiple canvases may lead to complex problems, as reported by @dimazah30.
I am not sure that we can fix that. May be major refactoring needed.

P.S.
From myself I can describe one more issue with multiple canvases, which is not related to original issue: some browsers are bad in implementation, and several canvases may lead to big memory consumption and jerky panning/zooming.
I observe this with Firefox and some outdated versions of Android WebView.
It's easily reproducible on retina screen, especially with large padding values (like 1).
(My wild guess that it is somehow related to #4578)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

pgeyman picture pgeyman  路  3Comments

prbaron picture prbaron  路  3Comments

JonnyBGod picture JonnyBGod  路  4Comments

CallMarl picture CallMarl  路  3Comments

jblarsen picture jblarsen  路  3Comments