Stop uPlot swallowing the click on a chart

uPlot swallows the click that ends a drag, and decides a drag happened by
comparing the position it took at mousedown against the one it holds at
mouseup. It refines the first through `cursor.move` and re-reads the second
raw, never refining it (`mouseUp` -> `cacheMouse(initial: false)`), so with any
correction in place the two never agree: on a scaled panel every click on a
plot read as a drag and was stopped before it reached the page. A chart tile
could not be selected in the dashboard editor by clicking the chart, and a
Health chart could not be clicked to pin a moment.

Not the cursor correction being applied twice — that was a separate defect,
and idempotence could not have fixed this one, since the mouseup path never
applies the correction at all. Not `cursor.y` either: that only decides
whether the y cursor element is created, and both axes are read from the event
regardless.

Drag-to-zoom goes with it, and loses nothing: `setData` re-ranges the scales
from the data on every render, so a dragged range was erased by the next
reading. With no drag there is no click to protect from one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ZeGnqVsf5VHQqvz4HdUhN
This commit is contained in:
2026-08-23 11:07:54 +02:00
co-authored by Claude Opus 5
parent 92fc2e7397
commit f58acfbd43
@@ -270,6 +270,25 @@ export function UplotChart({
// is not, and this must run exactly once per position. // is not, and this must run exactly once per position.
move: (self, left, top) => move: (self, left, top) =>
refine(self.rect.width / self.over.clientWidth, left, top), refine(self.rect.width / self.over.clientWidth, left, top),
drag: {
// No drag-to-zoom. `setData` below re-ranges the scales from the
// data and runs on every render, so a dragged range was erased by
// the next reading — all it ever did here was flash a selection
// box over a live chart.
//
// Which also settles the guard that comes with it. uPlot swallows
// the click that ends a drag, and decides one happened by
// comparing the position it took at mousedown — refined through
// `cursor.move` — against the one it holds at mouseup, which it
// re-reads raw and never refines. On a scaled panel those never
// agree, so *every* click on a plot read as a drag and was
// stopped: a chart tile could not be selected by clicking the
// chart. With no drag there is no click to protect.
x: false,
y: false,
setScale: false,
click: () => {},
},
}, },
legend: { legend: {
live: true, live: true,