// Hand-drawn SVG helpers. Output is built from numbers only, so it is safe as innerHTML.
// Bigger chart for the end-of-term review: weekly samples over the whole term,
// a gridline per year and per quarter of the value range.
export function lineChart(values, { w = 260, h = 96, min = 0, max = 100, yearEvery = 52 } = {}) {
const pad = 3;
const n = values.length;
const span = max - min || 1;
const x = (i) => pad + (n > 1 ? (i / (n - 1)) * (w - 2 * pad) : 0);
const y = (v) => h - pad - Math.min(1, Math.max(0, (v - min) / span)) * (h - 2 * pad);
const grid = [];
for (let i = yearEvery; i < n; i += yearEvery) grid.push(``);
for (const f of [0.25, 0.5, 0.75]) grid.push(``);
const pts = values.map((v, i) => `${x(i).toFixed(1)},${y(v).toFixed(1)}`).join(" ");
return ``;
}
// Small line chart on graph paper. `values` are plotted evenly left to right.
export function sparkline(values, { w = 84, h = 24, min = 0, max = 100 } = {}) {
const grid = [];
for (let x = 12; x < w; x += 12) grid.push(``);
for (const f of [0.25, 0.5, 0.75]) grid.push(``);
let line = "";
const n = values.length;
if (n > 1) {
const span = max - min || 1;
const pts = values.map((v, i) => {
const x = 2 + (i / (n - 1)) * (w - 4);
const y = h - 2 - Math.min(1, Math.max(0, (v - min) / span)) * (h - 4);
return [x.toFixed(1), y.toFixed(1)];
});
const last = pts[n - 1];
line =
`` +
``;
}
return ``;
}