@@ -1,121 +0,0 @@
|
||||
import { useState, useCallback, useEffect } from "react"
|
||||
import type { ClipData, TrimConfig } from "../types"
|
||||
|
||||
interface TrimDragState {
|
||||
clipId: string
|
||||
direction: "left" | "right"
|
||||
startX: number
|
||||
originalTrim: TrimConfig
|
||||
originalDuration: number
|
||||
}
|
||||
|
||||
interface TrimPreviewState {
|
||||
clipId: string
|
||||
startTime: number
|
||||
endTime: number
|
||||
duration: number
|
||||
x: number
|
||||
y: number
|
||||
}
|
||||
|
||||
const MIN_TRIM_DURATION = 1
|
||||
|
||||
/**
|
||||
* 裁剪拖拽 Hook
|
||||
* 拖拽片段两端手柄调整入点/出点,实时显示预览
|
||||
*/
|
||||
export const useTrimDrag = (
|
||||
clips: ClipData[],
|
||||
pps: number,
|
||||
onClipTrim?: (clipId: string, trimConfig: TrimConfig, newDuration: number) => void,
|
||||
) => {
|
||||
const [trimDrag, setTrimDrag] = useState<TrimDragState | null>(null)
|
||||
const [trimPreview, setTrimPreview] = useState<TrimPreviewState | null>(null)
|
||||
|
||||
const handleTrimHandleMouseDown = useCallback(
|
||||
(e: React.MouseEvent, clipId: string, direction: "left" | "right") => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
const clip = clips.find((c) => c.id === clipId)
|
||||
if (!clip) return
|
||||
|
||||
const trim: TrimConfig = clip.trim_config ?? {
|
||||
start_time: 0,
|
||||
end_time: clip.duration,
|
||||
original_duration: clip.duration,
|
||||
}
|
||||
|
||||
setTrimDrag({
|
||||
clipId,
|
||||
direction,
|
||||
startX: e.clientX,
|
||||
originalTrim: { ...trim },
|
||||
originalDuration: clip.duration,
|
||||
})
|
||||
},
|
||||
[clips],
|
||||
)
|
||||
|
||||
/* ── 裁剪拖拽全局 mousemove/mouseup ── */
|
||||
useEffect(() => {
|
||||
if (!trimDrag) return
|
||||
|
||||
const handleMouseMove = (e: MouseEvent) => {
|
||||
const dx = e.clientX - trimDrag.startX
|
||||
const dtSec = dx / pps
|
||||
const clip = clips.find((c) => c.id === trimDrag.clipId)
|
||||
if (!clip) return
|
||||
|
||||
const origTrim = trimDrag.originalTrim
|
||||
const origDur = origTrim.original_duration ?? trimDrag.originalDuration
|
||||
let newStart = origTrim.start_time
|
||||
let newEnd = origTrim.end_time
|
||||
|
||||
if (trimDrag.direction === "left") {
|
||||
newStart = Math.max(0, Math.min(origTrim.start_time + dtSec, newEnd - MIN_TRIM_DURATION))
|
||||
} else {
|
||||
newEnd = Math.max(
|
||||
origTrim.start_time + MIN_TRIM_DURATION,
|
||||
Math.min(origTrim.end_time + dtSec, origDur),
|
||||
)
|
||||
}
|
||||
|
||||
const newDuration = Math.round((newEnd - newStart) * 10) / 10
|
||||
|
||||
setTrimPreview({
|
||||
clipId: trimDrag.clipId,
|
||||
startTime: Math.round(newStart * 10) / 10,
|
||||
endTime: Math.round(newEnd * 10) / 10,
|
||||
duration: newDuration,
|
||||
x: e.clientX,
|
||||
y: e.clientY,
|
||||
})
|
||||
}
|
||||
|
||||
const handleMouseUp = () => {
|
||||
if (trimPreview && trimPreview.clipId === trimDrag.clipId && onClipTrim) {
|
||||
const newTrim: TrimConfig = {
|
||||
start_time: trimPreview.startTime,
|
||||
end_time: trimPreview.endTime,
|
||||
original_duration: trimDrag.originalTrim.original_duration ?? trimDrag.originalDuration,
|
||||
}
|
||||
onClipTrim(trimDrag.clipId, newTrim, trimPreview.duration)
|
||||
}
|
||||
setTrimDrag(null)
|
||||
setTrimPreview(null)
|
||||
}
|
||||
|
||||
document.addEventListener("mousemove", handleMouseMove)
|
||||
document.addEventListener("mouseup", handleMouseUp)
|
||||
return () => {
|
||||
document.removeEventListener("mousemove", handleMouseMove)
|
||||
document.removeEventListener("mouseup", handleMouseUp)
|
||||
}
|
||||
}, [trimDrag, trimPreview, clips, pps, onClipTrim])
|
||||
|
||||
return {
|
||||
trimDrag,
|
||||
trimPreview,
|
||||
handleTrimHandleMouseDown,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user