diff --git a/features/dashboard/components/charts/Donut.tsx b/features/dashboard/components/charts/Donut.tsx index 1ccff83..a65a40a 100644 --- a/features/dashboard/components/charts/Donut.tsx +++ b/features/dashboard/components/charts/Donut.tsx @@ -1,8 +1,7 @@ "use client"; import React from "react"; -import { Cell, Pie, PieChart, ResponsiveContainer, Tooltip } from "recharts"; -import { ChartTooltip } from "./ChartTooltip"; +import { Cell, Pie, PieChart, ResponsiveContainer } from "recharts"; import { ChartLeer } from "./ChartLeer"; import { DONUT, farbeFuer, gruppiereRest } from "../../utils/chartTheme"; @@ -19,6 +18,15 @@ import { DONUT, farbeFuer, gruppiereRest } from "../../utils/chartTheme"; * eine Container-Query, weil dieselbe Karte mal ein Drittel und mal die halbe * Seitenbreite einnimmt, der Viewport weiß davon nichts. * - Klick auf einen Legendeneintrag hebt das Segment hervor + * + * **Kein Tooltip.** Der Ring beantwortet das Überfahren in seiner eigenen + * Mitte: Statt Gesamtwert steht dort das berührte Segment mit Wert und Anteil. + * + * Ein schwebender Tooltip war hier zweimal falsch. Er legte sich über die + * Mitte und machte beide Angaben unlesbar, weil ein Ring von 168 px keinen + * Platz daneben hat. Und er wiederholte nur, was die Legende daneben schon + * zeigt. Die Mitte ist im Ruhezustand ohnehin belegt und die einzige Fläche, + * die groß genug ist. */ export function Donut({ daten, @@ -47,6 +55,8 @@ export function Donut({ if (!segmente.length) return ; const gesamt = segmente.reduce((summe, s) => summe + s.value, 0); + const anteilVon = (wert: number) => (gesamt > 0 ? (wert / gesamt) * 100 : 0).toFixed(0); + const hervorgehoben = segmente.find((s) => s.name === aktiv) ?? null; return (
@@ -66,32 +76,61 @@ export function Donut({ stroke="#ffffff" strokeWidth={2} isAnimationActive={false} + onMouseEnter={(eintrag: { name?: string }) => setAktiv(eintrag?.name ?? null)} + onMouseLeave={() => setAktiv(null)} > {segmente.map((segment, index) => ( ))} - } /> -
- - {mitteLabel} + {/* Die Textbreite muss am Ringdurchmesser hängen, nicht am Container. + Der Ring ist so groß wie die **kleinere** der beiden Seiten, und die + Karte kann sehr viel breiter als hoch sein. Deshalb begrenzt + `min()` beides: 56 % der Breite und 56 % der bekannten Höhe. + + Warum 48 % und nicht 62 % wie der Innenradius: Nachgemessen ist der + Innenkreis bei 200 px Ringhöhe 124 px breit, „KLIMA & LÜFTUNG" in + einer Zeile 109 px. Das passt rechnerisch und sieht trotzdem + gedrängt aus, weil der Innenkreis ein Kreis ist und die + Beschriftung über der Mittellinie steht, wo er schmaler wird. Bei + 48 % bricht der Name auf zwei Zeilen um und bekommt Luft. */} +
+ + {hervorgehoben ? hervorgehoben.name : mitteLabel} - {(formatMitte ?? formatWert)(gesamt)} + {hervorgehoben + ? formatWert(hervorgehoben.value) + : (formatMitte ?? formatWert)(gesamt)} + {hervorgehoben ? ( + + {anteilVon(hervorgehoben.value)} % + + ) : null}
    {segmente.map((segment, index) => { - const anteil = gesamt > 0 ? (segment.value / gesamt) * 100 : 0; + const anteil = anteilVon(segment.value); return (