Region processing
This commit is contained in:
@ -5,11 +5,26 @@
|
||||
buffer: AudioBuffer | null;
|
||||
color?: string;
|
||||
playbackPosition?: number;
|
||||
selectionStart?: number | null;
|
||||
selectionEnd?: number | null;
|
||||
onselectionchange?: (start: number | null, end: number | null) => void;
|
||||
onclick?: () => void;
|
||||
}
|
||||
|
||||
let { buffer, color = '#646cff', playbackPosition = 0, onclick }: Props = $props();
|
||||
let {
|
||||
buffer,
|
||||
color = '#646cff',
|
||||
playbackPosition = 0,
|
||||
selectionStart = null,
|
||||
selectionEnd = null,
|
||||
onselectionchange,
|
||||
onclick
|
||||
}: Props = $props();
|
||||
|
||||
let canvas: HTMLCanvasElement;
|
||||
let isDragging = $state(false);
|
||||
let dragStartX = $state(0);
|
||||
let hasMoved = $state(false);
|
||||
|
||||
onMount(() => {
|
||||
const resizeObserver = new ResizeObserver(() => {
|
||||
@ -28,6 +43,8 @@
|
||||
buffer;
|
||||
color;
|
||||
playbackPosition;
|
||||
selectionStart;
|
||||
selectionEnd;
|
||||
draw();
|
||||
});
|
||||
|
||||
@ -37,12 +54,120 @@
|
||||
canvas.height = parent.clientHeight;
|
||||
}
|
||||
|
||||
function handleClick() {
|
||||
function handleClick(event: MouseEvent) {
|
||||
if (hasMoved) return;
|
||||
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
const x = event.clientX - rect.left;
|
||||
|
||||
if (buffer && selectionStart !== null && selectionEnd !== null) {
|
||||
const selStart = Math.min(selectionStart, selectionEnd);
|
||||
const selEnd = Math.max(selectionStart, selectionEnd);
|
||||
const width = canvas.width;
|
||||
const startX = (selStart / buffer.length) * width;
|
||||
const endX = (selEnd / buffer.length) * width;
|
||||
|
||||
if (x < startX || x > endX) {
|
||||
if (onselectionchange) {
|
||||
onselectionchange(null, null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (onclick) {
|
||||
onclick();
|
||||
}
|
||||
}
|
||||
|
||||
function handleMouseDown(event: MouseEvent) {
|
||||
if (!buffer) return;
|
||||
|
||||
isDragging = true;
|
||||
hasMoved = false;
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
dragStartX = event.clientX - rect.left;
|
||||
|
||||
const sample = Math.floor((dragStartX / canvas.width) * buffer.length);
|
||||
if (onselectionchange) {
|
||||
onselectionchange(sample, sample);
|
||||
}
|
||||
}
|
||||
|
||||
function handleMouseMove(event: MouseEvent) {
|
||||
if (!isDragging || !buffer) return;
|
||||
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
const currentX = event.clientX - rect.left;
|
||||
const clampedX = Math.max(0, Math.min(canvas.width, currentX));
|
||||
|
||||
if (Math.abs(clampedX - dragStartX) > 2) {
|
||||
hasMoved = true;
|
||||
}
|
||||
|
||||
const endSample = Math.floor((clampedX / canvas.width) * buffer.length);
|
||||
|
||||
if (onselectionchange && selectionStart !== null) {
|
||||
onselectionchange(selectionStart, endSample);
|
||||
}
|
||||
}
|
||||
|
||||
function handleMouseUp() {
|
||||
if (isDragging && selectionStart !== null && selectionEnd !== null) {
|
||||
if (Math.abs(selectionEnd - selectionStart) < buffer!.sampleRate * 0.01) {
|
||||
if (onselectionchange) {
|
||||
onselectionchange(null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
isDragging = false;
|
||||
}
|
||||
|
||||
function handleTouchStart(event: TouchEvent) {
|
||||
if (!buffer || event.touches.length !== 1) return;
|
||||
|
||||
event.preventDefault();
|
||||
isDragging = true;
|
||||
hasMoved = false;
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
dragStartX = event.touches[0].clientX - rect.left;
|
||||
|
||||
const sample = Math.floor((dragStartX / canvas.width) * buffer.length);
|
||||
if (onselectionchange) {
|
||||
onselectionchange(sample, sample);
|
||||
}
|
||||
}
|
||||
|
||||
function handleTouchMove(event: TouchEvent) {
|
||||
if (!isDragging || !buffer || event.touches.length !== 1) return;
|
||||
|
||||
event.preventDefault();
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
const currentX = event.touches[0].clientX - rect.left;
|
||||
const clampedX = Math.max(0, Math.min(canvas.width, currentX));
|
||||
|
||||
if (Math.abs(clampedX - dragStartX) > 2) {
|
||||
hasMoved = true;
|
||||
}
|
||||
|
||||
const endSample = Math.floor((clampedX / canvas.width) * buffer.length);
|
||||
|
||||
if (onselectionchange && selectionStart !== null) {
|
||||
onselectionchange(selectionStart, endSample);
|
||||
}
|
||||
}
|
||||
|
||||
function handleTouchEnd() {
|
||||
if (isDragging && selectionStart !== null && selectionEnd !== null) {
|
||||
if (Math.abs(selectionEnd - selectionStart) < buffer!.sampleRate * 0.01) {
|
||||
if (onselectionchange) {
|
||||
onselectionchange(null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
isDragging = false;
|
||||
}
|
||||
|
||||
function draw() {
|
||||
if (!canvas) return;
|
||||
|
||||
@ -102,6 +227,25 @@
|
||||
}
|
||||
}
|
||||
|
||||
if (buffer && selectionStart !== null && selectionEnd !== null) {
|
||||
const selStart = Math.min(selectionStart, selectionEnd);
|
||||
const selEnd = Math.max(selectionStart, selectionEnd);
|
||||
const startX = (selStart / buffer.length) * width;
|
||||
const endX = (selEnd / buffer.length) * width;
|
||||
|
||||
ctx.fillStyle = 'rgba(100, 108, 255, 0.2)';
|
||||
ctx.fillRect(startX, 0, endX - startX, height);
|
||||
|
||||
ctx.strokeStyle = 'rgba(100, 108, 255, 0.8)';
|
||||
ctx.lineWidth = 2;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(startX, 0);
|
||||
ctx.lineTo(startX, height);
|
||||
ctx.moveTo(endX, 0);
|
||||
ctx.lineTo(endX, height);
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
if (playbackPosition >= 0 && buffer) {
|
||||
const duration = buffer.length / buffer.sampleRate;
|
||||
const x = (playbackPosition / duration) * width;
|
||||
@ -116,7 +260,17 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<canvas bind:this={canvas} onclick={handleClick} style="cursor: pointer;"></canvas>
|
||||
<svelte:window onmouseup={handleMouseUp} ontouchend={handleTouchEnd} />
|
||||
|
||||
<canvas
|
||||
bind:this={canvas}
|
||||
onclick={handleClick}
|
||||
onmousedown={handleMouseDown}
|
||||
onmousemove={handleMouseMove}
|
||||
ontouchstart={handleTouchStart}
|
||||
ontouchmove={handleTouchMove}
|
||||
style="cursor: {isDragging ? 'text' : 'pointer'}; touch-action: none;"
|
||||
></canvas>
|
||||
|
||||
<style>
|
||||
canvas {
|
||||
|
||||
Reference in New Issue
Block a user