From 01a48403936cf1d3c593216c49cbf803716e1bd4 Mon Sep 17 00:00:00 2001 From: dschlueter Date: Mon, 6 Apr 2026 19:58:05 +0200 Subject: [PATCH] Add slider hover tooltip and CSV/paste import for custom arrays --- sorting_visualization.html | 101 ++++++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 2 deletions(-) diff --git a/sorting_visualization.html b/sorting_visualization.html index 263b931..22ae361 100644 --- a/sorting_visualization.html +++ b/sorting_visualization.html @@ -73,6 +73,24 @@ cursor: pointer; touch-action: none; } + + /* ── Slider Tooltip ── */ + .slider-tooltip { + position: fixed; + background: var(--c-surface2, #1e2235); + border: 1px solid var(--c-border, #2a2d3d); + border-radius: 6px; + padding: 3px 8px; + font-size: 11px; + font-family: monospace; + color: var(--c-accent, #4a7cff); + pointer-events: none; + opacity: 0; + transition: opacity 0.15s ease; + z-index: 9999; + white-space: nowrap; + } + .slider-tooltip.visible { opacity: 1; } input[type="range"]::-webkit-slider-runnable-track { height: 6px; background: var(--c-surface2); @@ -197,7 +215,7 @@

- Sortier-Algorithmen v0.2.8 + Sortier-Algorithmen v0.2.9

Interaktive Visualisierung mit schrittweiser Animation

@@ -275,10 +293,14 @@
- + @@ -316,6 +338,9 @@
+ +
+
@@ -809,6 +834,8 @@ const $algoSelect = document.getElementById('algoSelect'); const $presetSelect = document.getElementById('presetSelect'); const $customArray = document.getElementById('customArray'); const $btnClearCustom = document.getElementById('btnClearCustom'); +const $btnPasteCustom = document.getElementById('btnPasteCustom'); +const $customArrayCount = document.getElementById('customArrayCount'); const $sizeSlider = document.getElementById('sizeSlider'); const $speedSlider = document.getElementById('speedSlider'); const $threadSlider = document.getElementById('threadSlider'); @@ -2840,14 +2867,41 @@ $presetSelect.addEventListener('change', function() { $customArray.addEventListener('change', function() { if (!isRunning) doReset(); + updateCustomArrayCount(); }); +$customArray.addEventListener('input', function() { + updateCustomArrayCount(); +}); + +function updateCustomArrayCount() { + const text = $customArray.value.trim(); + if (!text) { + $customArrayCount.textContent = ''; + return; + } + const values = text.split(/[,;\s\n\t]+/).filter(function(v) { return v !== '' && !isNaN(parseFloat(v)); }); + $customArrayCount.textContent = values.length + ' Wert' + (values.length === 1 ? '' : 'e'); +} + $btnClearCustom.addEventListener('click', function() { $customArray.value = ''; + $customArrayCount.textContent = ''; $sizeSlider.disabled = false; if (!isRunning) doReset(); }); +$btnPasteCustom.addEventListener('click', async function() { + try { + const text = await navigator.clipboard.readText(); + $customArray.value = text.replace(/[\r\n]+/g, ', ').replace(/,/g, ', '); + updateCustomArrayCount(); + $customArray.dispatchEvent(new Event('change')); + } catch (e) { + // Clipboard API not available or permission denied + } +}); + $btnTheme.addEventListener('click', function() { const isDark = document.documentElement.classList.contains('dark'); const newTheme = !isDark; @@ -2922,6 +2976,49 @@ makeTouchSlider($sizeSlider); makeTouchSlider($speedSlider); makeTouchSlider($threadSlider); +// ================================================================ +// Slider Tooltip on Hover +// ================================================================ + +const $sliderTooltip = document.getElementById('sliderTooltip'); +const $allSliders = [$sizeSlider, $speedSlider, $threadSlider].filter(Boolean); + +$allSliders.forEach(function(slider) { + slider.addEventListener('mouseenter', function() { + updateSliderTooltip(slider); + $sliderTooltip.classList.add('visible'); + }); + slider.addEventListener('mousemove', function(e) { + updateSliderTooltipPosition(e.clientX, e.clientY); + }); + slider.addEventListener('mouseleave', function() { + $sliderTooltip.classList.remove('visible'); + }); +}); + +function updateSliderTooltip(slider) { + if (slider.id === 'sizeSlider') { + $sliderTooltip.textContent = slider.value + ' Elemente'; + } else if (slider.id === 'speedSlider') { + const ms = Math.round(1000 * Math.pow(0.001, (parseInt(slider.value) - 1) / 99)); + $sliderTooltip.textContent = ms + ' ms/Schritt'; + } else if (slider.id === 'threadSlider') { + $sliderTooltip.textContent = slider.value + ' Thread(s)'; + } +} + +function updateSliderTooltipPosition(x, y) { + const tw = $sliderTooltip.offsetWidth; + const th = $sliderTooltip.offsetHeight; + let left = x - tw / 2; + let top = y - th - 12; + if (left < 8) left = 8; + if (left + tw > window.innerWidth - 8) left = window.innerWidth - tw - 8; + if (top < 8) top = y + 16; + $sliderTooltip.style.left = left + 'px'; + $sliderTooltip.style.top = top + 'px'; +} + // ================================================================ // URL State Persistence // ================================================================