scrollbalken für wellenform
This commit is contained in:
@@ -288,6 +288,10 @@ h1 { margin:0 0 6px; font-size:28px; }
|
||||
.playhead { position:absolute; top:0; bottom:0; width:2px; margin-left:-1px; background:#ffcc33; box-shadow:0 0 5px #000; z-index:4; pointer-events:none; }
|
||||
.handle { position:absolute; top:0; bottom:0; width:18px; margin-left:-9px; cursor:ew-resize; z-index:3; touch-action:none; }
|
||||
.handle::after { content:""; position:absolute; left:7px; top:0; bottom:0; width:4px; background:#fff; border-radius:2px; box-shadow:0 0 5px #000; }
|
||||
.view-scroll { position:relative; width:100%; height:14px; margin-top:5px; background:#292929; border-radius:7px; overflow:hidden; touch-action:none; cursor:grab; }
|
||||
.view-scroll-thumb { position:absolute; top:2px; bottom:2px; left:0; min-width:14px; background:#777; border-radius:5px; cursor:grab; touch-action:none; }
|
||||
.view-scroll-thumb:hover { background:#999; }
|
||||
.view-scroll-thumb.dragging { background:#aaa; cursor:grabbing; }
|
||||
.time-row { display:flex; justify-content:space-between; margin-top:8px; color:#aaa; font-size:14px; }
|
||||
.controls { display:flex; flex-wrap:wrap; gap:8px; align-items:center; margin-top:18px; }
|
||||
button, a.button { border:0; border-radius:6px; padding:11px 16px; background:#333; color:#fff; cursor:pointer; text-decoration:none; font-size:15px; }
|
||||
@@ -314,6 +318,8 @@ button:disabled { opacity:.45; cursor:not-allowed; }
|
||||
body { padding:12px; }
|
||||
.editor { padding:12px; }
|
||||
.wave-wrap { height:180px; }
|
||||
.view-scroll { height:18px; }
|
||||
.view-scroll-thumb { min-width:28px; }
|
||||
.zoom { width:100%; margin-left:0; }
|
||||
.values { grid-template-columns:1fr; }
|
||||
.position { width:100%; margin-left:0; }
|
||||
@@ -335,6 +341,9 @@ button:disabled { opacity:.45; cursor:not-allowed; }
|
||||
<div class="handle" id="startHandle" title="Anfang verschieben"></div>
|
||||
<div class="handle" id="endHandle" title="Ende verschieben"></div>
|
||||
</div>
|
||||
<div class="view-scroll" id="viewScroll" aria-label="Sichtbaren Bereich verschieben">
|
||||
<div class="view-scroll-thumb" id="viewScrollThumb"></div>
|
||||
</div>
|
||||
<div class="time-row">
|
||||
<span id="viewStart">00:00:00</span>
|
||||
<span id="viewEnd">{{ duration }}</span>
|
||||
@@ -392,6 +401,12 @@ const endHandle = document.getElementById('endHandle');
|
||||
const selection = document.getElementById('selection');
|
||||
const playhead = document.getElementById('playhead');
|
||||
const audio = document.getElementById('audio');
|
||||
const viewScroll = document.getElementById('viewScroll');
|
||||
const viewScrollThumb = document.getElementById('viewScrollThumb');
|
||||
let scrollbarDragging = false;
|
||||
let scrollbarPointerId = null;
|
||||
let scrollbarStartX = 0;
|
||||
let scrollbarStartView = 0;
|
||||
|
||||
function fmt(sec) {
|
||||
sec = Math.max(0, Math.round(sec));
|
||||
@@ -428,6 +443,14 @@ function render() {
|
||||
document.getElementById('viewStart').textContent = fmt(viewStart);
|
||||
document.getElementById('viewEnd').textContent = fmt(viewEnd);
|
||||
document.getElementById('zoomValue').textContent = 'Zoom: '+Math.round(zoom*100)+' %';
|
||||
|
||||
// The scrollbar thumb represents the currently visible part of the full recording.
|
||||
const visiblePercent = Math.max(0, Math.min(100, ((viewEnd-viewStart)/duration)*100));
|
||||
const offsetPercent = Math.max(0, Math.min(100-visiblePercent, (viewStart/duration)*100));
|
||||
viewScrollThumb.style.width = visiblePercent+'%';
|
||||
viewScrollThumb.style.left = offsetPercent+'%';
|
||||
viewScrollThumb.style.pointerEvents = zoom > 1 ? 'auto' : 'none';
|
||||
viewScrollThumb.classList.toggle('dragging', scrollbarDragging);
|
||||
renderPlayhead();
|
||||
}
|
||||
function renderPlayhead() {
|
||||
@@ -461,6 +484,60 @@ function resetZoom() {
|
||||
viewEnd = duration;
|
||||
render();
|
||||
}
|
||||
|
||||
function moveViewTo(newStart) {
|
||||
const span = viewEnd-viewStart;
|
||||
if (span >= duration) {
|
||||
viewStart = 0;
|
||||
viewEnd = duration;
|
||||
} else {
|
||||
viewStart = Math.max(0, Math.min(duration-span, newStart));
|
||||
viewEnd = viewStart+span;
|
||||
}
|
||||
render();
|
||||
}
|
||||
|
||||
viewScrollThumb.addEventListener('pointerdown', e => {
|
||||
if (zoom <= 1) return;
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
scrollbarDragging = true;
|
||||
scrollbarPointerId = e.pointerId;
|
||||
scrollbarStartX = e.clientX;
|
||||
scrollbarStartView = viewStart;
|
||||
viewScrollThumb.setPointerCapture(e.pointerId);
|
||||
render();
|
||||
});
|
||||
viewScrollThumb.addEventListener('pointermove', e => {
|
||||
if (!scrollbarDragging || e.pointerId !== scrollbarPointerId) return;
|
||||
const trackWidth = viewScroll.clientWidth;
|
||||
const thumbWidth = viewScrollThumb.offsetWidth;
|
||||
const movableWidth = Math.max(1, trackWidth-thumbWidth);
|
||||
const span = viewEnd-viewStart;
|
||||
const deltaPixels = e.clientX-scrollbarStartX;
|
||||
const deltaTime = (deltaPixels/movableWidth) * (duration-span);
|
||||
moveViewTo(scrollbarStartView+deltaTime);
|
||||
e.preventDefault();
|
||||
});
|
||||
function endScrollbarDrag(e) {
|
||||
if (!scrollbarDragging || e.pointerId !== scrollbarPointerId) return;
|
||||
scrollbarDragging = false;
|
||||
scrollbarPointerId = null;
|
||||
render();
|
||||
}
|
||||
viewScrollThumb.addEventListener('pointerup', endScrollbarDrag);
|
||||
viewScrollThumb.addEventListener('pointercancel', endScrollbarDrag);
|
||||
|
||||
// Clicking/touching the empty part of the scrollbar moves the visible window
|
||||
// so that the clicked position becomes its center.
|
||||
viewScroll.addEventListener('pointerdown', e => {
|
||||
if (zoom <= 1 || e.target === viewScrollThumb) return;
|
||||
e.preventDefault();
|
||||
const r = viewScroll.getBoundingClientRect();
|
||||
const ratio = Math.max(0, Math.min(1, (e.clientX-r.left)/r.width));
|
||||
const span = viewEnd-viewStart;
|
||||
moveViewTo(ratio*duration-span/2);
|
||||
});
|
||||
wave.addEventListener('wheel', e => {
|
||||
e.preventDefault();
|
||||
const factor = e.deltaY < 0 ? ZOOM_FACTOR : 1/ZOOM_FACTOR;
|
||||
|
||||
Reference in New Issue
Block a user