Files
CPLv4.0/components/main/kabelueberwachung/kue705FO/Charts/TDRChart/TDRChart.tsx
ISA 4e459a7f36 refactor: TDR-Daten in neuen tdrSingleChartSlice ausgelagert und nur pro Slot geladen
- Globalen fetchAllTDRChartData entfernt
- Neuen Slice und Thunk pro Slot erstellt
- TDRChart liest initiale Daten aus neuem Slice
2025-03-27 14:55:06 +01:00

208 lines
6.9 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// components/main/kabelueberwachung/kue705FO/Charts/TDRChart/TDRChart.tsx
"use client";
import React, { useEffect, useRef, useMemo } from "react";
import { RootState } from "../../../../../../redux/store";
import { useSelector, useDispatch } from "react-redux";
import { AppDispatch } from "../../../../../../redux/store";
import { Chart, registerables } from "chart.js";
import "chartjs-adapter-date-fns";
import { getColor } from "../../../../../../utils/colors";
import TDRChartActionBar from "./TDRChartActionBar";
import { fetchAllTDRReferenceChartThunk } from "../../../../../../redux/thunks/fetchAllTDRReferenceChartThunk";
const TDRChart: React.FC<{ isFullScreen: boolean }> = ({ isFullScreen }) => {
const dispatch = useDispatch<AppDispatch>();
//---------------------------------
const chartRef = useRef<HTMLCanvasElement>(null);
const chartInstance = useRef<Chart | null>(null);
// 🟢 **Hole den ausgewählten Slot und Messkurve aus Redux**
const selectedId = useSelector(
(state: RootState) => state.tdrDataById.selectedId
);
const selectedSlot = useSelector(
(state: RootState) => state.kueChartMode.selectedSlot
);
const selectedChartType = useSelector(
(state: RootState) => state.kueChartMode.activeMode
);
const tdrDataById = useSelector(
(state: RootState) => state.tdrDataById.dataById
);
//--------------------------------
const tdrDataBySlot = useSelector(
(state: RootState) => state.tdrSingleChart.data
);
const tdrInitialData =
selectedSlot !== null ? tdrDataBySlot[selectedSlot] ?? [] : [];
//--------------------------------
// Kombinierte Logik: ID hat Vorrang, sonst Initial-Daten für Slot
const tdrChartData = useMemo(() => {
if (selectedId !== null && tdrDataById[selectedId]) {
return tdrDataById[selectedId];
}
return tdrInitialData;
}, [selectedId, tdrDataById, tdrInitialData]);
const referenceChartData = useSelector((state: RootState) =>
selectedSlot !== null
? state.tdrReferenceChart.referenceData[selectedSlot] || []
: []
);
//--------------------------------
const tdmChartData = useSelector((state: RootState) => state.tdmChart.data);
const pinDistance =
Array.isArray(tdmChartData?.[selectedSlot ?? -1]) &&
tdmChartData[selectedSlot!]?.length > 0 &&
typeof tdmChartData[selectedSlot!][0].d === "number"
? tdmChartData[selectedSlot!][0].d
: null;
//--------------------------------
useEffect(() => {
import("chartjs-plugin-zoom").then((zoomPlugin) => {
Chart.register(...registerables, zoomPlugin.default);
if (chartRef.current && tdrChartData.length > 0) {
if (chartInstance.current) {
chartInstance.current.destroy();
}
const ctx = chartRef.current.getContext("2d");
if (ctx) {
chartInstance.current = new Chart(ctx, {
type: "line",
data: {
datasets: [
{
label: `Modul ${
selectedSlot !== null ? selectedSlot + 1 : "?"
}`,
data: tdrChartData,
borderColor: getColor("littwin-blue"),
borderWidth: 1,
tension: 0.1,
parsing: {
xAxisKey: "d",
yAxisKey: "p",
},
},
{
label: "Referenzkurve",
data: referenceChartData,
borderColor: "black",
borderWidth: 1,
borderDash: [5, 5],
pointRadius: 3,
pointHoverRadius: 5,
pointBackgroundColor: "black",
tension: 0.1,
parsing: {
xAxisKey: "d",
yAxisKey: "p",
},
},
{
label: "Fehlerstelle",
data: pinDistance !== null ? [{ d: pinDistance, p: 0 }] : [],
borderColor: "red",
backgroundColor: "red",
pointRadius: 5,
pointStyle: "circle",
showLine: false,
parsing: {
xAxisKey: "d",
yAxisKey: "p",
},
},
],
},
options: {
responsive: true,
maintainAspectRatio: false,
animation: {
duration: 150, // 150 ms Animation
},
scales: {
x: {
type: "linear",
title: {
display: true,
text: "Entfernung (m)",
},
},
y: {
title: {
display: true,
text: "Pegel",
},
},
},
plugins: {
tooltip: {
yAlign: "bottom", // Tooltip oberhalb des Punktes
callbacks: {
title: () => "Fehlerstelle", // Kein Titel
label: function (context) {
const rawData = context.raw as { d: number; p: number };
// 👇 Unterscheide zwischen Mess- und Referenzkurve
if (context.dataset.label === "Referenzkurve") {
return [
`Referenzwert`,
`Entfernung: ${rawData.d.toFixed(0)} Meter`,
`Pegel: ${rawData.p.toFixed(2)}`,
];
} else {
return [
`Messwert`,
`Entfernung: ${rawData.d.toFixed(0)} Meter`,
`Pegel: ${rawData.p.toFixed(2)}`,
];
}
},
},
},
zoom: {
pan: {
enabled: true,
mode: "xy",
},
zoom: {
wheel: {
enabled: true,
},
pinch: {
enabled: true,
},
mode: "xy",
},
},
},
},
});
}
}
});
}, [JSON.stringify(tdrChartData), selectedSlot, selectedChartType]);
return (
<div style={{ width: "100%", height: isFullScreen ? "90%" : "28rem" }}>
<TDRChartActionBar />
{tdrChartData.length === 0 ? (
<div className="flex items-center justify-center h-full text-gray-500 italic">
Keine Daten verfügbar für diesen Slot
</div>
) : (
<canvas ref={chartRef} style={{ width: "100%", height: "100%" }} />
)}
</div>
);
};
export default TDRChart;