plotly / plotly.js

Open-source JavaScript charting library behind Plotly and Dash
https://plotly.com/javascript/
MIT License
17.05k stars 1.86k forks source link

image and heatmap traces jump/flash on Firefox and Safari #4377

Open jonmmease opened 4 years ago

jonmmease commented 4 years ago

The new image trace seems to have a flashing/jumping behavior when zoomed in and panning on Firefox and Safari. (Firefox version 69.0, Safari version 13.0.3)

Example from https://plot.ly/python/imshow/

image_jump

This jumping does not happen on Chrome but I do see it on Firefox/Safari. Not sure if it's related, but in all three browsers, the tooltip also seems to jump to another location when the pan is completed.

antoinerg commented 4 years ago

@jonmmease I think the issue also occurs on heatmap (https://plot.ly/python/heatmap/). Could you rename the issue to reflect that?

The problem stems from reinjecting an image when pan operation is completed. I thought this pattern was safe since it's been used for a long time in heatmap. Maybe this issue only affects newer versions of Firefox :thinking: ?

jonmmease commented 4 years ago

Could you rename the issue to reflect that?

Done, thanks!

etpinard commented 4 years ago

Hmm. I can't replicate in FF 70

jonmmease commented 4 years ago

Hmm, I am seeing it in FF 70 on Ubuntu. @antoinerg were you able to reproduce?

antoinerg commented 4 years ago

Hmm, I am seeing it in FF 70 on Ubuntu. @antoinerg were you able to reproduce?

I can reproduce it in FF 70.0.1 (64-bit) on Linux (NixOS distro).

firasm commented 4 years ago

I can also reproduce in Safari 13.0.3 on macOS 10.15.1.

On the same system, the problem does not appear in Chrome Version 78.0.3904.108.

etpinard commented 4 years ago

@antoinerg do you think there's an "easy" way to fix this bug?

Or do you think our canvas -> pixels -> img inside the _paper SVG is fundamentally flawed and FF does behaves as expected?

antoinerg commented 4 years ago

Or do you think our canvas -> pixels -> img inside the _paper SVG is fundamentally flawed and FF does behaves as expected?

It's hard to say which one behaves right and I suspect the specification may not be clear in this regard.

do you think there's an "easy" way to fix this bug?

Idea for an easy fix: have two images (A and B) and alternate between the two. Once you pan, image B content is updated and moved in front of image A (so no flash in principle). Then if you pan again, image A content is updated and moved in front and so on. Hopefully, this approach works.

If we only target a fix for FF: leverage image-rendering: pixelated, draw the image only once and things will fly :racehorse:.

alexcjohnson commented 4 years ago

So we're reverting the drag, then redrawing with the new view... and it seems like even if we do this synchronously, some browsers will do two repaints (if that's it, there will be async edge cases in other browsers too). I wonder if we can just not revert the drag, and tweak the redraw process if necessary so it still works right. I think it's this call that's doing it:

https://github.com/plotly/plotly.js/blob/4ab3b49c12e3e8be3800f7e4aacd4dddcf497357/src/plots/cartesian/dragbox.js#L770-L774

updateSubplots seems to modify some internal state as well as adjusting viewboxes, we still may need the internal state even if we don't change anything visible.

antoinerg commented 4 years ago

This may be a problem with Firefox itself: Images are flashing when updates by img.src[]=url in Firefox >= 8.0

Potential solution: https://stackoverflow.com/questions/14704796/image-reload-causes-flicker-only-in-firefox/14711272#14711272

etpinard commented 4 years ago

FYI: using some navigator.userAgent-based solution here would be :ok_hand: with me.


It would be interesting to see how image-rendering: pixelated performs in comparison to the current algorithm. Using that in browsers that support it could be a big win and allow us to fix this problem in FF.

The solution in https://stackoverflow.com/questions/14704796/image-reload-causes-flicker-only-in-firefox/14711272#14711272 may be a quick and easy way to fix this bug in Safari (albeit with a potential performance cost).

antoinerg commented 4 years ago

The issue is twofold:

  1. Image is flashing (can be fixed by not redrawing the image)
  2. Tooltip appears at the position of the last click

EDIT: I opened an issue to tackle 2) since it affects other trace types (https://github.com/plotly/plotly.js/issues/4570)

antoinerg commented 4 years ago

@etpinard at the moment, when an axis has a scaleanchor attribute (the default for image), the calc step is called on every pan operation. For the planned improvement to the image trace type, this is somewhat undesirable. We'd like to produce the image in calc once and then simply move/scale it in the plot phase when a pan operation is completed. The goal is to save ourselves from the sometimes expensive operation of looping over all the pixels in view (and then some). Do you see potential roadblocks or flaws in trying to achieve what I just described? How would you go about skipping the calc phase when it's being triggered by a pan?

etpinard commented 4 years ago

Here's the relevant logic that makes zoom interactions go through the 'calc' pipeline:

https://github.com/plotly/plotly.js/blob/15d75db46fb88d5dd11b8d6945bb74064198c47e/src/plot_api/plot_api.js#L2274-L2293

By the looks of it, all the range "constraints" operations are taken care of in

https://github.com/plotly/plotly.js/blob/15d75db46fb88d5dd11b8d6945bb74064198c47e/src/plots/cartesian/constraints.js#L198-L352

which is called during

https://github.com/plotly/plotly.js/blob/15d75db46fb88d5dd11b8d6945bb74064198c47e/src/plot_api/subroutines.js#L669-L721

from a few places in plot_api.js including in the "fast" 'axrange' edit pipeline:

https://github.com/plotly/plotly.js/blob/15d75db46fb88d5dd11b8d6945bb74064198c47e/src/plot_api/plot_api.js#L1970-L1976


So perhaps zoom/pan interaction just work already under the fast 'axrange' edit pipeline? @antoinerg have you tried commenting the above block in _relayout to see in any tests fail?

We'll have to be extra careful though. I wouldn't want to trust 100% our test coverage for constraints.

But yeah, to answer your question, making zoom/pan on constrained axes not have to go through the 'calc' pipeline would be a huge win for image traces. Maybe 'axrange' works already, maybe we'll need a new flavour of that 'axrange' pipeline, but yeah we can do better than 'calc'!

etpinard commented 4 years ago

(Ping, I updated my comment above)

jackparmer commented 4 years ago

This issue has been tagged with NEEDS SPON$OR

A community PR for this feature would certainly be welcome, but our experience is deeper features like this are difficult to complete without the Plotly maintainers leading the effort.

Sponsorship range: $10k-$15k

What Sponsorship includes:

Please include the link to this issue when contacting us to discuss.