📝 Commit Details:

This commit is contained in:
2025-05-31 22:40:29 +02:00
parent 91b1886dde
commit df8fb197c0
14061 changed files with 997277 additions and 103548 deletions

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,291 @@
/**
* MYP Platform Chart-Adapter
* Verbindet bestehende API/Logik mit ApexCharts
* Version: 1.0.0
*/
/**
* Überbrückt die bestehende renderChart Funktion mit der neuen ApexCharts Implementation
* @param {HTMLElement} container - Der Diagramm-Container
* @param {Object} data - Die Diagrammdaten vom API-Endpunkt
*/
function renderChart(container, data) {
// Überprüfen, ob die Daten vorhanden sind
if (!data || (Array.isArray(data) && data.length === 0) || Object.keys(data).length === 0) {
showEmptyState(container, 'Keine Daten', 'Es sind keine Daten für dieses Diagramm verfügbar.');
return;
}
// Container-ID überprüfen und ggf. generieren
if (!container.id) {
container.id = 'chart-' + Math.random().toString(36).substr(2, 9);
}
// Chart-Typ basierend auf Container-ID oder Attributen bestimmen
let chartType = container.getAttribute('data-chart-type');
if (!chartType) {
if (container.id === 'job-status-chart') {
chartType = 'pie';
container.setAttribute('data-chart-type', 'pie');
} else if (container.id === 'printer-usage-chart') {
chartType = 'bar';
container.setAttribute('data-chart-type', 'bar');
} else if (container.id.includes('line')) {
chartType = 'line';
container.setAttribute('data-chart-type', 'line');
} else if (container.id.includes('area')) {
chartType = 'area';
container.setAttribute('data-chart-type', 'area');
} else if (container.id.includes('bar')) {
chartType = 'bar';
container.setAttribute('data-chart-type', 'bar');
} else if (container.id.includes('pie')) {
chartType = 'pie';
container.setAttribute('data-chart-type', 'pie');
} else if (container.id.includes('donut')) {
chartType = 'donut';
container.setAttribute('data-chart-type', 'donut');
} else {
// Standard-Typ
chartType = 'line';
container.setAttribute('data-chart-type', 'line');
}
}
// Daten für das Diagramm vorbereiten
let chartData = {};
// Daten-Transformation basierend auf Container-ID
if (container.id === 'job-status-chart') {
chartData = transformJobStatusData(data);
} else if (container.id === 'printer-usage-chart') {
chartData = transformPrinterUsageData(data);
} else {
// Generischer Ansatz für andere Diagrammtypen
chartData = transformGenericData(data, chartType);
}
// Existierendes Chart zerstören, falls vorhanden
if (activeCharts[container.id]) {
destroyChart(container.id);
}
// Daten als Attribut am Container speichern
container.setAttribute('data-chart-data', JSON.stringify(chartData));
// Neues Chart erstellen
createChart(container, chartType, chartData);
}
/**
* Transformiert Job-Status-Daten für Pie-Chart
* @param {Object} data - Rohdaten vom API-Endpunkt
* @returns {Object} - Formatierte Daten für ApexCharts
*/
function transformJobStatusData(data) {
// Werte für Pie-Chart extrahieren
const series = [
data.scheduled || 0,
data.active || 0,
data.completed || 0,
data.cancelled || 0
];
// Labels für die Diagramm-Segmente
const labels = ['Geplant', 'Aktiv', 'Abgeschlossen', 'Abgebrochen'];
// Benutzerdefinierte Farben
const colors = [
MYP_CHART_COLORS.info, // Blau für geplant
MYP_CHART_COLORS.primary, // Primär für aktiv
MYP_CHART_COLORS.success, // Grün für abgeschlossen
MYP_CHART_COLORS.warning // Gelb für abgebrochen
];
// Zusätzliche Optionen
const options = {
colors: colors,
chart: {
height: 320
},
plotOptions: {
pie: {
donut: {
size: '0%' // Vollständiger Kreis (kein Donut)
}
}
},
legend: {
position: 'bottom'
}
};
return {
series: series,
labels: labels,
options: options
};
}
/**
* Transformiert Drucker-Nutzungsdaten für Bar-Chart
* @param {Object} data - Rohdaten vom API-Endpunkt
* @returns {Object} - Formatierte Daten für ApexCharts
*/
function transformPrinterUsageData(data) {
// Prüfen, ob Daten ein Array sind
if (!Array.isArray(data)) {
console.error('Drucker-Nutzungsdaten müssen ein Array sein:', data);
return {
series: [],
categories: [],
options: {}
};
}
// Druckernamen für X-Achse extrahieren
const categories = data.map(item => item.printer_name || 'Unbekannt');
// Datenreihen für Jobs und Stunden erstellen
const jobsSeries = {
name: 'Jobs',
data: data.map(item => item.job_count || 0)
};
const hoursSeries = {
name: 'Stunden',
data: data.map(item => Math.round((item.print_hours || 0) * 10) / 10)
};
// Zusätzliche Optionen
const options = {
colors: [MYP_CHART_COLORS.primary, MYP_CHART_COLORS.success],
chart: {
height: 320
},
plotOptions: {
bar: {
horizontal: false,
columnWidth: '60%',
borderRadius: 4
}
},
dataLabels: {
enabled: false
},
xaxis: {
categories: categories
}
};
return {
series: [jobsSeries, hoursSeries],
categories: categories,
options: options
};
}
/**
* Transformiert generische Daten für verschiedene Diagrammtypen
* @param {Object|Array} data - Rohdaten vom API-Endpunkt
* @param {string} chartType - Art des Diagramms
* @returns {Object} - Formatierte Daten für ApexCharts
*/
function transformGenericData(data, chartType) {
// Standard-Ergebnisobjekt
const result = {
series: [],
categories: [],
labels: [],
options: {}
};
// Arrays verarbeiten
if (Array.isArray(data)) {
if (chartType === 'pie' || chartType === 'donut' || chartType === 'radial') {
// Für Kreisdiagramme
result.series = data.map(item => item.value || 0);
result.labels = data.map(item => item.name || item.label || 'Unbekannt');
} else {
// Für Linien-, Flächen- und Balkendiagramme
// Annahme: Erste Datenreihe
result.series = [{
name: 'Werte',
data: data.map(item => item.value || 0)
}];
result.categories = data.map(item => item.name || item.label || item.date || 'Unbekannt');
}
}
// Objekte mit Datenreihen verarbeiten
else if (data.series && Array.isArray(data.series)) {
result.series = data.series;
if (data.categories) {
result.categories = data.categories;
}
if (data.labels) {
result.labels = data.labels;
}
if (data.options) {
result.options = data.options;
}
}
// Einfache Objekte verarbeiten
else {
// Für Kreisdiagramme: Alle Eigenschaften als Segmente verwenden
if (chartType === 'pie' || chartType === 'donut' || chartType === 'radial') {
const seriesData = [];
const labelData = [];
Object.keys(data).forEach(key => {
if (typeof data[key] === 'number') {
seriesData.push(data[key]);
labelData.push(key);
}
});
result.series = seriesData;
result.labels = labelData;
}
// Für andere Diagrammtypen: Versuchen, Zeit-/Wertepaare zu finden
else {
const timeKeys = [];
const values = [];
Object.keys(data).forEach(key => {
if (typeof data[key] === 'number') {
timeKeys.push(key);
values.push(data[key]);
}
});
result.series = [{
name: 'Werte',
data: values
}];
result.categories = timeKeys;
}
}
return result;
}
/**
* Zeigt einen leeren Status-Container an
* @param {HTMLElement} container - Der Diagramm-Container
* @param {string} title - Titel der Meldung
* @param {string} message - Meldungstext
*/
function showEmptyState(container, title, message) {
container.innerHTML = `
<div class="text-center py-8">
<svg class="w-12 h-12 mx-auto text-slate-500 dark:text-slate-400 mb-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4"/>
</svg>
<h3 class="text-lg font-medium text-slate-700 dark:text-slate-300">${title}</h3>
<p class="text-sm text-slate-500 dark:text-slate-400 italic mt-1">${message}</p>
</div>
`;
}

