95 lines
2.7 KiB
React
95 lines
2.7 KiB
React
import { useEffect, useRef, useState } from "react";
|
|
import {
|
|
CartesianGrid,
|
|
Legend,
|
|
Line,
|
|
LineChart,
|
|
ResponsiveContainer,
|
|
Tooltip,
|
|
XAxis,
|
|
YAxis,
|
|
} from "recharts";
|
|
|
|
const COLORS = ["#2563eb", "#dc2626", "#1d4ed8", "#b91c1c", "#3b82f6", "#ef4444"];
|
|
|
|
export default function TrendChart({ result, title = "Trendansicht" }) {
|
|
const hostRef = useRef(null);
|
|
const [isFullscreen, setIsFullscreen] = useState(false);
|
|
|
|
useEffect(() => {
|
|
const onChange = () => {
|
|
setIsFullscreen(document.fullscreenElement === hostRef.current);
|
|
};
|
|
|
|
document.addEventListener("fullscreenchange", onChange);
|
|
return () => document.removeEventListener("fullscreenchange", onChange);
|
|
}, []);
|
|
|
|
if (!result?.rows?.length) {
|
|
return (
|
|
<div className="panel chart-panel empty-state">
|
|
<h3>{title}</h3>
|
|
<p>Keine Daten im gewaehlten Zeitraum.</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const rows = result.rows.map((row) => ({
|
|
...row,
|
|
timestampLabel: new Date(row.timestamp).toLocaleString("de-DE"),
|
|
}));
|
|
|
|
const toggleFullscreen = async () => {
|
|
if (!hostRef.current) {
|
|
return;
|
|
}
|
|
|
|
if (document.fullscreenElement === hostRef.current) {
|
|
await document.exitFullscreen();
|
|
return;
|
|
}
|
|
|
|
await hostRef.current.requestFullscreen();
|
|
};
|
|
|
|
return (
|
|
<div ref={hostRef} className="panel chart-panel">
|
|
<div className="panel-header">
|
|
<h3>{title}</h3>
|
|
<button className="ghost-button" type="button" onClick={toggleFullscreen}>
|
|
{isFullscreen ? "Zurueck" : "Vollbild"}
|
|
</button>
|
|
</div>
|
|
<div className="chart-wrapper">
|
|
<ResponsiveContainer width="100%" height={isFullscreen ? 520 : 320}>
|
|
<LineChart data={rows}>
|
|
<CartesianGrid strokeDasharray="3 3" stroke="var(--grid)" />
|
|
<XAxis dataKey="timestampLabel" minTickGap={30} stroke="var(--muted)" />
|
|
<YAxis stroke="var(--muted)" />
|
|
<Tooltip
|
|
contentStyle={{
|
|
background: "var(--surface-strong)",
|
|
border: "1px solid var(--border-strong)",
|
|
borderRadius: 10,
|
|
fontSize: 12,
|
|
}}
|
|
/>
|
|
<Legend />
|
|
{result.series.map((series, index) => (
|
|
<Line
|
|
key={series.key}
|
|
type="monotone"
|
|
dataKey={series.key}
|
|
dot={false}
|
|
strokeWidth={1.75}
|
|
stroke={COLORS[index % COLORS.length]}
|
|
name={series.displayName + " / " + series.alias + (series.unit ? " (" + series.unit + ")" : "")}
|
|
/>
|
|
))}
|
|
</LineChart>
|
|
</ResponsiveContainer>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|