Files
CPLv4.0/components/main/kabelueberwachung/kue705FO/Charts/TDRChart/TDRChart.tsx
ISA 6b6b6cc9b8 feat: Referenzkurve-Button sendet API-Aufruf an Backend (KTR)
- handleSetReference um fetch-Aufruf ergänzt
- Unterscheidung von Entwicklungs- und Produktionsumgebung via NEXT_PUBLIC_API_BASE_URL
- Fehlerbehandlung und Alert bei Erfolg/Misserfolg eingebaut
2025-03-31 10:05:36 +02:00

226 lines
7.4 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: false, // Wenn du die Fehlerstelle sichtbar sehen möchtest
parsing: {
xAxisKey: "d",
yAxisKey: "p",
},
order: 9999,
// 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),
JSON.stringify(referenceChartData),
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;