From 113b8ff758fbaad92783362d5cc2fd8031f5cba5 Mon Sep 17 00:00:00 2001 From: dschlueter Date: Mon, 6 Apr 2026 18:43:43 +0200 Subject: [PATCH] Fix: timsort snap params, passive resize, drawPath optimization, aria-live, readUrlState labels --- sorting_visualization.html | 63 ++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/sorting_visualization.html b/sorting_visualization.html index ee4254d..46e0d1f 100644 --- a/sorting_visualization.html +++ b/sorting_visualization.html @@ -197,7 +197,7 @@

- Sortier-Algorithmen v0.2.5 + Sortier-Algorithmen v0.2.6

Interaktive Visualisierung mit schrittweiser Animation

@@ -359,8 +359,8 @@
-
 
-
 
+
 
+
 
@@ -381,7 +381,7 @@
- 0 / 0 + 0 / 0 @@ -1687,6 +1687,8 @@ function buildSteps(algoName) { case 'timsort': { const n = arr.length; const RUN = 32; + const runMeta = { runs: [] }; + for (let r = 0; r < n; r += RUN) runMeta.runs.push(r); // Phase 1: Insertion Sort auf Runs der Größe RUN for (let start = 0; start < n; start += RUN) { const end = Math.min(start + RUN, n); @@ -1695,11 +1697,11 @@ function buildSteps(algoName) { let j = i - 1; while (j >= start) { compares++; - snap('compare', [j, j + 1]); + snap('compare', [j, j + 1], null, runMeta); if (arr[j] > key) { arr[j + 1] = arr[j]; moves++; - snap('move', [j + 1]); + snap('move', [j + 1], null, runMeta); j--; } else { break; @@ -1708,7 +1710,7 @@ function buildSteps(algoName) { if (arr[j + 1] !== key) { arr[j + 1] = key; moves++; - snap('move', [j + 1]); + snap('move', [j + 1], null, runMeta); } } } @@ -2109,6 +2111,24 @@ function drawBars(arr, highlights, allSorted, meta, connectedPair) { ctx.textAlign = 'center'; ctx.textBaseline = 'bottom'; + // Reusable rounded-rect path helper (defined once, called per bar) + function drawRoundedRectPath(ctx, px, py, pw, ph, pr) { + if (pr > 0 && ph > pr * 2) { + ctx.beginPath(); + ctx.moveTo(px + pr, py); + ctx.lineTo(px + pw - pr, py); + ctx.quadraticCurveTo(px + pw, py, px + pw, py + pr); + ctx.lineTo(px + pw, py + ph); + ctx.lineTo(px, py + ph); + ctx.lineTo(px, py + pr); + ctx.quadraticCurveTo(px, py, px + pr, py); + ctx.closePath(); + } else { + ctx.beginPath(); + ctx.rect(px, py, pw, ph); + } + } + for (let i = 0; i < n; i++) { const val = arr[i]; const barH = Math.max(2, (val / maxVal) * areaH); @@ -2126,41 +2146,24 @@ function drawBars(arr, highlights, allSorted, meta, connectedPair) { else if (t === 'move') color = COLORS.move; } - // Rounded-top bar path generator const r = Math.min(3, barW / 4); - function drawPath() { - if (r > 0 && barH > r * 2) { - ctx.beginPath(); - ctx.moveTo(x + r, y); - ctx.lineTo(x + barW - r, y); - ctx.quadraticCurveTo(x + barW, y, x + barW, y + r); - ctx.lineTo(x + barW, y + barH); - ctx.lineTo(x, y + barH); - ctx.lineTo(x, y + r); - ctx.quadraticCurveTo(x, y, x + r, y); - ctx.closePath(); - } else { - ctx.beginPath(); - ctx.rect(x, y, barW, barH); - } - } - // FIX: Glow-Effekt VOR dem normalen Balken zeichnen + // Glow-Effekt if (highlights[i] && !allSorted) { ctx.save(); ctx.fillStyle = color; ctx.shadowColor = color; ctx.shadowBlur = 14; ctx.globalAlpha = 0.35; - drawPath(); + drawRoundedRectPath(ctx, x, y, barW, barH, r); ctx.fill(); ctx.restore(); } - // Haupt-Balken zeichnen + // Haupt-Balken ctx.fillStyle = color; ctx.globalAlpha = 1; - drawPath(); + drawRoundedRectPath(ctx, x, y, barW, barH, r); ctx.fill(); // Value label @@ -2929,6 +2932,8 @@ function readUrlState() { if (params.has('preset')) $presetSelect.value = params.get('preset'); if (params.has('size')) $sizeSlider.value = Math.max(5, Math.min(200, parseInt(params.get('size'), 10) || 50)); if (params.has('speed')) $speedSlider.value = Math.max(1, Math.min(100, parseInt(params.get('speed'), 10) || 50)); + updateSizeLabel(); + updateSpeedLabel(); } function writeUrlState() { @@ -2961,7 +2966,7 @@ function handleResize() { } // Use window resize to avoid feedback loops (ResizeObserver on canvas parent causes blowout) -window.addEventListener('resize', handleResize); +window.addEventListener('resize', handleResize, { passive: true }); // ================================================================ // Initialization