8873ffe9d3
Summenzeile (VerbrauchCharts) und Balken-Einfaerbung (BarChart) greifen die Werte jetzt per Index mit Array.isArray-Guard ab, statt Elemente per [x,y] zu destrukturieren. Damit kann "(destructured parameter) is not iterable" auch bei unerwarteten Datenelementen nicht mehr auftreten. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
113 lines
2.9 KiB
TypeScript
113 lines
2.9 KiB
TypeScript
'use client';
|
|
|
|
import Highcharts from 'highcharts';
|
|
import HighchartsReact from 'highcharts-react-official';
|
|
import type { Options } from 'highcharts';
|
|
import { VerbrauchPoint, Every } from '@/types/strom';
|
|
|
|
interface BarChartProps {
|
|
title: string;
|
|
data: VerbrauchPoint[];
|
|
every: Every;
|
|
color: string;
|
|
// Optionale feste Achsengrenzen (z.B. komplettes Jahr -> immer 12 Monate sichtbar)
|
|
xMin?: number;
|
|
xMax?: number;
|
|
// Hervorzuhebende Balken (Zeitstempel-Set, z.B. E-Auto-Ladetage) + Farbe
|
|
highlight?: Set<number>;
|
|
highlightColor?: string;
|
|
}
|
|
|
|
const HOUR_MS = 60 * 60 * 1000;
|
|
const DAY_MS = 24 * HOUR_MS;
|
|
|
|
export default function BarChart({
|
|
title,
|
|
data,
|
|
every,
|
|
color,
|
|
xMin,
|
|
xMax,
|
|
highlight,
|
|
highlightColor = '#c0392b',
|
|
}: BarChartProps) {
|
|
const isHourly = every === '1h';
|
|
const isMonthly = every === '1mo';
|
|
const tooltipDateFormat = isHourly ? '%d.%m.%Y %H:%M' : isMonthly ? '%B %Y' : '%d.%m.%Y';
|
|
// Spaltenbreite: Stunde/Tag fix; Monat ~30 Tage breit
|
|
const pointRange = isHourly ? HOUR_MS : isMonthly ? 30 * DAY_MS : DAY_MS;
|
|
|
|
const options: Options = {
|
|
// Achse in lokaler Zeit rendern, damit Berliner Tages-/Monatsgrenzen
|
|
// (z.B. 01.01. 00:00 = 31.12. 23:00 UTC) korrekt beschriftet werden.
|
|
time: { timezone: 'Europe/Berlin' },
|
|
chart: {
|
|
type: 'column',
|
|
backgroundColor: '#F4F4F5',
|
|
style: { fontFamily: 'Arial, Helvetica, sans-serif' },
|
|
height: 300,
|
|
width: null,
|
|
zooming: { type: 'x' },
|
|
},
|
|
title: { text: title, style: { fontWeight: 'bold', fontSize: '15px' } },
|
|
xAxis: {
|
|
type: 'datetime',
|
|
min: xMin,
|
|
max: xMax,
|
|
dateTimeLabelFormats: {
|
|
hour: '%H:%M',
|
|
day: '%d.%m.',
|
|
week: '%d.%m.',
|
|
month: '%m.%Y',
|
|
},
|
|
title: { text: null },
|
|
labels: { style: { fontSize: '11px' } },
|
|
},
|
|
yAxis: {
|
|
title: { text: 'kWh' },
|
|
min: 0,
|
|
gridLineColor: '#ddd',
|
|
},
|
|
tooltip: {
|
|
xDateFormat: tooltipDateFormat,
|
|
pointFormat: '<b>{point.y:.3f} kWh</b>',
|
|
valueDecimals: 3,
|
|
},
|
|
credits: { enabled: false },
|
|
legend: { enabled: false },
|
|
plotOptions: {
|
|
column: {
|
|
borderRadius: 0,
|
|
groupPadding: 0.12,
|
|
pointPadding: 0.05,
|
|
maxPointWidth: 26,
|
|
pointRange,
|
|
},
|
|
},
|
|
series: [
|
|
{
|
|
type: 'column',
|
|
name: 'Verbrauch',
|
|
// markierte Balken (z.B. Ladetage) bekommen eine eigene Farbe
|
|
data:
|
|
highlight && highlight.size
|
|
? data.map((p) => {
|
|
const x = Array.isArray(p) ? p[0] : 0;
|
|
const y = Array.isArray(p) ? p[1] : 0;
|
|
return highlight.has(x) ? { x, y, color: highlightColor } : { x, y };
|
|
})
|
|
: data,
|
|
color,
|
|
},
|
|
],
|
|
};
|
|
|
|
return (
|
|
<HighchartsReact
|
|
highcharts={Highcharts}
|
|
options={options}
|
|
containerProps={{ style: { display: 'block', width: '100%' } }}
|
|
/>
|
|
);
|
|
}
|