Component | Tooltip: Re-land #859's fade-in/follow-cursor fix without breaking Crosshair - #923
Open
Vincentdevreede wants to merge 5 commits into
Open
Vincentdevreede wants to merge 5 commits into
Vincentdevreede wants to merge 5 commits into
Conversation
…ver trigger gaps `_display()` removed the `hidden` class and added the `show` class back-to-back in the same tick. With no frame painted in between, the browser could coalesce both class changes into a single style recalc, skipping the "before" state the opacity transition needs to animate from, the tooltip would just pop to full opacity instead of fading in. Forcing a reflow (`getBoundingClientRect()`) between the two class changes guarantees that intermediate frame exists. With `followCursor` enabled, moving the cursor from one trigger into a gap between triggers (e.g. between bars, covered by an axis or another sibling component's element) never fired a mousemove on any configured trigger, since each one only listens on its own element. The tooltip would freeze at its last position instead of tracking the cursor through the fade-out.
…allowHover is enabled Co-authored-by: Nikita Rokotyan <[email protected]>
…s from delegated handlers The delegated mousemove handler hides the tooltip whenever no trigger matches, and since f5#859 it is also attached to the tooltip container. When the container is document.body, any mouse movement on the page hides a tooltip that Crosshair pinned via `forceShowAt`, and the follow-cursor fallback drags it to the pointer. Track ownership instead: `show()` marks the tooltip as externally controlled and `hide()` releases it, so the delegated handlers leave imperatively shown tooltips alone. Co-Authored-By: Claude Fable 5 <[email protected]>
…ointer position With `forceShowAt` set, `shouldShow` still required the pointer to be within the Y range, so moving the mouse over the axis area (inside the SVG but outside the plot) hid the pinned crosshair and tooltip, and leaving the SVG re-showed them — visible as flickering. A pinned crosshair's visibility should only depend on the forced position being within the X range. Co-Authored-By: Claude Fable 5 <[email protected]>
…ontainer-level listeners
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Related to
#859
#898
#902
What happened
#859 fixed two real Tooltip bugs: the fade-in animation not having a frame to start from, and the tooltip freezing mid-fade when the mouse crossed a gap between triggers (e.g. an axis, between bars). It was reverted in #902 because it also broke Crosshairs: the pinned tooltip disappeared or keep rerendering the instant the mouse moved anywhere on the page.
The cause: #859 attached its new delegated
mousemove/mouseleavelisteners to the tooltip's container, which is commonlydocument.body(Crosshair's default). A container-level listener therefore caught mouse movement anywhere on the page, and its "no trigger matched" fallback kept hiding and re-placing Crosshair's imperatively-controlled tooltip.What this PR does
Re-lands #859, #898's two commits by @rokotyan and fixed the remaining gap:
<svg>not the container. Still catches the "gap between triggers", but page-wide mouse movement never reaches these handlers regardless of what the tooltip's container is set to.stopPropagation()on an actual trigger match, so a chart with no triggers configured at all (exactly the Crosshair-driven case) was running the "no match" fallback twice per mousemove. Once via the component, once via the bubbled-up<svg>listener._isControlledExternallyonly when the tooltip actually hides (inside_hide(), nothide()) fixing a race.hide()cleared the flag synchronously even though the real hide can be deferred byhideDelay, letting a delegated handler interfere during that grace period.