Kurzmeldungen als Overlay, Liniendiagramm fuellt die Karte, Zeitraum ab 1 Tag
Meldungen: "Gespeichert", "Anordnung gespeichert" und die uebrigen Erfolgsmeldungen standen als Leiste mitten in der Seite - beim Speichern sprang dadurch das ganze Layout ein Stueck nach unten. Sie erscheinen jetzt als Overlay am unteren Rand und verschwinden nach fuenf Sekunden von selbst; ein Kreuz blendet sie sofort aus. Umgestellt in Uebersicht, Einstellungen, Gefahrenbereich, Benutzer, Produktformular sowie Ein- und Auslagern. Bewusst NICHT umgestellt: Fehlermeldungen. Ein Fehler, der nach fuenf Sekunden verschwindet, ist genau dann weg, wenn man ihn noch braucht - der bleibt an seiner Stelle stehen. Rollbalken beim Liniendiagramm: Den hatte ich mir mit der Zeitraum-Auswahl selbst eingebaut. Das Diagramm hatte eine feste Hoehe von 200 px; zusammen mit der Auswahl darueber passte das nicht mehr in die Karte. Jetzt wird auch die Hoehe gemessen, das Diagramm fuellt den verbleibenden Platz. Zeitraum "1 Tag": Ein einzelner Tag ergibt genau einen Messpunkt - eine Linie aus einem Punkt waere unsinnig. Das Diagramm zeigt in dem Fall die blanke Zahl. Die Backend-Begrenzung laesst jetzt einen Tag zu. Geprueft: "npm run build" laeuft durch; kein Verweis mehr auf die entfernten Meldungszustaende. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -2,19 +2,24 @@ import { useEffect, useRef, useState } from "react";
|
||||
import { fmt } from "../../units";
|
||||
import { tokenFarbe } from "../palette";
|
||||
|
||||
/** Misst die tatsächliche Breite, damit das SVG in echten Pixeln zeichnet.
|
||||
* Ein festes viewBox mit Skalierung würde Linienstärken verzerren. */
|
||||
function useBreite(ref) {
|
||||
const [breite, setBreite] = useState(0);
|
||||
/** Misst die tatsächliche Größe, damit das SVG in echten Pixeln zeichnet.
|
||||
* Ein festes viewBox mit Skalierung würde Linienstärken verzerren.
|
||||
* Auch die Höhe wird gemessen: Mit fester Höhe passte das Diagramm nicht mehr
|
||||
* in die Karte, sobald darüber noch eine Auswahl stand – es gab einen Rollbalken. */
|
||||
function useGroesse(ref) {
|
||||
const [groesse, setGroesse] = useState({ breite: 0, hoehe: 0 });
|
||||
useEffect(() => {
|
||||
if (!ref.current) return undefined;
|
||||
const beobachter = new ResizeObserver(([eintrag]) => {
|
||||
setBreite(eintrag.contentRect.width);
|
||||
setGroesse({
|
||||
breite: eintrag.contentRect.width,
|
||||
hoehe: eintrag.contentRect.height,
|
||||
});
|
||||
});
|
||||
beobachter.observe(ref.current);
|
||||
return () => beobachter.disconnect();
|
||||
}, [ref]);
|
||||
return breite;
|
||||
return groesse;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -27,19 +32,39 @@ function useBreite(ref) {
|
||||
* labels: ["01.07.", …] – gemeinsame X-Achse
|
||||
* serien: [{ name, color, werte: number[] }]
|
||||
*/
|
||||
export default function Line({ labels = [], serien = [], einheit = "", hoehe = 200 }) {
|
||||
export default function Line({ labels = [], serien = [], einheit = "" }) {
|
||||
const wirt = useRef(null);
|
||||
const breite = useBreite(wirt);
|
||||
const plot = useRef(null);
|
||||
const { breite, hoehe } = useGroesse(plot);
|
||||
const [index, setIndex] = useState(null);
|
||||
|
||||
const hatDaten = labels.length > 1 && serien.some((s) => s.werte?.length);
|
||||
if (!hatDaten) {
|
||||
const legende = serien.length > 1;
|
||||
const hatWerte = serien.some((s) => s.werte?.length);
|
||||
|
||||
// Ein einzelner Tag ergibt keine Linie – dann ist die blanke Zahl die
|
||||
// ehrlichere Darstellung als eine Linie aus einem Punkt.
|
||||
if (labels.length === 1 && hatWerte) {
|
||||
return (
|
||||
<div className="chart-line einzelwert" ref={wirt}>
|
||||
{serien.map((s) => (
|
||||
<div key={s.name} className="einzel-reihe">
|
||||
<span className="swatch" style={{ background: s.color }} />
|
||||
<span className="einzel-zahl">{fmt(s.werte[0] ?? 0)}</span>
|
||||
<span className="muted small">{einheit || s.name}</span>
|
||||
</div>
|
||||
))}
|
||||
<div className="muted small">{labels[0]}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (labels.length <= 1 || !hatWerte) {
|
||||
return <div className="chart-line" ref={wirt}><div className="empty">Keine Daten vorhanden.</div></div>;
|
||||
}
|
||||
|
||||
const rand = { oben: 12, rechts: 12, unten: 24, links: 44 };
|
||||
const w = Math.max(breite, 240);
|
||||
const h = hoehe;
|
||||
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);
|
||||
|
||||
@@ -72,7 +97,7 @@ export default function Line({ labels = [], serien = [], einheit = "", hoehe = 2
|
||||
|
||||
return (
|
||||
<div className="chart-line" ref={wirt}>
|
||||
{serien.length > 1 && (
|
||||
{legende && (
|
||||
<ul className="chart-legend inline">
|
||||
{serien.map((s) => (
|
||||
<li key={s.name}>
|
||||
@@ -83,7 +108,7 @@ export default function Line({ labels = [], serien = [], einheit = "", hoehe = 2
|
||||
</ul>
|
||||
)}
|
||||
|
||||
<div className="line-plot">
|
||||
<div className="line-plot" ref={plot}>
|
||||
<svg width={w} height={h} role="img"
|
||||
aria-label={`Liniendiagramm über ${labels.length} Tage`}
|
||||
onMouseMove={bewegen} onMouseLeave={() => setIndex(null)}>
|
||||
|
||||
Reference in New Issue
Block a user