Skip to content

fix: percentile chart tooltips and x-axis label overlap#199

Merged
rootulp merged 1 commit into
mainfrom
worktree-optimized-gathering-mccarthy
May 26, 2026
Merged

fix: percentile chart tooltips and x-axis label overlap#199
rootulp merged 1 commit into
mainfrom
worktree-optimized-gathering-mccarthy

Conversation

@rootulp
Copy link
Copy Markdown
Owner

@rootulp rootulp commented May 26, 2026

Summary

  • Hovering over a dot in the Finish Percentile chart (and the Finish Time bars) mapped the cursor to the wrong data point β€” most visibly on the rightmost (most recent) result, which showed the tooltip for an earlier race.
  • X-axis date labels (e.g. Sep 2024) overlapped one another whenever an athlete had roughly 10 races, because the previous step formula returned 1 for any chart with ≀15 points.

Root cause

The SVG uses viewBox="0 0 500 250" with className="w-full" and a fixed style={{ height: 250 }}. With the default preserveAspectRatio="xMidYMid meet", when the container is wider than 500px the content is drawn at scale 1 and centered, so the rendered chart only occupies the middle 500px of the SVG element. The old handleMouseMove treated the entire rendered SVG width as if it were the chart content, so the cursor was mapped a few cells short of where it actually was.

Fix

  • New app/src/components/chart-utils.ts with two pure helpers:
    • cursorXToDataIndex β€” undoes the preserveAspectRatio offset and maps client X back into viewBox coordinates.
    • computeLabelStep β€” derives the tick step from actual per-label spacing vs. minimum label width (~50px for Sep 2024).
  • Both StackedBarChart and PercentileLineChart in AthletePerformanceCharts.tsx use the helpers.
  • New chart-utils.test.ts with 9 vitest cases. Five of them failed against the original logic β€” including the exact "rightmost dot returns index 6 in a 1000px container" case from the bug report β€” and all 31 tests pass after the fix.

Test plan

  • npm test (31 passed)
  • npx tsc --noEmit
  • npm run lint
  • Manually verified on /athlete/jed-radbone--au-m (10 races, 1120px-wide SVG): every dot returns its own tooltip, including the rightmost (2026 IRONMAN 70.3 Da Nang); only 5 of 10 date labels are drawn, no overlap.

πŸ€– Generated with Claude Code

The SVG charts use viewBox 500x250 with default preserveAspectRatio
"meet", so on containers wider than 500px the content is drawn at scale
1 and centered. The previous cursor-to-index math ignored that offset,
so hovering over the rightmost dot mapped to an earlier index. The
label-step formula also returned 1 for any chart with up to 15 races,
causing labels like "Sep 2024" to collide.

Extract cursorXToDataIndex and computeLabelStep into a pure module with
unit tests that reproduce both bugs, then wire them into both the
stacked bar and percentile line charts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@rootulp rootulp self-assigned this May 26, 2026
@rootulp rootulp merged commit b444261 into main May 26, 2026
5 of 6 checks passed
@vercel
Copy link
Copy Markdown

vercel Bot commented May 26, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
tritimes Building Building Preview, Comment May 26, 2026 11:44pm

@rootulp rootulp deleted the worktree-optimized-gathering-mccarthy branch May 26, 2026 23:44
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.

1 participant