import { useRef, useState } from "react"; import { tokenFarbe } from "../palette"; import useGroesse from "./useGroesse"; // Liniendiagramm über die Zeit. // labels: ["01.07.", …] serien: [{ name, color, werte: number[] }] // fmt: Werteformatierer. export default function Line({ labels = [], serien = [], fmt = (v) => String(v), achsenFmt }) { const yFmt = achsenFmt || fmt; // Achsen-Ticks dürfen schmaler sein (ohne Währungssymbol) const wirt = useRef(null); const plot = useRef(null); const { breite, hoehe } = useGroesse(plot); const [index, setIndex] = useState(null); const legende = serien.length > 1; const hatWerte = serien.some((s) => s.werte?.length); if (labels.length <= 1 || !hatWerte) { return
Keine Daten vorhanden.
; } const rand = { oben: 12, rechts: 12, unten: 24, links: 58 }; const w = Math.max(breite, 240); const h = Math.max(hoehe, 120); const flaecheB = Math.max(w - rand.links - rand.rechts, 10); const flaecheH = Math.max(h - rand.oben - rand.unten, 10); const alleWerte = serien.flatMap((s) => s.werte); const maxWert = Math.max(...alleWerte, 1); const minWert = Math.min(...alleWerte, 0); const spanne = Math.max(maxWert - minWert, 1); const skalaMax = maxWert + spanne * 0.1; const skalaMin = minWert - spanne * 0.05; const skalaSpanne = Math.max(skalaMax - skalaMin, 1); const x = (i) => rand.links + (i / (labels.length - 1)) * flaecheB; const y = (wert) => rand.oben + flaecheH - ((wert - skalaMin) / skalaSpanne) * flaecheH; const gitter = [0, 0.5, 1].map((teil) => { const wert = skalaMin + skalaSpanne * teil; return { wert, y: y(wert) }; }); const schritt = Math.max(1, Math.round(labels.length / 5)); const achse = labels.map((l, i) => ({ l, i })).filter(({ i }) => i % schritt === 0); const gitterFarbe = tokenFarbe("--border", "#ddd"); const textFarbe = tokenFarbe("--muted", "#888"); function bewegen(event) { const box = event.currentTarget.getBoundingClientRect(); const rel = event.clientX - box.left - rand.links; const i = Math.round((rel / flaecheB) * (labels.length - 1)); setIndex(Math.min(Math.max(i, 0), labels.length - 1)); } return (
{legende && ( )}
setIndex(null)}> {gitter.map((g) => ( {yFmt(g.wert)} ))} {achse.map(({ l, i }) => ( {l} ))} {serien.map((s) => ( `${i === 0 ? "M" : "L"} ${x(i)} ${y(wert)}`).join(" ")} /> ))} {index != null && ( <> {serien.map((s) => ( ))} )} {index != null && (
{labels[index]}
{serien.map((s) => (
{serien.length > 1 && {s.name}} {fmt(s.werte[index] ?? 0)}
))}
)}
); }