import { useState, useEffect } from 'react'; import { MediaSet } from './generated/media_set'; import { Frames, VideoPosition } from './App'; import { WaveformCanvas } from './WaveformCanvas'; import { HudCanvas, EmptySelectionAction, SelectionChangeEvent, } from './HudCanvas'; import { SelectionMode } from './HudCanvasState'; import { Observable } from 'rxjs'; export interface Selection { start: number; end: number; } interface Props { peaks: Observable; mediaSet: MediaSet; position: VideoPosition; viewport: Frames; onSelectionChange: (selectionState: SelectionChangeEvent) => void; } export const CanvasLogicalWidth = 2_000; export const CanvasLogicalHeight = 500; export const Overview: React.FC = ({ peaks, mediaSet, position, viewport, onSelectionChange, }: Props) => { const [selectedPixels, setSelectedPixels] = useState({ start: 0, end: 0 }); const [positionPixels, setPositionPixels] = useState(0); // side effects // convert viewport from frames to canvas pixels. // TODO: consider an adapter component to handle this. useEffect(() => { setSelectedPixels({ start: Math.round( (viewport.start / mediaSet.audioFrames) * CanvasLogicalWidth ), end: Math.round( (viewport.end / mediaSet.audioFrames) * CanvasLogicalWidth ), }); }, [viewport, mediaSet]); // convert position from frames to canvas pixels: // TODO: consider an adapter component to handle this. useEffect(() => { const ratio = position.currentTime / (mediaSet.audioFrames / mediaSet.audioSampleRate); setPositionPixels(Math.round(ratio * CanvasLogicalWidth)); frames; }, [mediaSet, position]); // handlers // convert selection change from canvas pixels to frames, and trigger callback. const handleSelectionChange = (selectionState: SelectionChangeEvent) => { const { mode, prevMode, selection: { start, end }, } = selectionState; if (mode != SelectionMode.Normal || prevMode == SelectionMode.Normal) { return; } onSelectionChange({ ...selectionState, selection: { start: Math.round((start / CanvasLogicalWidth) * mediaSet.audioFrames), end: Math.round((end / CanvasLogicalWidth) * mediaSet.audioFrames), }, }); }; // render component const hudStyles = { borderLineWidth: 4, borderStrokeStyle: 'red', positionLineWidth: 4, positionStrokeStyle: 'red', hoverPositionStrokeStyle: 'transparent', }; return ( <>
); };