Files
CPLv4.0/components/main/kabelueberwachung/kue705FO/Charts/TDRChart/TDRChart.tsx
Ismail Ali cb2deecf17 feat: Referenzkurve pro Slot dynamisch per Redux Slice laden und anzeigen
- Neuen Slice `tdrReferenceChartDataBySlot` eingeführt
- Thunk `fetchReferenceCurveBySlotThunk` erstellt
- Referenzdaten pro Slot in Redux gespeichert
- Zugriff im TDRChart angepasst auf neue Struktur
2025-03-30 13:32:32 +02:00

220 lines
7.3 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 { fetchReferenceCurveBySlotThunk } from "../../../../../../redux/thunks/fetchReferenceCurveBySlotThunk";
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 tdrInitialData =
selectedId !== null && tdrDataById[selectedId]
? tdrDataById[selectedId]
: [];
//--------------------------------
// Kombinierte Logik: ID hat Vorrang, sonst Initial-Daten für Slot
const tdrChartData =
selectedId !== null && tdrDataById[selectedId]
? tdrDataById[selectedId]
: [];
//--------------------------------
const referenceChartData = useSelector((state: RootState) =>
selectedSlot !== null
? state.tdrReferenceChartDataBySlot.referenceData[selectedSlot] || []
: []
);
//--------------------------------
useEffect(() => {
if (selectedSlot !== null) {
dispatch(fetchReferenceCurveBySlotThunk(selectedSlot));
}
}, [selectedSlot, dispatch]);
//--------------------------------
const tdmChartData = useSelector(
(state: RootState) => state.tdmSingleChart.data
);
const pinDistance =
selectedId !== null && Array.isArray(tdmChartData?.[selectedSlot ?? -1])
? tdmChartData[selectedSlot!].find((entry) => entry.id === selectedId)
?.d ?? null
: 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 && typeof pinDistance === "number"
? [{ d: pinDistance, p: 0 }]
: [],
borderColor: "red",
backgroundColor: "red",
pointRadius: 10,
pointStyle: "triangle", // Hier den korrekten Stil setzen
showLine: false,
clip: true, // Wenn du die Fehlerstelle sichtbar sehen möchtest
parsing: {
xAxisKey: "d",
yAxisKey: "p",
},
order: 9999,
z: 10, // Hier die Reihenfolge der Marker bestimmen
},
],
},
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;