This commit is contained in:
@@ -170,21 +170,60 @@ export function FrameTimeline({ fps, comments, annotations = [], videoRef, onSee
|
||||
isDragging.current = false;
|
||||
}, []);
|
||||
|
||||
// ── Touch scrubbing ──────────────────────────────────────────────────────
|
||||
const getFrameFromTouch = useCallback(
|
||||
(touch: Touch): number => {
|
||||
const canvas = canvasRef.current;
|
||||
if (!canvas || totalFrames === 0) return 0;
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
const x = Math.max(0, Math.min(touch.clientX - rect.left, rect.width));
|
||||
return Math.round((x / rect.width) * totalFrames);
|
||||
},
|
||||
[totalFrames]
|
||||
);
|
||||
|
||||
const handleTouchStart = useCallback(
|
||||
(e: React.TouchEvent<HTMLCanvasElement>) => {
|
||||
e.preventDefault();
|
||||
const touch = e.touches[0];
|
||||
if (!touch) return;
|
||||
isDragging.current = true;
|
||||
onSeek(getFrameFromTouch(touch));
|
||||
},
|
||||
[getFrameFromTouch, onSeek]
|
||||
);
|
||||
|
||||
const handleTouchMove = useCallback(
|
||||
(e: TouchEvent) => {
|
||||
if (!isDragging.current) return;
|
||||
e.preventDefault();
|
||||
const touch = e.touches[0];
|
||||
if (!touch) return;
|
||||
onSeek(getFrameFromTouch(touch));
|
||||
},
|
||||
[getFrameFromTouch, onSeek]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener("mousemove", handleMouseMove);
|
||||
window.addEventListener("mouseup", handleMouseUp);
|
||||
window.addEventListener("touchmove", handleTouchMove, { passive: false });
|
||||
window.addEventListener("touchend", handleMouseUp);
|
||||
return () => {
|
||||
window.removeEventListener("mousemove", handleMouseMove);
|
||||
window.removeEventListener("mouseup", handleMouseUp);
|
||||
window.removeEventListener("touchmove", handleTouchMove);
|
||||
window.removeEventListener("touchend", handleMouseUp);
|
||||
};
|
||||
}, [handleMouseMove, handleMouseUp]);
|
||||
}, [handleMouseMove, handleMouseUp, handleTouchMove]);
|
||||
|
||||
return (
|
||||
<canvas
|
||||
ref={canvasRef}
|
||||
className="frame-timeline w-full cursor-ew-resize"
|
||||
style={{ height: 48 }}
|
||||
style={{ height: 48, touchAction: "none" }}
|
||||
onMouseDown={handleMouseDown}
|
||||
onTouchStart={handleTouchStart}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user