(function () { "use strict"; // Tabellen sortieren (Klick auf th[data-sort]); leere Werte stehen immer am Ende. document.querySelectorAll("table.sortable").forEach(function (table) { table.querySelectorAll("th[data-sort]").forEach(function (th) { th.addEventListener("click", function () { var index = Array.prototype.indexOf.call(th.parentNode.children, th); var numeric = th.dataset.sort === "num"; var dir = th.getAttribute("aria-sort") === "descending" ? "ascending" : "descending"; table.querySelectorAll("th[aria-sort]").forEach(function (other) { other.removeAttribute("aria-sort"); }); th.setAttribute("aria-sort", dir); var body = table.tBodies[0]; var rows = Array.prototype.slice.call(body.rows); function valueOf(row) { var cell = row.cells[index]; return cell.dataset.value !== undefined ? cell.dataset.value : cell.textContent.trim(); } rows.sort(function (a, b) { var va = valueOf(a), vb = valueOf(b); if (numeric) { var na = va === "" ? null : parseFloat(va); var nb = vb === "" ? null : parseFloat(vb); if (na === null && nb === null) return 0; if (na === null) return 1; if (nb === null) return -1; return dir === "ascending" ? na - nb : nb - na; } return dir === "ascending" ? va.localeCompare(vb, "de") : vb.localeCompare(va, "de"); }); rows.forEach(function (row) { body.appendChild(row); }); }); }); }); // Zeilen nach Reasoning-Modus filtern. Die Schalter stehen nur im HTML, wenn eine Tabelle mehrere Modi // zeigt; ohne JavaScript bleiben alle Zeilen sichtbar. document.querySelectorAll("[data-filter-table]").forEach(function (group) { var table = document.getElementById(group.dataset.filterTable); if (!table || !table.tBodies[0]) return; var buttons = Array.prototype.slice.call(group.querySelectorAll("[data-reasoning-filter]")); buttons.forEach(function (button) { button.addEventListener("click", function () { var wanted = button.dataset.reasoningFilter; buttons.forEach(function (other) { var picked = other === button; other.classList.toggle("active", picked); other.setAttribute("aria-pressed", picked ? "true" : "false"); }); Array.prototype.slice.call(table.tBodies[0].rows).forEach(function (row) { row.hidden = wanted !== "all" && (row.dataset.reasoning || "default") !== wanted; }); }); }); }); // Läufe für den Vergleich auswählen (mindestens 2). var picks = document.querySelectorAll(".compare-pick"); var button = document.getElementById("compare-button"); var hidden = document.getElementById("compare-runs"); picks.forEach(function (box) { box.addEventListener("change", function () { var ids = Array.prototype.filter.call(picks, function (p) { return p.checked; }).map(function (p) { return p.value; }); hidden.value = ids.join(","); button.disabled = ids.length < 2; }); }); // Bestätigung vor gefährlichen Aktionen (Formulare mit data-confirm). document.querySelectorAll("form[data-confirm]").forEach(function (form) { form.addEventListener("submit", function (event) { if (!window.confirm(form.dataset.confirm)) event.preventDefault(); }); }); if (typeof Chart === "undefined") return; var css = getComputedStyle(document.documentElement); function token(name) { return css.getPropertyValue(name).trim(); } var ink = token("--ink"), ink2 = token("--ink-2"), muted = token("--muted"); var grid = token("--grid"), axisColor = token("--axis"), surface = token("--surface"); var series = [token("--series-1"), token("--series-2"), token("--series-3")]; var fontFamily = 'system-ui, -apple-system, "Segoe UI", sans-serif'; Chart.defaults.font.family = fontFamily; Chart.defaults.color = ink2; function axis(title, extra) { var config = { grid: { color: grid, drawTicks: false }, border: { color: axisColor }, ticks: { color: muted, padding: 6 } }; if (title) config.title = { display: true, text: title, color: ink2 }; return Object.assign(config, extra || {}); } function readJson(id) { var el = document.getElementById(id); return el ? JSON.parse(el.textContent) : null; } // Wert direkt am Balkenende (nur für die einreihige Übersicht). var barValueLabels = { id: "barValueLabels", afterDatasetsDraw: function (chart) { var meta = chart.getDatasetMeta(0); var ctx = chart.ctx; ctx.save(); ctx.fillStyle = ink; ctx.font = "12px " + fontFamily; ctx.textBaseline = "middle"; meta.data.forEach(function (bar, i) { var value = chart.data.datasets[0].data[i]; if (value !== null && value !== undefined) ctx.fillText(value.toFixed(1), bar.x + 6, bar.y); }); ctx.restore(); } }; var overview = readJson("overview-data"); if (overview && overview.bars.length) { new Chart(document.getElementById("bar-chart"), { type: "bar", data: { labels: overview.bars.map(function (b) { return b.label; }), datasets: [{ label: "Gesamtscore", data: overview.bars.map(function (b) { return b.value; }), backgroundColor: series[0], borderRadius: 4, borderSkipped: "start", barPercentage: 0.8, categoryPercentage: 0.9, maxBarThickness: 18 }] }, options: { indexAxis: "y", maintainAspectRatio: false, animation: false, layout: { padding: { right: 40 } }, scales: { x: axis("Score (0–100)", { min: 0, max: 100 }), y: axis(null, { grid: { display: false } }) }, plugins: { legend: { display: false }, tooltip: { callbacks: { label: function (c) { return "Gesamt: " + c.parsed.x.toFixed(1); } } } } }, plugins: [barValueLabels] }); } if (overview && overview.scatter.length) { new Chart(document.getElementById("scatter-chart"), { type: "scatter", data: { datasets: [{ label: "Modellvarianten", data: overview.scatter, backgroundColor: series[0], borderColor: surface, borderWidth: 2, pointRadius: 5, pointHoverRadius: 7, pointHitRadius: 12 }] }, options: { maintainAspectRatio: false, animation: false, scales: { x: axis("Generierung (Tokens/s)", { beginAtZero: true }), y: axis("Gesamtscore", { min: 0, max: 100 }) }, plugins: { legend: { display: false }, tooltip: { callbacks: { label: function (c) { return c.raw.label + ": " + c.raw.y.toFixed(1) + " Punkte, " + c.raw.x.toFixed(1) + " t/s"; } } } } } }); } var categories = readJson("category-data"); if (categories && categories.series.length) { new Chart(document.getElementById("category-chart"), { type: "bar", data: { labels: categories.labels, datasets: categories.series.map(function (s, i) { return { label: s.label, data: s.values, backgroundColor: series[i], borderColor: surface, borderWidth: { top: 1, bottom: 1, right: 2 }, borderRadius: 4, borderSkipped: "start", barPercentage: 0.9, categoryPercentage: 0.8, maxBarThickness: 16 }; }) }, options: { indexAxis: "y", maintainAspectRatio: false, animation: false, scales: { x: axis("Score (0–100)", { min: 0, max: 100 }), y: axis(null, { grid: { display: false } }) }, plugins: { legend: { display: true, position: "top", align: "start", labels: { usePointStyle: true, pointStyle: "rectRounded", color: ink2 } }, tooltip: { callbacks: { label: function (c) { return c.dataset.label + ": " + (c.parsed.x === null ? "–" : c.parsed.x.toFixed(1)); } } } } } }); } })();