View File

@ -0,0 +1,431 @@
/**
* MYP Platform Chart-Konfigurationen
* Basierend auf ApexCharts Bibliothek
* Version: 1.0.0
*/
// Standard Farben für Diagramme
const MYP_CHART_COLORS = {
primary: '#3b82f6', // Blau
secondary: '#8b5cf6', // Lila
success: '#10b981', // Grün
warning: '#f59e0b', // Orange
danger: '#ef4444', // Rot
info: '#06b6d4', // Türkis
gray: '#6b7280', // Grau
gradient: {
blue: ['#3b82f6', '#93c5fd'],
purple: ['#8b5cf6', '#c4b5fd'],
green: ['#10b981', '#6ee7b7'],
red: ['#ef4444', '#fca5a5'],
orange: ['#f59e0b', '#fcd34d'],
}
};
// Gemeinsame Grundeinstellungen für alle Diagramme
const getBaseChartOptions = () => {
return {
chart: {
fontFamily: 'Inter, sans-serif',
toolbar: {
show: false
},
zoom: {
enabled: false
},
animations: {
enabled: true,
easing: 'easeinout',
speed: 800,
animateGradually: {
enabled: true,
delay: 150
},
dynamicAnimation: {
enabled: true,
speed: 350
}
}
},
tooltip: {
enabled: true,
theme: 'dark',
style: {
fontSize: '12px',
fontFamily: 'Inter, sans-serif'
}
},
grid: {
show: true,
borderColor: '#334155',
strokeDashArray: 4,
position: 'back',
xaxis: {
lines: {
show: false
}
},
yaxis: {
lines: {
show: true
}
}
},
legend: {
position: 'bottom',
horizontalAlign: 'center',
offsetY: 8,
fontSize: '14px',
fontFamily: 'Inter, sans-serif',
markers: {
width: 10,
height: 10,
strokeWidth: 0,
radius: 4
},
itemMargin: {
horizontal: 10,
vertical: 0
}
},
stroke: {
curve: 'smooth',
width: 3
},
xaxis: {
labels: {
style: {
fontSize: '12px',
fontFamily: 'Inter, sans-serif',
colors: '#94a3b8'
}
},
axisBorder: {
show: false
},
axisTicks: {
show: false
}
},
yaxis: {
labels: {
style: {
fontSize: '12px',
fontFamily: 'Inter, sans-serif',
colors: '#94a3b8'
}
}
},
dataLabels: {
enabled: false
},
responsive: [
{
breakpoint: 768,
options: {
chart: {
height: '300px'
},
legend: {
position: 'bottom',
offsetY: 0
}
}
}
]
};
};
/**
* Liniendiagramm Konfiguration
* @param {Array} series - Datenreihen
* @param {Array} categories - X-Achsen Kategorien
* @param {Object} customOptions - Benutzerdefinierte Optionen
* @returns {Object} Konfigurationsobjekt für ApexCharts
*/
function getLineChartConfig(series, categories, customOptions = {}) {
const baseOptions = getBaseChartOptions();
const defaultOptions = {
chart: {
...baseOptions.chart,
type: 'line',
height: 350
},
colors: [
MYP_CHART_COLORS.primary,
MYP_CHART_COLORS.secondary,
MYP_CHART_COLORS.success
],
series: series || [],
xaxis: {
...baseOptions.xaxis,
categories: categories || []
}
};
// Optionen zusammenführen
return mergeDeep(mergeDeep({}, baseOptions), mergeDeep(defaultOptions, customOptions));
}
/**
* Flächendiagramm Konfiguration
* @param {Array} series - Datenreihen
* @param {Array} categories - X-Achsen Kategorien
* @param {Object} customOptions - Benutzerdefinierte Optionen
* @returns {Object} Konfigurationsobjekt für ApexCharts
*/
function getAreaChartConfig(series, categories, customOptions = {}) {
const baseOptions = getBaseChartOptions();
const defaultOptions = {
chart: {
...baseOptions.chart,
type: 'area',
height: 350
},
colors: [
MYP_CHART_COLORS.primary,
MYP_CHART_COLORS.success
],
series: series || [],
xaxis: {
...baseOptions.xaxis,
categories: categories || []
},
fill: {
type: 'gradient',
gradient: {
shadeIntensity: 1,
opacityFrom: 0.7,
opacityTo: 0.3,
stops: [0, 90, 100]
}
}
};
// Optionen zusammenführen
return mergeDeep(mergeDeep({}, baseOptions), mergeDeep(defaultOptions, customOptions));
}
/**
* Balkendiagramm Konfiguration
* @param {Array} series - Datenreihen
* @param {Array} categories - X-Achsen Kategorien
* @param {Object} customOptions - Benutzerdefinierte Optionen
* @returns {Object} Konfigurationsobjekt für ApexCharts
*/
function getBarChartConfig(series, categories, customOptions = {}) {
const baseOptions = getBaseChartOptions();
const defaultOptions = {
chart: {
...baseOptions.chart,
type: 'bar',
height: 350
},
colors: [
MYP_CHART_COLORS.primary,
MYP_CHART_COLORS.secondary
],
series: series || [],
xaxis: {
...baseOptions.xaxis,
categories: categories || []
},
plotOptions: {
bar: {
horizontal: false,
columnWidth: '70%',
borderRadius: 6,
dataLabels: {
position: 'top'
}
}
}
};
// Optionen zusammenführen
return mergeDeep(mergeDeep({}, baseOptions), mergeDeep(defaultOptions, customOptions));
}
/**
* Kreisdiagramm Konfiguration
* @param {Array} series - Datenreihen (Werte)
* @param {Array} labels - Beschriftungen
* @param {Object} customOptions - Benutzerdefinierte Optionen
* @returns {Object} Konfigurationsobjekt für ApexCharts
*/
function getPieChartConfig(series, labels, customOptions = {}) {
const baseOptions = getBaseChartOptions();
const defaultOptions = {
chart: {
...baseOptions.chart,
type: 'pie',
height: 350
},
colors: [
MYP_CHART_COLORS.primary,
MYP_CHART_COLORS.success,
MYP_CHART_COLORS.warning,
MYP_CHART_COLORS.danger,
MYP_CHART_COLORS.info
],
series: series || [],
labels: labels || [],
legend: {
position: 'bottom'
},
responsive: [
{
breakpoint: 480,
options: {
chart: {
width: 300
},
legend: {
position: 'bottom'
}
}
}
]
};
// Optionen zusammenführen
return mergeDeep(mergeDeep({}, baseOptions), mergeDeep(defaultOptions, customOptions));
}
/**
* Donut-Diagramm Konfiguration
* @param {Array} series - Datenreihen (Werte)
* @param {Array} labels - Beschriftungen
* @param {Object} customOptions - Benutzerdefinierte Optionen
* @returns {Object} Konfigurationsobjekt für ApexCharts
*/
function getDonutChartConfig(series, labels, customOptions = {}) {
const baseOptions = getBaseChartOptions();
const defaultOptions = {
chart: {
...baseOptions.chart,
type: 'donut',
height: 350
},
colors: [
MYP_CHART_COLORS.primary,
MYP_CHART_COLORS.success,
MYP_CHART_COLORS.warning,
MYP_CHART_COLORS.danger,
MYP_CHART_COLORS.info
],
series: series || [],
labels: labels || [],
legend: {
position: 'bottom'
},
plotOptions: {
pie: {
donut: {
size: '70%',
labels: {
show: true,
name: {
show: true
},
value: {
show: true,
formatter: function(val) {
return val;
}
},
total: {
show: true,
formatter: function(w) {
return w.globals.seriesTotals.reduce((a, b) => a + b, 0);
}
}
}
}
}
}
};
// Optionen zusammenführen
return mergeDeep(mergeDeep({}, baseOptions), mergeDeep(defaultOptions, customOptions));
}
/**
* Radial-Diagramm Konfiguration
* @param {Array} series - Datenreihen (Werte)
* @param {Array} labels - Beschriftungen
* @param {Object} customOptions - Benutzerdefinierte Optionen
* @returns {Object} Konfigurationsobjekt für ApexCharts
*/
function getRadialChartConfig(series, labels, customOptions = {}) {
const baseOptions = getBaseChartOptions();
const defaultOptions = {
chart: {
...baseOptions.chart,
type: 'radialBar',
height: 350
},
colors: [
MYP_CHART_COLORS.primary,
MYP_CHART_COLORS.success,
MYP_CHART_COLORS.warning
],
series: series || [],
labels: labels || [],
plotOptions: {
radialBar: {
dataLabels: {
name: {
fontSize: '22px',
},
value: {
fontSize: '16px',
},
total: {
show: true,
label: 'Gesamt',
formatter: function(w) {
return w.globals.seriesTotals.reduce((a, b) => a + b, 0) + '%';
}
}
}
}
}
};
// Optionen zusammenführen
return mergeDeep(mergeDeep({}, baseOptions), mergeDeep(defaultOptions, customOptions));
}
/**
* Helper-Funktion zum tiefen Zusammenführen von Objekten
*/
function mergeDeep(target, source) {
const isObject = obj => obj && typeof obj === 'object';
if (!isObject(target) || !isObject(source)) {
return source;
}
const output = { ...target };
Object.keys(source).forEach(key => {
if (isObject(source[key])) {
if (!(key in target)) {
output[key] = source[key];
} else {
output[key] = mergeDeep(target[key], source[key]);
}
} else {
output[key] = source[key];
}
});
return output;
}

