SVG pointer accuracy and binned calendar heatmap - #27
Conversation
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Superseded by #44, rebased onto current main with the original implementation preserved plus a real-browser negative-control regression and reconciled baselines. |
Problem
Responsive width charts inside a fixed-height card, flex/grid shrinking, or weird padding can make the SVG and CSS viewports mismatch.
Pointer hit-testing mapped browser coordinates from the SVG element's full bounding box directly into chart coordinates. When the CSS viewport and SVG
viewBoxhave different aspect ratios, the defaultpreserveAspectRatio="xMidYMid meet"centers the rendered scene with letterboxed space around it. Treating that empty space as chart space shifts hover and focus selection—by nearly one calendar row in this example.Fix
Use the SVG screen matrix instead of assuming the bounding box matches the painted scene:
getScreenCTM()describes the complete scene-to-viewport transform, including scale, centering, CSS/SVG transforms, and letterboxing. Applying its inverse returns the pointer to the correct scene coordinate. The existing bounds calculation remains as a fallback for incomplete DOM environments.This is the established approach used by D3
pointer, D3's implementation, and Airbnb visxlocalPointGeneric. See also MDN onpreserveAspectRatioandgetScreenCTM().Example
Adds Token use calendar heatmap, a responsive interaction case that also demonstrates
binTimeXdaily token/session aggregation, explicit UTC bins, transform lineage, calendar layout, keyboard focus, and a mark-anchored portal tooltip.You can see in this little recording how my cursor tracks the row below it because there's like ~13px of space above and below the container due to the SVG
viewBoxstuff.CleanShot.2026-07-31.at.21.21.54.mp4
Verification
typecheck, 654 tests, package/catalog/docs checks, bundle check, and browser verification at 320/640/960px widths all pass.