Skip to content

fall back to the remaining active pointer’s value - #2467

Open
SahinurDEV wants to merge 1 commit into
observablehq:mainfrom
SahinurDEV:fix/pointer-value-fallback
Open

SahinurDEV wants to merge 1 commit into
observablehq:mainfrom
SahinurDEV:fix/pointer-value-fallback

Conversation

@SahinurDEV

Copy link
Copy Markdown

Problem

When the mouse is within range of several pointers, clearing one of them resets the plot’s value to null, even though another pointer is still focused (#2431):

  • Plot.rect(…, Plot.pointerY({maxRadius: Infinity})) plus Plot.dot(…, {tip: true}): move near the dot (value is the dot’s datum), then away from it inside the frame → value becomes null instead of the rect’s datum, although the rect pointer is still active.
  • With pooled tips (two dots with tip: {maxRadius: 100}), moving from the second dot back to the first sets the value to null: the pool renders the winner first and then the loser with null, and the loser’s render dispatches null last.

Cause

Each pointer’s render dispatches its own value directly (context.dispatchValue(i == null ? null : datum)), so whichever pointer renders last wins, including a pointer that just cleared. The other pointers don’t re-render (their focused index didn’t change), so nothing restores their value.

Fix

Keep a per-plot focus map (render index → focused datum) in the shared pointer state. On each render, the mark updates its own entry (removed when cleared, re-inserted when focused so the most recently focused pointer is last), and the dispatched value is that of the most recently focused pointer still active, or null when none is. The existing facet guard (prefer the entering facet when exiting another) is unchanged; clearing all pointers on pointerleave or when releasing a sticky pointer still yields null.

Tests

Added a pointer value suite in test/pointer-test.js:

  • the rect pointerY + dot tip scenario from the issue: value goes "foo" → dot datum → back to "foo" → null on pointerleave;
  • two pooled tips: moving right then back left keeps the winner’s datum (and one visible tip).

Both fail on main (value is null) and pass with this change. Full vitest --typecheck run passes (404 files, 1351 tests), and tsc, eslint src test and prettier --check src test are clean.

Fixes #2431

When several pointer marks are active (e.g., a pointerY on a rect and a tip
on a dot, or pooled tips), each render dispatched its own value, so clearing
one pointer set the plot’s value to null even though another pointer was
still focused. Track the focused datum per rendered mark and dispatch the
value of the most recently focused pointer that is still active.

Fixes observablehq#2431

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Plot value not restored correctly when interacting with multiple pointers

1 participant