/** * 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 = `

Fehler beim Laden

Die Diagrammdaten konnten nicht geladen werden.

`; }); } /** * 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(); });