bugfix dashboard
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { useState } from "react";
|
||||
import { useApp } from "../context/AppContext.jsx";
|
||||
import { fmt, fmtDatum } from "../utils/format.js";
|
||||
import { fmt, fmtDatum, fmtMaand } from "../utils/format.js";
|
||||
import { crPath, vlakPad } from "../utils/grafiek.js";
|
||||
import { useKolomBreedtes } from "../hooks/useKolomBreedtes.js";
|
||||
import { RED, GREEN } from "../constants/index.js";
|
||||
import { VCard, DonutChart, Overlay, ModalBox, ModalHeader, ModalFooter } from "../components/ui/index.jsx";
|
||||
@@ -16,8 +17,11 @@ function SvgLineChart({ pts, lines, T, H = 200 }) {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
const W = 700, pl = 64, pr = 16, pt2 = 16, pb = 62;
|
||||
// pb was 62 voor gedraaide datumlabels. Die staan nu rechtop en zijn korter.
|
||||
const W = 700, pl = 64, pr = 16, pt2 = 16, pb = 34;
|
||||
const iW = W - pl - pr, iH = H - pt2 - pb;
|
||||
// Eén label "sep '26" is ongeveer 46px breed; zoveel passen er naast elkaar.
|
||||
const labelStap = Math.max(1, Math.ceil(pts.length / Math.max(1, Math.floor(iW / 46))));
|
||||
const allVals = lines.flatMap((l) => pts.map((p) => p[l.key] ?? 0));
|
||||
const dataMin = Math.min(...allVals);
|
||||
const dataMax = Math.max(...allVals);
|
||||
@@ -60,17 +64,21 @@ function SvgLineChart({ pts, lines, T, H = 200 }) {
|
||||
if (validPts.length < 2) return null;
|
||||
const xs = validPts.map((p) => xp(p._i));
|
||||
const ys = validPts.map((p) => yp(p[l.key]));
|
||||
const ls = xs.map((x, i) => `${x},${ys[i]}`).join(" ");
|
||||
const ar = `${xs[0]},${pt2 + iH} ${ls} ${xs[xs.length - 1]},${pt2 + iH}`;
|
||||
// Dezelfde Catmull-Rom afronding als de dashboardgrafiek, in plaats
|
||||
// van rechte segmenten tussen de punten.
|
||||
const lijn = crPath(xs, ys);
|
||||
const vlak = vlakPad(lijn, xs[0], xs[xs.length - 1], pt2 + iH);
|
||||
return (
|
||||
<g key={l.key}>
|
||||
<polygon points={ar} fill={`url(#g_${l.key})`} />
|
||||
<polyline points={ls} fill="none" stroke={l.color} strokeWidth="2.5"
|
||||
<path d={vlak} fill={`url(#g_${l.key})`} />
|
||||
<path d={lijn} fill="none" stroke={l.color} strokeWidth="2.5"
|
||||
strokeLinejoin="round" strokeLinecap="round" />
|
||||
{validPts.map((p, i) => {
|
||||
const x = xs[i], y = ys[i];
|
||||
const isHov = hovered?.lineKey === l.key && hovered?.ptIdx === i;
|
||||
const tipW = 90, tipH = 22;
|
||||
// Twee regels: sinds de x-as alleen nog maanden noemt, is dit
|
||||
// de enige plek in de grafiek waar de exacte dag te lezen is.
|
||||
const tipW = 104, tipH = 34;
|
||||
const tipX = Math.min(Math.max(x - tipW / 2, pl), W - tipW - 4);
|
||||
const tipY = y - tipH - 8 < pt2 ? y + 10 : y - tipH - 8;
|
||||
return (
|
||||
@@ -84,10 +92,14 @@ function SvgLineChart({ pts, lines, T, H = 200 }) {
|
||||
fill={l.color} stroke={T.card} strokeWidth="2" />
|
||||
{isHov && (
|
||||
<g>
|
||||
<rect x={tipX} y={tipY} width={tipW} height={22}
|
||||
<rect x={tipX} y={tipY} width={tipW} height={tipH}
|
||||
rx="5" fill={T.card}
|
||||
stroke={l.color} strokeWidth="1" />
|
||||
<text x={tipX + tipW / 2} y={tipY + 15} fill={l.color} fontSize="8"
|
||||
<text x={tipX + tipW / 2} y={tipY + 13} fill={T.muted} fontSize="8"
|
||||
textAnchor="middle">
|
||||
{fmtDatum(p.datum)}
|
||||
</text>
|
||||
<text x={tipX + tipW / 2} y={tipY + 26} fill={l.color} fontSize="9"
|
||||
fontWeight="700" textAnchor="middle">
|
||||
{fmt(p[l.key])}
|
||||
</text>
|
||||
@@ -99,15 +111,23 @@ function SvgLineChart({ pts, lines, T, H = 200 }) {
|
||||
</g>
|
||||
);
|
||||
})}
|
||||
{pts.map((p, i) => (
|
||||
<text key={i}
|
||||
x={xp(i)} y={H - pb + 16}
|
||||
fill={T.muted} fontSize="8"
|
||||
textAnchor="end"
|
||||
transform={`rotate(-45, ${xp(i)}, ${H - pb + 16})`}>
|
||||
{fmtDatum(p.datum)}
|
||||
</text>
|
||||
))}
|
||||
{/* X-as: korte maandlabels, rechtop en uitgedund op wat er past. Elk
|
||||
punt een volledige datum geven liep bij een lange reeks over in een
|
||||
onleesbare band. De exacte dag staat in de tooltip op elk punt. */}
|
||||
{pts.map((p, i) => {
|
||||
const laatste = i === pts.length - 1;
|
||||
if (i % labelStap !== 0 && !laatste) return null;
|
||||
return (
|
||||
<g key={i}>
|
||||
<line x1={xp(i)} y1={pt2 + iH} x2={xp(i)} y2={pt2 + iH + 4}
|
||||
stroke={T.muted} strokeOpacity="0.5" strokeWidth="1" />
|
||||
<text x={xp(i)} y={pt2 + iH + 17} fill={T.muted} fontSize="9"
|
||||
textAnchor={i === 0 ? "start" : laatste ? "end" : "middle"}>
|
||||
{fmtMaand(p.datum)}
|
||||
</text>
|
||||
</g>
|
||||
);
|
||||
})}
|
||||
</svg>
|
||||
<div style={{ display: "flex", gap: 20, justifyContent: "center", marginTop: 10 }}>
|
||||
{lines.map((l) => (
|
||||
|
||||
Reference in New Issue
Block a user