From f5a3ccd634abdd356fe18649c635e5f1b997208f Mon Sep 17 00:00:00 2001 From: DeeCee03 Date: Mon, 31 Aug 2026 22:58:20 +0200 Subject: [PATCH] Ring beantwortet das Ueberfahren in seiner Mitte statt im Tooltip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Der Tooltip legte sich ueber die Ringmitte: "Klima & Lueftung 268,0 T€" und "GESAMT 2,27 Mio. €" uebereinander, beides unlesbar. Ein Ring von 168 px hat keinen Platz fuer ein schwebendes Feld daneben, egal wohin man es schiebt. Der Tooltip faellt deshalb ganz weg. Beim Ueberfahren zeigt die Mitte das beruehrte Segment mit Name, Wert und Anteil, im Ruhezustand weiter den Gesamtwert. Die Flaeche ist ohnehin belegt und die einzige, die gross genug ist; ausserdem wiederholte der Tooltip nur, was die Legende daneben schon zeigt. Das ist auch die Carbon-Loesung. Damit das Ueberfahren des Rings selbst wirkt (bisher setzte nur die Legende den Zustand), liegen die Handler jetzt auch am Pie. Zur Breite der Beschriftung: erst am Container bemessen, dann an der Hoehe, beides falsch. Der Ring ist so gross wie die **kleinere** der beiden Seiten. Jetzt begrenzt min() beide. Der Wert ist nachgemessen statt geschaetzt: Bei 200 px Ringhoehe ist der Innenkreis 124 px breit und "KLIMA & LÜFTUNG" in einer Zeile 109 px. Das passt rechnerisch und sieht trotzdem gedraengt aus, weil der Innenkreis ein Kreis ist und die Beschriftung ueber der Mittellinie steht, wo er schmaler wird. Bei 48 % bricht der Name auf zwei Zeilen um und bekommt Luft. Das Abblenden der uebrigen Segmente bleibt. Im Trichter war dasselbe Mittel falsch, hier ist es richtig, und der Unterschied steht als Kommentar dabei: Dort kodiert die Balkenlaenge eine Menge, und Deckkraft liest sich als "weniger". Hier kodiert die Farbe nur eine Kategorie. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01QPeZNwSeU7qG3RRCwaxEZX --- .../dashboard/components/charts/Donut.tsx | 57 ++++++++++++++++--- 1 file changed, 48 insertions(+), 9 deletions(-) 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 (