Hover-scrubber on projection charts — cursor reveals predicted time/% (parked 2026-05-24)
DARE.CO.UK · PARKED SKETCH · 2026-05-24
Mirrored from ~/.claude/.../memory/parked_sketch_hover_scrubber_projection_chart_2026-05-24.md. This is a design sketch parked for future build — read for context, not as a current deliverable.
Mousing over the projection line (or anywhere on the trend chart) surfaces a tooltip with the predicted timestamp + percentage complete + estimated PNG count at that x-coordinate. Cursor becomes a scrubber along the projected path. Same SVG, +JS event handler. Lifts to batch-status template + any future chart with a projection layer.
Dan 2026-05-24: “if you mouse over the predicted path of either graph, the cursor can calculate the predicted time/percentage-complete/number-estimated-to-be-completed, it’s like a layer of insight that your mind doesnt have to run.”
What this adds
The projection line on the trend chart visually answers “when will we finish?” The hover-scrubber answers a richer question at any x-coordinate: “if I’m wondering what state we’ll be in at 9am tomorrow / next Monday / when I get home Friday, point at that x and see.”
The math the eye otherwise runs (interpolate x → t, project count via pace, format both) becomes free.
Two reading modes — and the inverse insight Dan flagged
Dan 2026-05-24 extending: “the math can be derived, to assess on what day/date, roughly 75% will be achieved, at current trajectory. That’s where data-viz really adds layers of value.”
This unlocks two complementary hover modes:
| Mode | Cursor input | Answer |
|---|---|---|
| Forward | Cursor at time-axis position (X) | At that time we’ll be at N% (Y count) |
| Inverse | Cursor at count-axis position (Y) | We’ll reach that count on T (X date) |
Both are derivable from the same projection slope. Cursor proximity to axis decides which one is active, OR show both lines (vertical guide + horizontal guide forming a crosshair at the projection intersection).
Default milestone annotations (no hover needed)
Even better — render the milestone-crossings as fixed annotations on the projection line so the answer is visible on first view, no interaction required:
- 25% will be at:
<date>·<time ET> - 50% will be at:
<date>·<time ET> - 75% will be at:
<date>·<time ET> - 100% will be at: ETA (already shown)
Three small dots along the projection line with date labels. Static SVG, no JS, no library. Adds the milestone-crossing insight on first paint; hover-scrubber adds the arbitrary-point insight as a richer layer on top.
Two-tier value: - Tier 1 (zero-effort) — fixed milestone annotations. Always-on. Answers most “when will we hit X%” questions before they’re asked. - Tier 2 (hover) — scrubber for the exact arbitrary point. Pays off when Tier 1’s coarseness isn’t enough.
Implementation shape
Pure JS event handler on the SVG (no library). On mousemove:
- Translate
event.offsetXback to a time via the chart’s x-axis range - If the cursor is between
nowandETA, compute: -predicted_count = current_count + pace_per_hour × hours_since_now-predicted_pct = 100 × predicted_count / target-predicted_ts = now + hours_since_now - Render a vertical guideline + a small floating callout
- On
mouseleave, hide the callout
Approx ~40 lines of inline JS. SVG already has the data it needs (data-attributes on key elements or recalculate from chart constants).
Where it lives
| Chart | Hover behavior |
|---|---|
| Trend chart (status pages) | Hover anywhere → vertical guideline at cursor + floating tooltip showing <predicted-time-ET> · <count> · <pct> |
| Bullet chart | Hover on the bands → tooltip shows what percentage cluster + projected timestamp to reach that band’s right edge |
| Future · vehicle TCO grouped bar | Hover on a bar segment → show category total + share of vehicle’s lifetime |
| Future · category spend stacked area | Hover on a year × category cell → show year total + cumulative-to-date |
Why this is a “future-pattern-rationalization-pending” build
Three reasons not to ship inline today:
- Pattern home not chosen. Inline JS in
pa_job_status_render.pyworks but doesn’t help when the Harvest renderer wants the same thing. Belongs inassets.gf.cx/charts/hover-scrubber.jsas a primitive — but that primitive doesn’t exist yet (perparked_sketch_d3_comparison_primitives_2026-05-24.md). - Specificity threshold. Current status page has one trend chart with two points (start, last); hover-scrubber pays off when the trend has more substance — once 50+ history points accumulate, the chart will be data-dense enough that hover-insight actually answers questions the eye couldn’t quickly.
- Other primitives to build first. Cards-as-primitive, charts-as-primitive — both blocking before this layer pays off cleanly.
Build trigger
Build when ALL of: - Cards-as-primitive lands (so the chart container is consistent) - A second surface needs a projection chart with the same hover behavior (e.g. vehicle TCO trend, harvest spend trajectory) - A status page has 30+ history points (enough density to scrub)
Estimated cost (when triggered)
| Layer | Effort |
|---|---|
| Tier 1 — fixed milestone annotations (25/50/75/100%) in SVG | ~30 min — pure server-side render, no JS |
| Tier 2 — hover-scrubber JS handler + floating tooltip | ~1 hour |
| Tier 2 — inverse mode (count-axis hover) | ~30 min |
| Integration into pa_job_status_render.py + replication to Harvest renderer | ~30 min |
| Tier 1 alone | ~30 min — ship first, biggest payoff per minute |
| Full Tier 1 + Tier 2 | ~2.5 hours |
Cross-references
parked_sketch_d3_comparison_primitives_2026-05-24.md— broader chart-primitive parking; this is one capability inside thatfeedback_xlab_co_toolkit_web_assets_home.md— where the primitive eventually livespa_job_status_render.py— first beneficiaryfeedback_simple_charts_disproportional_weight.md— sibling philosophy: don’t add chart-junk; this passes that test because the hover layer is invisible until invoked
The aphorism
Static charts answer the question once. Hover-aware charts answer every question you didn’t know you had until your cursor was there.