Conversation
| return Boolean( | ||
| (xa && xa.showspikes && xa.spikesnap !== 'hovered data') || | ||
| (ya && ya.showspikes && ya.spikesnap !== 'hovered data') | ||
| ); |
There was a problem hiding this comment.
Or perhaps
| return Boolean( | |
| (xa && xa.showspikes && xa.spikesnap !== 'hovered data') || | |
| (ya && ya.showspikes && ya.spikesnap !== 'hovered data') | |
| ); | |
| return (xa?.showspikes && xa.spikesnap !== 'hovered data') || | |
| (ya?.showspikes && ya.spikesnap !== 'hovered data'); |
There was a problem hiding this comment.
That's fine, but let's keep the Boolean() to avoid returning undefined
There was a problem hiding this comment.
The presence of the strict inequality operator (!==) at the end of both clauses forces the final output to always be a boolean.
There was a problem hiding this comment.
Hm, I realized that if xa?.showspikes evaluates to falsy (but not false) then the !== condition will be short-circuited, so may not return a boolean.
I've updated the logic to use the question-mark notation but keep the Boolean().
| spikePoints.vLinePoint = tmpPoint; | ||
| } | ||
| } | ||
| if (closestPoints && closestPoints.length) { |
There was a problem hiding this comment.
| if (closestPoints && closestPoints.length) { | |
| if (closestPoints?.length) { |
There was a problem hiding this comment.
FWIW I didn't touch this logic at all; it only shows up in the diff because the indentation changed. I'm fine with making this change though.
Closes #5927
Closes #5790
Closes #8036
(Supersedes #7998)
Fix unreasonably slow scattergl hover behavior (to the point of freezing) in the default case. Even with this fix, the hover is still somewhat laggy, but doesn't freeze entirely as in the linked issues.
The scattergl hover logic was following a code path which looks for nearby points to draw spikelines to. This code path was being followed even when spikelines were not enabled. The search is very slow with large numbers of points. This PR adds a guard to skip the "find nearby points" search unless required.
Note: For the diff chunk in
src/components/fx/hover.jsstarting on line 671, the only meaningful change is addingcanSpikeToNonHoveredPoint()to theifcondition. The rest of that diff is just indentation change from collapsing two nestedifstatements into 1.Screen recording
This video shows the performance I see on my machine after this fix, with extremely closely-spaced points.
scattergl-hover.mov
Steps for testing:
main. Notice that the entire plot freezes completely when trying to hover.Caveat
There's an underlying performance issue which is not addressed by this PR, which probably deserves its own issue. #8036 points out that there's a performance cliff which starts at 100k points, even though 99,999 points are fine. At 100k points we exceed the
TOO_MANY_POINTSconstant defined insrc/traces/scattergl/constants.ts, which triggers us to use a tree data structure for searching through points, rather than a plain array.I haven't fully investigated but there seems to be some performance issues with that tree implementation (which is ours: see https://github.com/plotly/point-cluster), specifically with the
.range()function called here. It's extremely slow when given infinite bounds, and seems to be slower than regular array traversal whenever the bounds cover a significant fraction of the total points. Either we're calling the.range()function in a non-optimal way, or there's a bug in the implementation. Hence why even with this fix, the scattergl hover is still somewhat laggy as soon as we exceed 100k points.