Web: Kategorien-Anteile-Karte umschaltbar auf Detailansicht (keine Gruppe Andere)
Neue Karten-Konfig-Option Detailansicht: mitFarben(..., { alle:true }) faerbt
jede Kategorie einzeln (Festpalette vorne, danach erzeugte Farbtoene) statt den
Rest zu Andere zu buendeln. Umschaltbar ueber das Zahnrad der Karte.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -462,14 +462,16 @@ function KarteAblaufRing() {
|
||||
);
|
||||
}
|
||||
|
||||
function KarteKategorienRing() {
|
||||
function KarteKategorienRing({ props: karteProps }) {
|
||||
const { daten, fehler } = useDaten(() => api.dashboardByCategory());
|
||||
if (fehler) return <div className="alert error"><Icon name="alert" size={16} />{fehler}</div>;
|
||||
if (!daten) return <div className="empty">Lädt…</div>;
|
||||
|
||||
// Detailansicht: jede Kategorie einzeln statt der Bündelung zu „Andere“.
|
||||
const segmente = mitFarben(
|
||||
daten.map((k) => ({ name: k.name, value: k.article_units })),
|
||||
istDunkel(),
|
||||
{ alle: !!karteProps?.detail },
|
||||
);
|
||||
return <Donut segmente={segmente} gesamtLabel="Einheiten" />;
|
||||
}
|
||||
@@ -687,6 +689,7 @@ export const KARTEN = {
|
||||
titel: "Kategorien-Anteile", icon: "tag", vorschau: "ring",
|
||||
beschreibung: "Ring: welche Kategorie wie viel ausmacht",
|
||||
standard: { w: 4, h: 6 }, min: { w: 3, h: 5 },
|
||||
config: [{ key: "detail", type: "boolean", label: "Detailansicht (alle Kategorien einzeln, keine Gruppe „Andere“)" }],
|
||||
komponente: KarteKategorienRing,
|
||||
},
|
||||
"category-bars": {
|
||||
|
||||
@@ -58,13 +58,36 @@ export function andereFarbe(dunkel) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Bündelt eine sortierte Liste auf SERIES_MAX Einträge plus „Andere“ und
|
||||
* vergibt die Farben in fester Reihenfolge.
|
||||
* Erwartet Objekte mit { name, value }.
|
||||
* Zusätzliche Farben für die Detailansicht (mehr Kategorien als die geprüfte
|
||||
* Palette hat). Bewusst nur für den Detail-Fall: gleichmäßig verteilte Farbtöne
|
||||
* (Goldener Winkel) statt der farbfehlsicht-geprüften Festfarben.
|
||||
*/
|
||||
export function mitFarben(eintraege, dunkel) {
|
||||
function extraFarben(anzahl, dunkel) {
|
||||
const s = dunkel ? 62 : 66;
|
||||
const l = dunkel ? 58 : 46;
|
||||
return Array.from({ length: anzahl }, (_, j) => {
|
||||
const ton = Math.round((28 + j * 137.508) % 360);
|
||||
return `hsl(${ton}, ${s}%, ${l}%)`;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Vergibt Farben für eine sortierte Anteilsliste (Objekte mit { name, value }).
|
||||
*
|
||||
* Standard: höchstens SERIES_MAX Einträge in fester Reihenfolge, der Rest zu
|
||||
* „Andere“ gebündelt. Mit `alle` (Detailansicht) bekommt JEDE Kategorie eine
|
||||
* eigene Farbe (Festpalette vorne, danach erzeugte Töne) – ohne „Andere“.
|
||||
*/
|
||||
export function mitFarben(eintraege, dunkel, { alle = false } = {}) {
|
||||
const farben = kategorieFarben(dunkel);
|
||||
const sortiert = [...eintraege].sort((a, b) => b.value - a.value);
|
||||
if (alle) {
|
||||
const extra = extraFarben(Math.max(0, sortiert.length - farben.length), dunkel);
|
||||
return sortiert.map((e, i) => ({
|
||||
...e,
|
||||
color: i < farben.length ? farben[i] : extra[i - farben.length],
|
||||
}));
|
||||
}
|
||||
const vorne = sortiert.slice(0, SERIES_MAX).map((e, i) => ({ ...e, color: farben[i] }));
|
||||
const rest = sortiert.slice(SERIES_MAX);
|
||||
if (rest.length === 0) return vorne;
|
||||
|
||||
Reference in New Issue
Block a user