fix(explorer): stop the canvas growing vertically on every hover - #21
Merged
Conversation
The real cause of the reported "hovering zooms the graph vertically"
bug, and a genuine defect in the explorer's own code -- not a browser
pinch-zoom behavior, which is what the two preceding commits wrongly
guessed at. Those guards are reverted here: they addressed a problem
that wasn't occurring, and both were actively harmful, stripping the
browser's standard Ctrl+scroll and touch-pinch zoom affordance from
the widget.
canvas.height = N is a *reflected* IDL attribute: assigning it also
rewrites the element's "height" content attribute. sizeCanvas() read
getAttribute("height") back as its source of truth for the CSS height,
so every redraw re-multiplied the already-scaled backing-store height
by devicePixelRatio again. mouseleave calls drawMain(), so a single
hover in-and-out doubled the canvas. Measured at dpr 2, hover alone,
no zoom input: 230 -> 460 -> 920 -> 1840 -> 3680 -> 7360 px.
At devicePixelRatio == 1 the multiply is a no-op and the bug cannot be
observed at all -- which is why it shipped, and why the earlier
headless checks (run at the default scale factor of 1) came back clean
and were wrongly read as clearing the chart's own math.
Fix: capture each canvas's intended CSS height once into a memoized
variable and never re-read the attribute that sizeCanvas itself writes.
Verified with headless Chromium at devicePixelRatio 1, 2 and 3: main
and overview canvas heights are byte-stable across 20 hover in/out
cycles, 15 wheel zooms, reset, and window resizes; the backing store is
exactly cssH * dpr at each scale (crisp, not oversized); horizontal
zoom still works; the second widget on the page is independent and
equally stable. The added regression test asserts the structure (height
memoized, never re-read) rather than trying to observe growth, since
the bug is invisible at dpr 1 -- confirmed it fails when the old line
is reinstated and passes when it isn't.
Suite: 268 passed, 1 skipped, 0 failures.
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.
The real cause of the reported "hovering zooms the graph vertically" bug, and a genuine defect in the explorer's own code -- not a browser pinch-zoom behavior, which is what the two preceding commits wrongly guessed at. Those guards are reverted here: they addressed a problem that wasn't occurring, and both were actively harmful, stripping the browser's standard Ctrl+scroll and touch-pinch zoom affordance from the widget.
canvas.height = N is a reflected IDL attribute: assigning it also rewrites the element's "height" content attribute. sizeCanvas() read getAttribute("height") back as its source of truth for the CSS height, so every redraw re-multiplied the already-scaled backing-store height by devicePixelRatio again. mouseleave calls drawMain(), so a single hover in-and-out doubled the canvas. Measured at dpr 2, hover alone, no zoom input: 230 -> 460 -> 920 -> 1840 -> 3680 -> 7360 px.
At devicePixelRatio == 1 the multiply is a no-op and the bug cannot be observed at all -- which is why it shipped, and why the earlier headless checks (run at the default scale factor of 1) came back clean and were wrongly read as clearing the chart's own math.
Fix: capture each canvas's intended CSS height once into a memoized variable and never re-read the attribute that sizeCanvas itself writes.
Verified with headless Chromium at devicePixelRatio 1, 2 and 3: main and overview canvas heights are byte-stable across 20 hover in/out cycles, 15 wheel zooms, reset, and window resizes; the backing store is exactly cssH * dpr at each scale (crisp, not oversized); horizontal zoom still works; the second widget on the page is independent and equally stable. The added regression test asserts the structure (height memoized, never re-read) rather than trying to observe growth, since the bug is invisible at dpr 1 -- confirmed it fails when the old line is reinstated and passes when it isn't.
Suite: 268 passed, 1 skipped, 0 failures.