fix(goals/chart): full money format on "Short" annotation + 4-digit year on x-axis

Two screenshot-driven audit fixes.

The chart's "Short $160.6K" annotation used `_fmtMoneyShort`'s
K/M shorthand while the page's other monetary readouts ("$26,621
to catch up", "$187,031 saved", "$1,830 last 30d") were full
`Intl.NumberFormat` output. Inconsistent units in the same
viewport. Switch the annotation to `_fmtMoney` ("$160,634 short")
+ reword to put the money first ("$X short" reads more naturally
than "Short $X"). Y-axis tick labels keep the K/M shorthand —
that column is space-constrained and the same convention is
already understood as "axis abbreviation."

The x-axis terminal tick rendered `"Jan '27"` from the
`"%b '%y"` time-format string. A glance read it as January 27th
of the year, not January 2027 — and the target-date tick is the
single one users navigate the chart for. Switch to `"%b %Y"` →
"Jan 2027." Slightly wider per tick; the existing adjacent-
duplicate-removal logic keeps the count sane.
This commit is contained in:
Guillem Arias
2026-05-14 21:56:42 +02:00
parent 71ca400f42
commit 40a6613603

View File

@@ -297,9 +297,12 @@ export default class extends Controller {
const collidesWithTargetLabel = targetAmount > 0 && Math.abs(projDotY - y(targetAmount)) < 18;
if (innerWidth >= 320 && !(willHit && collidesWithTargetLabel)) {
// Full Intl.NumberFormat (no K/M shorthand) so the chart annotation
// matches the rest of the page's monetary readouts ("$160,634
// short" reads cleanly next to "$26,621/mo to catch up").
const labelText = willHit
? this._fmtMoneyShort(projectionEnd, data.currency)
: `Short ${this._fmtMoneyShort(targetAmount - projectionEnd, data.currency)}`;
? this._fmtMoney(projectionEnd, data.currency)
: `${this._fmtMoney(targetAmount - projectionEnd, data.currency)} short`;
svg
.append("text")
.attr("x", x(target) - 8)
@@ -377,7 +380,10 @@ export default class extends Controller {
.text("Today");
}
const tickFmt = d3.timeFormat("%b '%y");
// Full 4-digit year so the terminal "Jan 2027" reads as the year, not
// as "Jan 27" (which scans as January 27th). Slightly wider per tick;
// the de-dupe logic below keeps the count sane.
const tickFmt = d3.timeFormat("%b %Y");
const tickCount = Math.min(5, Math.max(2, Math.round(innerWidth / 80)));
const ticks = x.ticks(tickCount);
const tickGroup = svg.append("g");