View File

@ -0,0 +1,400 @@
/**
* MYP Platform Chart-Renderer
* Erstellt und verwaltet Diagramme mit ApexCharts
* Version: 1.0.0
*/
// Speicher für aktive Chart-Instanzen
const activeCharts = {};
/**
* Initialisiert alle Diagramme auf der Seite
*/
function initCharts() {
// Prüfen, ob ApexCharts verfügbar ist
if (typeof ApexCharts === 'undefined') {
console.error('ApexCharts ist nicht geladen. Bitte ApexCharts vor chart-renderer.js einbinden.');
return;
}
// Alle Diagramm-Container mit data-chart-type Attribut finden
const chartContainers = document.querySelectorAll('[data-chart-type]');
// Für jeden Container ein Diagramm erstellen
chartContainers.forEach(container => {
const chartId = container.id;
const chartType = container.getAttribute('data-chart-type');
// Prüfen, ob Container eine ID hat
if (!chartId) {
console.error('Chart-Container benötigt eine ID:', container);
return;
}
// Bereits erstellte Charts nicht neu initialisieren
if (activeCharts[chartId]) {
return;
}
// Daten aus data-chart-data Attribut laden (als JSON)
let chartData = {};
try {
const dataAttr = container.getAttribute('data-chart-data');
if (dataAttr) {
chartData = JSON.parse(dataAttr);
}
} catch (error) {
console.error(`Fehler beim Parsen der Chart-Daten für ${chartId}:`, error);
return;
}
// Chart basierend auf Typ erstellen
createChart(container, chartType, chartData);
});
}
/**
* Erstellt ein einzelnes Diagramm
* @param {HTMLElement} container - Der Container für das Diagramm
* @param {string} chartType - Typ des Diagramms (line, area, bar, pie, donut, radial)
* @param {Object} chartData - Daten und Optionen für das Diagramm
*/
function createChart(container, chartType, chartData = {}) {
const chartId = container.id;
let chartOptions = {};
// Diagramm-Typ-spezifische Konfiguration laden
switch(chartType.toLowerCase()) {
case 'line':
chartOptions = getLineChartConfig(
chartData.series || [],
chartData.categories || [],
chartData.options || {}
);
break;
case 'area':
chartOptions = getAreaChartConfig(
chartData.series || [],
chartData.categories || [],
chartData.options || {}
);
break;
case 'bar':
chartOptions = getBarChartConfig(
chartData.series || [],
chartData.categories || [],
chartData.options || {}
);
break;
case 'pie':
chartOptions = getPieChartConfig(
chartData.series || [],
chartData.labels || [],
chartData.options || {}
);
break;
case 'donut':
chartOptions = getDonutChartConfig(
chartData.series || [],
chartData.labels || [],
chartData.options || {}
);
break;
case 'radial':
chartOptions = getRadialChartConfig(
chartData.series || [],
chartData.labels || [],
chartData.options || {}
);
break;
default:
console.error(`Unbekannter Chart-Typ: ${chartType}`);
return;
}
// Dark Mode Anpassungen
updateChartTheme(chartOptions);
// Chart erstellen und speichern
try {
const chart = new ApexCharts(container, chartOptions);
chart.render();
// Referenz speichern
activeCharts[chartId] = {
instance: chart,
type: chartType,
lastData: chartData
};
return chart;
} catch (error) {
console.error(`Fehler beim Erstellen des Charts ${chartId}:`, error);
return null;
}
}
/**
* Aktualisiert ein bestehendes Diagramm mit neuen Daten
* @param {string} chartId - ID des Diagramm-Containers
* @param {Object} newData - Neue Daten für das Diagramm
*/
function updateChart(chartId, newData) {
const chartInfo = activeCharts[chartId];
if (!chartInfo) {
console.error(`Chart mit ID ${chartId} nicht gefunden.`);
return;
}
const chart = chartInfo.instance;
// Aktualisieren basierend auf Chart-Typ
if (chartInfo.type === 'pie' || chartInfo.type === 'donut' || chartInfo.type === 'radial') {
// Für Pie/Donut/Radial-Charts
chart.updateSeries(newData.series || []);
if (newData.labels) {
chart.updateOptions({
labels: newData.labels
});
}
} else {
// Für Line/Area/Bar-Charts
chart.updateSeries(newData.series || []);
if (newData.categories) {
chart.updateOptions({
xaxis: {
categories: newData.categories
}
});
}
}
// Zusätzliche Optionen aktualisieren
if (newData.options) {
chart.updateOptions(newData.options);
}
// Gespeicherte Daten aktualisieren
chartInfo.lastData = {
...chartInfo.lastData,
...newData
};
}
/**
* Lädt Diagrammdaten über AJAX und aktualisiert das Diagramm
* @param {string} chartId - ID des Diagramm-Containers
* @param {string} url - URL zur Datenbeschaffung
* @param {Function} successCallback - Callback nach erfolgreicher Aktualisierung
*/
function loadChartData(chartId, url, successCallback) {
const container = document.getElementById(chartId);
if (!container) {
console.error(`Container mit ID ${chartId} nicht gefunden.`);
return;
}
// Lade-Animation anzeigen
container.classList.add('chart-loading');
// Daten vom Server laden
fetch(url)
.then(response => {
if (!response.ok) {
throw new Error('Netzwerkantwort war nicht ok');
}
return response.json();
})
.then(data => {
// Lade-Animation entfernen
container.classList.remove('chart-loading');
const chartInfo = activeCharts[chartId];
// Chart erstellen, falls nicht vorhanden
if (!chartInfo) {
const chartType = container.getAttribute('data-chart-type');
if (chartType) {
createChart(container, chartType, data);
} else {
console.error(`Kein Chart-Typ für ${chartId} definiert.`);
}
} else {
// Bestehendes Chart aktualisieren
updateChart(chartId, data);
}
// Callback aufrufen, falls vorhanden
if (typeof successCallback === 'function') {
successCallback(data);
}
})
.catch(error => {
console.error('Fehler beim Laden der Chart-Daten:', error);
container.classList.remove('chart-loading');
// Fehlermeldung im Container anzeigen
container.innerHTML = `
<div class="chart-error">
<svg class="w-10 h-10 text-red-500 mb-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
<h3 class="text-lg font-medium">Fehler beim Laden</h3>
<p class="text-sm text-gray-500">Die Diagrammdaten konnten nicht geladen werden.</p>
</div>
`;
});
}
/**
* Aktualisiert die Farbthemen basierend auf dem Dark Mode
* @param {Object} chartOptions - Chart-Optionen Objekt
*/
function updateChartTheme(chartOptions) {
const isDarkMode = document.documentElement.classList.contains('dark');
// Theme anpassen
if (isDarkMode) {
// Dark Mode Einstellungen
chartOptions.theme = {
mode: 'dark',
palette: 'palette1'
};
chartOptions.grid = {
...chartOptions.grid,
borderColor: '#334155'
};
// Text Farben anpassen
chartOptions.xaxis = {
...chartOptions.xaxis,
labels: {
...chartOptions.xaxis?.labels,
style: {
...chartOptions.xaxis?.labels?.style,
colors: '#94a3b8'
}
}
};
chartOptions.yaxis = {
...chartOptions.yaxis,
labels: {
...chartOptions.yaxis?.labels,
style: {
...chartOptions.yaxis?.labels?.style,
colors: '#94a3b8'
}
}
};
} else {
// Light Mode Einstellungen
chartOptions.theme = {
mode: 'light',
palette: 'palette1'
};
chartOptions.grid = {
...chartOptions.grid,
borderColor: '#e2e8f0'
};
// Text Farben anpassen
chartOptions.xaxis = {
...chartOptions.xaxis,
labels: {
...chartOptions.xaxis?.labels,
style: {
...chartOptions.xaxis?.labels?.style,
colors: '#64748b'
}
}
};
chartOptions.yaxis = {
...chartOptions.yaxis,
labels: {
...chartOptions.yaxis?.labels,
style: {
...chartOptions.yaxis?.labels?.style,
colors: '#64748b'
}
}
};
}
return chartOptions;
}
/**
* Event-Listener für Dark Mode Änderungen
*/
function setupDarkModeListener() {
window.addEventListener('darkModeChanged', function(event) {
const isDark = event.detail?.isDark;
// Alle aktiven Charts aktualisieren
Object.keys(activeCharts).forEach(chartId => {
const chartInfo = activeCharts[chartId];
const chart = chartInfo.instance;
// Theme aktualisieren
const updatedOptions = updateChartTheme({
grid: chart.opts.grid,
xaxis: chart.opts.xaxis,
yaxis: chart.opts.yaxis
});
// Chart aktualisieren
chart.updateOptions({
theme: updatedOptions.theme,
grid: updatedOptions.grid,
xaxis: updatedOptions.xaxis,
yaxis: updatedOptions.yaxis
});
});
});
}
/**
* Entfernt alle Chart-Instanzen
*/
function destroyAllCharts() {
Object.keys(activeCharts).forEach(chartId => {
const chartInfo = activeCharts[chartId];
if (chartInfo && chartInfo.instance) {
chartInfo.instance.destroy();
}
});
// Aktive Charts zurücksetzen
Object.keys(activeCharts).forEach(key => delete activeCharts[key]);
}
/**
* Entfernt eine spezifische Chart-Instanz
* @param {string} chartId - ID des Diagramm-Containers
*/
function destroyChart(chartId) {
const chartInfo = activeCharts[chartId];
if (chartInfo && chartInfo.instance) {
chartInfo.instance.destroy();
delete activeCharts[chartId];
}
}
// DOM bereit Event-Listener
document.addEventListener('DOMContentLoaded', function() {
initCharts();
setupDarkModeListener();
});