"use strict"; /** * @module visualization * @description Verarbeitung und Darstellung aggregierter Zeitmessungsdaten. * Verantwortlich für Rendering und Update von Charts und Summary Cards. */ /** * Rendert interaktive Diagramme auf Basis der geladenen Daten. * @param {Array} data - Aggregierte Ergebnisse von der /results API. * @param {HTMLElement} container - Container-Element zur Anzeige des Diagramms. * @returns {void} */ export function renderCharts(data, container) { if (!Array.isArray(data) || !container) return; container.innerHTML = ""; const canvas = document.createElement("canvas"); canvas.id = "chart-results"; canvas.setAttribute("aria-label", "Zeitmessungsdiagramm"); canvas.setAttribute("role", "img"); container.appendChild(canvas); const ctx = canvas.getContext("2d"); const runTypes = [...new Set(data.map(d => d.run_type))]; const labels = data.map(d => d.run_id); const datasets = runTypes.map((type) => { const subset = data.filter(d => d.run_type === type); return { label: type, data: subset.map(r => r.metrics?.latency_mean ?? 0), borderColor: type === "pinned" ? "#2a9d8f" : "#e76f51", backgroundColor: type === "pinned" ? "rgba(42,157,143,0.4)" : "rgba(231,111,81,0.4)", borderWidth: 2, tension: 0.3, }; }); if (window.currentChart) { window.currentChart.destroy(); } window.currentChart = new Chart(ctx, { type: "line", data: { labels, datasets }, options: { responsive: true, interaction: { mode: "index", intersect: false }, scales: { x: { title: { display: true, text: "Run ID" } }, y: { title: { display: true, text: "Latenz (ms)" }, beginAtZero: true } }, plugins: { legend: { position: "top" }, tooltip: { callbacks: { label: ctx => `${ctx.dataset.label}: ${ctx.parsed.y.toFixed(2)} ms` } } } } }); renderSummary(data); } /** * Aktualisiert Diagramme und Statistiken basierend auf Filtern. * @param {Object} filters - Nutzerdefinierte Filterparameter. * @param {Array} data - Aktuelle Ergebnisdaten. * @returns {void} */ export function updateVisualization(filters, data) { if (typeof filters !== "object" || !Array.isArray(data)) return; const filteredData = data.filter(item => { const matchRunType = !filters.runType || item.run_type === filters.runType; const matchMetric = !filters.metric || Object.keys(item.metrics || {}).includes(filters.metric); return matchRunType && matchMetric; }); const container = document.querySelector("#chart-container"); renderCharts(filteredData, container); } /** * Rendert aggregierte Kennzahlen als Summary Cards unterhalb des Diagramms. * @param {Array} data */ function renderSummary(data) { const summaryContainer = document.querySelector("#summary-container"); if (!summaryContainer) return; const total = data.length; const avgLatency = (data.reduce((acc, val) => acc + (val.metrics?.latency_mean ?? 0), 0) / Math.max(total, 1)).toFixed(2); const avgVariance = (data.reduce((acc, val) => acc + (val.metrics?.variance ?? 0), 0) / Math.max(total, 1)).toFixed(3); const avgStability = (data.reduce((acc, val) => acc + (val.metrics?.stability_index ?? 0), 0) / Math.max(total, 1)).toFixed(3); summaryContainer.innerHTML = `

Runs insgesamt

${total}

Ø Latenz

${avgLatency} ms

Ø Varianz

${avgVariance}

Ø Stabilität

${avgStability}

`; }