Improve waveform selection behaviour
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Rob Watson 2021-12-13 05:10:07 +01:00
parent c8de6643e8
commit 34681821e4
2 changed files with 18 additions and 36 deletions

View File

@ -210,26 +210,26 @@ function App(): JSX.Element {
setPositionFromFrame(newViewport.start); setPositionFromFrame(newViewport.start);
}, },
[mediaSet, audio, video] [mediaSet, audio, video, selection]
); );
// handler called when the selection in the main waveform view is changed. // handler called when the selection in the main waveform view is changed.
const handleWaveformSelectionChange = useCallback( const handleWaveformSelectionChange = useCallback(
(selection: Frames) => { (newSelection: Frames) => {
setSelection(selection); setSelection(newSelection);
if (mediaSet == null) { if (mediaSet == null) {
return; return;
} }
// move playback position to start of selection // move playback position to start of selection
const ratio = selection.start / mediaSet.audioFrames; const ratio = newSelection.start / mediaSet.audioFrames;
const currentTime = const currentTime =
(mediaSet.audioFrames / mediaSet.audioSampleRate) * ratio; (mediaSet.audioFrames / mediaSet.audioSampleRate) * ratio;
audio.currentTime = currentTime; audio.currentTime = currentTime;
video.currentTime = currentTime; video.currentTime = currentTime;
}, },
[mediaSet, audio, video] [mediaSet, audio, video, selection]
); );
const handlePlay = useCallback(() => { const handlePlay = useCallback(() => {

View File

@ -71,30 +71,20 @@ export const Waveform: React.FC<Props> = ({
setPositionPixels(null); setPositionPixels(null);
return; return;
} }
const logicalPixelsPerFrame = const pixelsPerFrame = CanvasLogicalWidth / (viewport.end - viewport.start);
CanvasLogicalWidth / (viewport.end - viewport.start); const positionPixels = (frame - viewport.start) * pixelsPerFrame;
const positionPixels = (frame - viewport.start) * logicalPixelsPerFrame;
setPositionPixels(positionPixels); setPositionPixels(positionPixels);
}, [mediaSet, position, viewport]); }, [mediaSet, position, viewport]);
// update selectedPixels on viewport change // update selectedPixels on viewport change
useEffect(() => { useEffect(() => {
const start = frameToCanvasX(selectedFrames.start); const start = Math.max(frameToCanvasX(selectedFrames.start), 0);
const end = frameToCanvasX(selectedFrames.end); const end = Math.min(
frameToCanvasX(selectedFrames.end),
// more verbose than it has to be to make TypeScript happy CanvasLogicalWidth
if (start == null && end == null) { );
setSelectedPixels({ start: 0, end: 0 }); setSelectedPixels({ start, end });
} else if (start == null && end != null) { }, [viewport, selectedFrames]);
setSelectedPixels({ start: 0, end: end });
} else if (start != null && end == null) {
setSelectedPixels({ start: 0, end: CanvasLogicalWidth });
} else if (start != null && end != null) {
setSelectedPixels({ start, end });
} else {
console.error('unreachable');
}
}, [viewport]);
// handlers // handlers
@ -112,26 +102,18 @@ export const Waveform: React.FC<Props> = ({
setSelectedFrames(selectedFrames); setSelectedFrames(selectedFrames);
onSelectionChange(selectedFrames); onSelectionChange(selectedFrames);
}, },
[viewport] [viewport, selectedFrames]
); );
// helpers // helpers
const frameToCanvasX = useCallback( const frameToCanvasX = useCallback(
(frame: number): number | null => { (frame: number): number => {
if (mediaSet == null) {
return null;
}
if (frame < viewport.start || frame > viewport.end) {
return null;
}
const pixelsPerFrame = const pixelsPerFrame =
CanvasLogicalWidth / (viewport.end - viewport.start); CanvasLogicalWidth / (viewport.end - viewport.start);
return (frame - viewport.start) * pixelsPerFrame; return Math.round((frame - viewport.start) * pixelsPerFrame);
}, },
[mediaSet, viewport] [viewport]
); );
// render component // render component