Label the revenue axis in euros

The y-axis ticks and the hover both carry the unit now — an axis in euros with a
bare number in the tooltip reads as two different quantities.

Two formatters, not one: the axis rounds to whole euros to keep the labels short,
but the tooltip keeps the cents. Rounding an amount someone is reading off a
chart to answer "how much did we take in March" is a lie, and €1.234,50 becoming
"€ 1.235" is exactly that.

Locale is nl-BE, so it renders "€ 1.234,50" rather than "€1,234.5".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-14 01:02:14 +02:00
parent 016206a79e
commit 21d3947d08
2 changed files with 23 additions and 5 deletions

View File

@@ -196,7 +196,13 @@
const ink = css("--color-base-content", "#333"); const ink = css("--color-base-content", "#333");
const grid = "color-mix(in oklab, " + ink + " 15%, transparent)"; const grid = "color-mix(in oklab, " + ink + " 15%, transparent)";
const build = (id, label, series, colour, type) => // Locale-aware, so 1234.5 reads as "€ 1.234,50" rather than "€1,234.5". Two of
// them: the axis is rounded to keep the labels short, but the tooltip keeps the
// cents — rounding a euro amount someone is reading off a chart is a lie.
const axisEuros = new Intl.NumberFormat("nl-BE", { style: "currency", currency: "EUR", maximumFractionDigits: 0 });
const exactEuros = new Intl.NumberFormat("nl-BE", { style: "currency", currency: "EUR", minimumFractionDigits: 2 });
const build = (id, label, series, colour, type, money) =>
new Chart(document.getElementById(id), { new Chart(document.getElementById(id), {
type, type,
data: { data: {
@@ -206,17 +212,26 @@
options: { options: {
responsive: true, responsive: true,
maintainAspectRatio: false, maintainAspectRatio: false,
plugins: { legend: { display: false } }, plugins: {
legend: { display: false },
// The tooltip carries the unit too: an axis in euros and a bare
// number on hover reads as two different quantities.
tooltip: money ? { callbacks: { label: (item) => exactEuros.format(item.parsed.y) } } : {},
},
scales: { scales: {
x: { ticks: { color: ink }, grid: { color: grid } }, x: { ticks: { color: ink }, grid: { color: grid } },
y: { beginAtZero: true, ticks: { color: ink, precision: 0 }, grid: { color: grid } }, y: {
beginAtZero: true,
grid: { color: grid },
ticks: { color: ink, precision: 0, callback: money ? (value) => axisEuros.format(value) : undefined },
},
}, },
}, },
}); });
return [ return [
build("signups-chart", "Signups", data.signups, css("--color-primary", "#4f46e5"), "bar"), build("signups-chart", "Signups", data.signups, css("--color-primary", "#4f46e5"), "bar", false),
build("revenue-chart", "Revenue", data.revenue, css("--color-accent", "#0ea5e9"), "line"), build("revenue-chart", "Revenue", data.revenue, css("--color-accent", "#0ea5e9"), "line", true),
]; ];
}; };

View File

@@ -3357,6 +3357,9 @@
.overflow-x-auto { .overflow-x-auto {
overflow-x: auto; overflow-x: auto;
} }
.rounded {
border-radius: 0.25rem;
}
.rounded-box { .rounded-box {
border-radius: var(--radius-box); border-radius: var(--radius-box);
} }