refactor: Auslagerung der Chart-Erstellungsfunktionen in chartUtils.ts
- createLoopChart und createTDRChart aus Kue705FO.tsx in eine separate Datei chartUtils.ts verschoben - Verbesserte Code-Struktur und Wiederverwendbarkeit der Chart-Funktionen - Import der ausgelagerten Funktionen in Kue705FO.tsx angepasst
This commit is contained in:
@@ -27,7 +27,7 @@ const Navigation: React.FC<NavigationProps> = ({ className }) => {
|
|||||||
{ name: "Ein- und Ausgänge", path: "/einausgaenge" },
|
{ name: "Ein- und Ausgänge", path: "/einausgaenge" },
|
||||||
{ name: "Analoge Eingänge", path: "/analogeEingaenge" },
|
{ name: "Analoge Eingänge", path: "/analogeEingaenge" },
|
||||||
{ name: "Meldungen", path: "/messages" },
|
{ name: "Meldungen", path: "/messages" },
|
||||||
{ name: "Einstellung", path: "/settings" },
|
{ name: "Einstellungen", path: "/settings" },
|
||||||
// Weitere Menüpunkte hier
|
// Weitere Menüpunkte hier
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
setSelectedFileName,
|
setSelectedFileName,
|
||||||
} from "../../redux/slices/variablesSlice";
|
} from "../../redux/slices/variablesSlice";
|
||||||
import TDRPopup from "../modales/kueModal/TDRPopup";
|
import TDRPopup from "../modales/kueModal/TDRPopup";
|
||||||
|
import { createLoopChart, createTDRChart } from "../../utils/chartUtils";
|
||||||
|
|
||||||
const Kue705FO: React.FC<Kue705FOProps> = ({
|
const Kue705FO: React.FC<Kue705FOProps> = ({
|
||||||
isolationswert,
|
isolationswert,
|
||||||
@@ -192,97 +193,6 @@ const Kue705FO: React.FC<Kue705FOProps> = ({
|
|||||||
|
|
||||||
const chartInstance = useRef<Chart | null>(null);
|
const chartInstance = useRef<Chart | null>(null);
|
||||||
|
|
||||||
const createTDRChart = (dataTDR: DataTDR[]) => {
|
|
||||||
const canvas = document.getElementById("myChart") as HTMLCanvasElement;
|
|
||||||
|
|
||||||
if (!canvas) {
|
|
||||||
console.error("Canvas mit ID 'myChart' nicht gefunden.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ctx = canvas.getContext("2d");
|
|
||||||
if (!ctx) {
|
|
||||||
console.error("2D-Kontext für Canvas konnte nicht erstellt werden.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vorhandenes Chart zerstören, falls vorhanden
|
|
||||||
if (chartInstance.current) {
|
|
||||||
console.log("Vorhandenes Chart wird zerstört.");
|
|
||||||
chartInstance.current.destroy();
|
|
||||||
chartInstance.current = null; // Referenz zurücksetzen
|
|
||||||
}
|
|
||||||
|
|
||||||
// Maximal- und Minimalwerte berechnen
|
|
||||||
const minX = Math.min(...dataTDR.map((row) => row.t));
|
|
||||||
const maxX = Math.max(...dataTDR.map((row) => row.t));
|
|
||||||
const minY = Math.min(...dataTDR.map((row) => row.m));
|
|
||||||
const maxY = Math.max(...dataTDR.map((row) => row.m));
|
|
||||||
|
|
||||||
// Neues Chart erstellen
|
|
||||||
try {
|
|
||||||
chartInstance.current = new Chart(ctx, {
|
|
||||||
type: "line",
|
|
||||||
data: {
|
|
||||||
labels: dataTDR.map((row) => row.t),
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
label: "Pegel",
|
|
||||||
data: dataTDR.map((row) => row.m),
|
|
||||||
borderColor: "#00AEEF",
|
|
||||||
borderWidth: 2,
|
|
||||||
fill: false,
|
|
||||||
tension: 0.1, // Weiche Kurve
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
responsive: true,
|
|
||||||
maintainAspectRatio: false, // Ermöglicht flexible Größe
|
|
||||||
layout: {
|
|
||||||
padding: {
|
|
||||||
bottom: 25, // Fügt zusätzliches Padding unten hinzu
|
|
||||||
},
|
|
||||||
},
|
|
||||||
plugins: {
|
|
||||||
zoom: {
|
|
||||||
pan: {
|
|
||||||
enabled: true,
|
|
||||||
mode: "xy",
|
|
||||||
},
|
|
||||||
zoom: {
|
|
||||||
wheel: {
|
|
||||||
enabled: true,
|
|
||||||
},
|
|
||||||
pinch: {
|
|
||||||
enabled: true,
|
|
||||||
},
|
|
||||||
mode: "xy",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
scales: {
|
|
||||||
x: {
|
|
||||||
type: "linear",
|
|
||||||
position: "bottom",
|
|
||||||
title: { display: true, text: "Entfernung" },
|
|
||||||
min: minX - 5, // Etwas Puffer hinzufügen
|
|
||||||
max: maxX + 5,
|
|
||||||
},
|
|
||||||
y: {
|
|
||||||
title: { display: true, text: "Pegel" },
|
|
||||||
min: minY - 10, // Puffer für Y-Werte
|
|
||||||
max: maxY + 10,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
console.log("Neues Chart erfolgreich erstellt.");
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Fehler beim Erstellen des Charts:", error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const selectedFileName = useSelector(
|
const selectedFileName = useSelector(
|
||||||
(state: RootState) => state.variables.selectedFileName
|
(state: RootState) => state.variables.selectedFileName
|
||||||
);
|
);
|
||||||
@@ -347,96 +257,6 @@ const Kue705FO: React.FC<Kue705FOProps> = ({
|
|||||||
n: number; // Schleifenwiderstand
|
n: number; // Schleifenwiderstand
|
||||||
}
|
}
|
||||||
|
|
||||||
const createLoopChart = (data: DataLoop[], title: string) => {
|
|
||||||
const canvas = document.getElementById("myChart") as HTMLCanvasElement;
|
|
||||||
if (!canvas) {
|
|
||||||
console.error("Canvas mit ID 'myChart' nicht gefunden.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ctx = canvas.getContext("2d");
|
|
||||||
if (!ctx) {
|
|
||||||
console.error("2D-Kontext für Canvas konnte nicht erstellt werden.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Konvertiere Zeitstempel in ein lesbares Format für die X-Achse
|
|
||||||
const labels = data.map((row) => {
|
|
||||||
const date = new Date(String(row.t).replace(/-/g, "/")); // Zeitstring parsen
|
|
||||||
return date.toLocaleString("de-DE", {
|
|
||||||
hour: "2-digit",
|
|
||||||
minute: "2-digit",
|
|
||||||
second: "2-digit",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
new Chart(ctx, {
|
|
||||||
type: "line",
|
|
||||||
data: {
|
|
||||||
labels,
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
label: "Isolationswiderstand (MOhm)",
|
|
||||||
data: data.map((row) => row.m),
|
|
||||||
borderColor: "#00AEEF",
|
|
||||||
borderWidth: 1,
|
|
||||||
tension: 0.1, // Glättung der Linie
|
|
||||||
pointRadius: 1,
|
|
||||||
pointHoverRadius: 5,
|
|
||||||
fill: false,
|
|
||||||
yAxisID: "y",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Schleifenwiderstand (kOhm)",
|
|
||||||
data: data.map((row) => row.n),
|
|
||||||
borderColor: "black",
|
|
||||||
borderWidth: 1,
|
|
||||||
tension: 0.1,
|
|
||||||
pointRadius: 1,
|
|
||||||
pointHoverRadius: 5,
|
|
||||||
fill: false,
|
|
||||||
yAxisID: "y1",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
scales: {
|
|
||||||
x: {
|
|
||||||
type: "category",
|
|
||||||
title: { display: true, text: "Zeit" },
|
|
||||||
},
|
|
||||||
y: {
|
|
||||||
type: "linear",
|
|
||||||
position: "left",
|
|
||||||
title: { display: true, text: "MOhm" },
|
|
||||||
},
|
|
||||||
y1: {
|
|
||||||
type: "linear",
|
|
||||||
position: "right",
|
|
||||||
title: { display: true, text: "kOhm" },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
plugins: {
|
|
||||||
zoom: {
|
|
||||||
pan: {
|
|
||||||
enabled: true,
|
|
||||||
mode: "xy",
|
|
||||||
},
|
|
||||||
zoom: {
|
|
||||||
wheel: {
|
|
||||||
enabled: true,
|
|
||||||
},
|
|
||||||
pinch: {
|
|
||||||
enabled: true,
|
|
||||||
},
|
|
||||||
mode: "xy",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const updateAlarmStatus = () => {
|
const updateAlarmStatus = () => {
|
||||||
const alarmStatus =
|
const alarmStatus =
|
||||||
|
|||||||
@@ -1,5 +1,113 @@
|
|||||||
import React from "react";
|
import React, { useState } from "react";
|
||||||
|
|
||||||
export default function OPCUAInterfaceSettings() {
|
export default function OPCUAInterfaceSettings() {
|
||||||
return <div>OPCUAInterfaceSettings</div>;
|
const [isEnabled, setIsEnabled] = useState(true);
|
||||||
|
const [encryption, setEncryption] = useState("None");
|
||||||
|
const [users, setUsers] = useState([
|
||||||
|
{ id: 1, username: "admin", password: "admin123" },
|
||||||
|
{ id: 2, username: "user1", password: "user123" },
|
||||||
|
]);
|
||||||
|
const [newUser, setNewUser] = useState({ username: "", password: "" });
|
||||||
|
|
||||||
|
const toggleServer = () => setIsEnabled(!isEnabled);
|
||||||
|
const updateEncryption = (event) => setEncryption(event.target.value);
|
||||||
|
const addUser = () => {
|
||||||
|
if (newUser.username && newUser.password) {
|
||||||
|
setUsers([...users, { id: users.length + 1, ...newUser }]);
|
||||||
|
setNewUser({ username: "", password: "" });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const removeUser = (id) => setUsers(users.filter((user) => user.id !== id));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="max-w-3xl mx-auto p-6 bg-gray-100 shadow-md rounded-lg">
|
||||||
|
<h2 className="text-xl font-semibold mb-4">OPCUA Server Einstellungen</h2>
|
||||||
|
|
||||||
|
{/* Server Aktivierung */}
|
||||||
|
<div className="mb-4">
|
||||||
|
<label className="flex items-center cursor-pointer">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={isEnabled}
|
||||||
|
onChange={toggleServer}
|
||||||
|
className="hidden"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className={`w-12 h-6 rounded-full transition-all ${
|
||||||
|
isEnabled ? "bg-green-500" : "bg-gray-300"
|
||||||
|
}`}
|
||||||
|
></div>
|
||||||
|
<span className="ml-2 text-sm">
|
||||||
|
{isEnabled ? "Aktiviert" : "Deaktiviert"}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Verschlüsselung */}
|
||||||
|
<div className="mb-4">
|
||||||
|
<label className="block text-sm font-medium text-gray-700">
|
||||||
|
Verschlüsselung
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
value={encryption}
|
||||||
|
onChange={updateEncryption}
|
||||||
|
className="mt-1 block w-full p-2 border border-gray-300 rounded-md shadow-sm focus:ring focus:ring-blue-200"
|
||||||
|
>
|
||||||
|
<option value="None">Keine</option>
|
||||||
|
<option value="Basic256">Basic256</option>
|
||||||
|
<option value="Basic256Sha256">Basic256Sha256</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Benutzer & Passwörter */}
|
||||||
|
<div className="mb-4">
|
||||||
|
<h3 className="text-lg font-semibold mb-2">Benutzer</h3>
|
||||||
|
<ul className="space-y-2">
|
||||||
|
{users.map((user) => (
|
||||||
|
<li
|
||||||
|
key={user.id}
|
||||||
|
className="p-2 bg-white shadow-sm rounded-md flex justify-between items-center"
|
||||||
|
>
|
||||||
|
<span className="font-medium">{user.username}</span>
|
||||||
|
<span className="text-gray-600 ml-2">
|
||||||
|
(Passwort: {user.password})
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
onClick={() => removeUser(user.id)}
|
||||||
|
className="ml-4 text-red-500"
|
||||||
|
>
|
||||||
|
Löschen
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
<div className="mt-4">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="Benutzername"
|
||||||
|
value={newUser.username}
|
||||||
|
onChange={(e) =>
|
||||||
|
setNewUser({ ...newUser, username: e.target.value })
|
||||||
|
}
|
||||||
|
className="p-2 border rounded mr-2"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
placeholder="Passwort"
|
||||||
|
value={newUser.password}
|
||||||
|
onChange={(e) =>
|
||||||
|
setNewUser({ ...newUser, password: e.target.value })
|
||||||
|
}
|
||||||
|
className="p-2 border rounded mr-2"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
onClick={addUser}
|
||||||
|
className="bg-blue-500 text-white p-2 rounded"
|
||||||
|
>
|
||||||
|
Hinzufügen
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export default function Settings() {
|
|||||||
}`}
|
}`}
|
||||||
onClick={() => setActiveTab("tab1")}
|
onClick={() => setActiveTab("tab1")}
|
||||||
>
|
>
|
||||||
Allgemeine Einstellung
|
Allgemeine Einstellungen
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
className={`px-4 py-2 ${
|
className={`px-4 py-2 ${
|
||||||
|
|||||||
153
utils/chartUtils.ts
Normal file
153
utils/chartUtils.ts
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import Chart from "chart.js/auto";
|
||||||
|
import { DataTDR } from "../redux/types/chartDataTypesTDR";
|
||||||
|
|
||||||
|
const chartInstance = { current: null as Chart | null };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erstellt ein TDR-Chart basierend auf den übergebenen Daten.
|
||||||
|
*/
|
||||||
|
export const createTDRChart = (dataTDR: DataTDR[]) => {
|
||||||
|
const canvas = document.getElementById("myChart") as HTMLCanvasElement;
|
||||||
|
if (!canvas) {
|
||||||
|
console.error("Canvas mit ID 'myChart' nicht gefunden.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
if (!ctx) {
|
||||||
|
console.error("2D-Kontext für Canvas konnte nicht erstellt werden.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chartInstance.current) {
|
||||||
|
chartInstance.current.destroy();
|
||||||
|
chartInstance.current = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const minX = Math.min(...dataTDR.map((row) => row.t));
|
||||||
|
const maxX = Math.max(...dataTDR.map((row) => row.t));
|
||||||
|
const minY = Math.min(...dataTDR.map((row) => row.m));
|
||||||
|
const maxY = Math.max(...dataTDR.map((row) => row.m));
|
||||||
|
|
||||||
|
try {
|
||||||
|
chartInstance.current = new Chart(ctx, {
|
||||||
|
type: "line",
|
||||||
|
data: {
|
||||||
|
labels: dataTDR.map((row) => row.t),
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: "Pegel",
|
||||||
|
data: dataTDR.map((row) => row.m),
|
||||||
|
borderColor: "#00AEEF",
|
||||||
|
borderWidth: 2,
|
||||||
|
fill: false,
|
||||||
|
tension: 0.1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
type: "linear",
|
||||||
|
position: "bottom",
|
||||||
|
title: { display: true, text: "Entfernung" },
|
||||||
|
min: minX - 5,
|
||||||
|
max: maxX + 5,
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
title: { display: true, text: "Pegel" },
|
||||||
|
min: minY - 10,
|
||||||
|
max: maxY + 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Fehler beim Erstellen des TDR-Charts:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
interface DataLoop {
|
||||||
|
t: number;
|
||||||
|
m: number;
|
||||||
|
n: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erstellt ein Schleifenmess-Chart basierend auf den übergebenen Daten.
|
||||||
|
*/
|
||||||
|
export const createLoopChart = (data: DataLoop[], title: string) => {
|
||||||
|
const canvas = document.getElementById("myChart") as HTMLCanvasElement;
|
||||||
|
if (!canvas) {
|
||||||
|
console.error("Canvas mit ID 'myChart' nicht gefunden.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
if (!ctx) {
|
||||||
|
console.error("2D-Kontext für Canvas konnte nicht erstellt werden.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const labels = data.map((row) => {
|
||||||
|
const date = new Date(String(row.t).replace(/-/g, "/"));
|
||||||
|
return date.toLocaleString("de-DE", {
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
second: "2-digit",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
new Chart(ctx, {
|
||||||
|
type: "line",
|
||||||
|
data: {
|
||||||
|
labels,
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: "Isolationswiderstand (MOhm)",
|
||||||
|
data: data.map((row) => row.m),
|
||||||
|
borderColor: "#00AEEF",
|
||||||
|
borderWidth: 1,
|
||||||
|
tension: 0.1,
|
||||||
|
pointRadius: 1,
|
||||||
|
pointHoverRadius: 5,
|
||||||
|
fill: false,
|
||||||
|
yAxisID: "y",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Schleifenwiderstand (kOhm)",
|
||||||
|
data: data.map((row) => row.n),
|
||||||
|
borderColor: "black",
|
||||||
|
borderWidth: 1,
|
||||||
|
tension: 0.1,
|
||||||
|
pointRadius: 1,
|
||||||
|
pointHoverRadius: 5,
|
||||||
|
fill: false,
|
||||||
|
yAxisID: "y1",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
type: "category",
|
||||||
|
title: { display: true, text: "Zeit" },
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
type: "linear",
|
||||||
|
position: "left",
|
||||||
|
title: { display: true, text: "MOhm" },
|
||||||
|
},
|
||||||
|
y1: {
|
||||||
|
type: "linear",
|
||||||
|
position: "right",
|
||||||
|
title: { display: true, text: "kOhm" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user