"use client"; // /components/main/kabelueberwachung/kue705FO/Charts/LoopMeasurementChart/LoopMeasurementChart.tsx import React, { useEffect, useRef } from "react"; import { useSelector } from "react-redux"; import { RootState } from "@/redux/store"; import { Chart as ChartJS, LineElement, PointElement, LinearScale, TimeScale, Title, Tooltip, Legend, Filler, } from "chart.js"; import "chartjs-adapter-date-fns"; import { de } from "date-fns/locale"; import { differenceInHours, parseISO } from "date-fns"; ChartJS.register( LineElement, PointElement, LinearScale, TimeScale, Title, Tooltip, Legend, Filler ); import { getColor } from "../../../../../../utils/colors"; import { PulseLoader } from "react-spinners"; type LoopMeasurementEntry = { t: string; i: number; m: number; g: number; a: number; }; const usePreviousData = (data: LoopMeasurementEntry[]) => { const ref = useRef([]); useEffect(() => { ref.current = data; }, [data]); return ref.current; }; const LoopMeasurementChart = () => { const canvasRef = useRef(null); const chartInstance = useRef(null); const { loopMeasurementCurveChartData, selectedMode, unit, isFullScreen, isLoading, vonDatum, bisDatum, } = useSelector((state: RootState) => state.kabelueberwachungChartSlice); const previousData = usePreviousData(loopMeasurementCurveChartData); // Vergleichsfunktion const isEqual = ( a: LoopMeasurementEntry[], b: LoopMeasurementEntry[] ): boolean => { if (a.length !== b.length) return false; for (let i = 0; i < a.length; i++) { if ( a[i].t !== b[i].t || a[i].i !== b[i].i || a[i].m !== b[i].m || a[i].g !== b[i].g || a[i].a !== b[i].a ) { return false; } } return true; }; // ⏱ Zeitspanne in Stunden berechnen const from = vonDatum ? parseISO(vonDatum) : null; const to = bisDatum ? parseISO(bisDatum) : null; const durationInHours = from && to ? differenceInHours(to, from) : 9999; const timeUnit: "hour" | "day" = durationInHours <= 48 ? "hour" : "day"; useEffect(() => { import("chartjs-plugin-zoom").then((zoomPlugin) => { if (!ChartJS.registry.plugins.get("zoom")) { ChartJS.register(zoomPlugin.default); } if (!canvasRef.current) return; const ctx = canvasRef.current.getContext("2d"); if (!ctx) return; if (isEqual(loopMeasurementCurveChartData, previousData)) { return; // keine echte Datenänderung → nicht neu zeichnen } if (chartInstance.current) { chartInstance.current.destroy(); } const chartData = { labels: loopMeasurementCurveChartData .map((entry) => new Date(entry.t)) .reverse(), datasets: [ { label: "Messwert Minimum", data: loopMeasurementCurveChartData.map((e) => e.i).reverse(), borderColor: "lightgrey", backgroundColor: "rgba(211,211,211,0.5)", borderWidth: 2, pointRadius: 0, pointHoverRadius: 10, tension: 0.1, order: 1, }, { label: "Messwert Maximum", data: loopMeasurementCurveChartData.map((e) => e.a).reverse(), borderColor: "lightgrey", backgroundColor: "rgba(211,211,211,0.5)", borderWidth: 2, pointRadius: 0, pointHoverRadius: 10, tension: 0.1, order: 1, }, selectedMode === "DIA0" ? { label: "Messwert", data: loopMeasurementCurveChartData.map((e) => e.m).reverse(), borderColor: getColor("littwin-blue"), backgroundColor: "rgba(59,130,246,0.5)", borderWidth: 3, pointRadius: 0, pointHoverRadius: 10, tension: 0.1, order: 3, } : { label: "Messwert Durchschnitt", data: loopMeasurementCurveChartData.map((e) => e.g).reverse(), borderColor: getColor("littwin-blue"), backgroundColor: "rgba(59,130,246,0.5)", borderWidth: 3, pointRadius: 0, pointHoverRadius: 10, tension: 0.1, order: 3, }, ], }; const options = { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: "top" as const }, tooltip: { yAlign: "bottom" as const, mode: "index" as const, intersect: false, }, zoom: { pan: { enabled: true, mode: "x" as const }, zoom: { wheel: { enabled: true }, pinch: { enabled: true }, mode: "x" as const, }, }, }, scales: { x: { type: "time" as const, time: { unit: timeUnit, tooltipFormat: "dd.MM.yyyy HH:mm:ss", displayFormats: { hour: "HH:mm", day: "dd.MM.", }, locale: de, }, title: { display: true, text: "Zeit" }, }, y: { title: { display: true, text: unit }, ticks: { precision: 0 }, }, }, }; chartInstance.current = new ChartJS(ctx, { type: "line", data: chartData, options, }); }); // eslint-disable-next-line react-hooks/exhaustive-deps }, [loopMeasurementCurveChartData, selectedMode, vonDatum, bisDatum]); return (
{isLoading && (
)}
); }; export default LoopMeasurementChart;