291 lines
8.3 KiB
JavaScript
291 lines
8.3 KiB
JavaScript
/**
|
|
* 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>
|
|
`;
|
|
}
|