diff --git a/frontend/src/Waveform.tsx b/frontend/src/Waveform.tsx index 845e251..32238b9 100644 --- a/frontend/src/Waveform.tsx +++ b/frontend/src/Waveform.tsx @@ -1,5 +1,6 @@ import { useEffect, useState, useRef, MouseEvent } from 'react'; -import { WaveformCanvas } from './WaveformCanvas'; +import { Waveform as WaveformOverview } from './Waveform/Overview'; +import { Canvas as WaveformCanvas } from './Waveform/Canvas'; type Props = { audioContext: AudioContext; @@ -19,18 +20,20 @@ type ZoomSettings = { const defaultZoomSettings: ZoomSettings = { startFrame: 0, endFrame: 0 }; +export const CanvasLogicalWidth = 2000; +export const CanvasLogicalHeight = 500; + export const Waveform: React.FC = ({ audioContext }: Props) => { const [audioFile, setAudioFile] = useState(null); const [currentTime, setCurrentTime] = useState(0); + // TODO: fix linter error const [audio, setAudio] = useState(new Audio()); const [zoomSettings, setZoomSettings] = useState(defaultZoomSettings); const [waveformPeaks, setWaveformPeaks] = useState(null); const [overviewPeaks, setOverviewPeaks] = useState(null); - const hudCanvasRef = useRef(null); - const canvasLogicalWidth = 2000; - const canvasLogicalHeight = 500; + // TODO: error handling const videoID = new URLSearchParams(window.location.search).get('video_id'); // helpers @@ -47,7 +50,7 @@ export const Waveform: React.FC = ({ audioContext }: Props) => { if (audioFile == null) { return 0; } - return Math.floor((x / canvasLogicalWidth) * audioFile.frames); + return Math.floor((x / CanvasLogicalWidth) * audioFile.frames); }; const secsToCanvasX = (canvasWidth: number, secs: number): number => { @@ -112,7 +115,7 @@ export const Waveform: React.FC = ({ audioContext }: Props) => { } const resp = await fetch( - `http://localhost:8888/api/peaks?video_id=${videoID}&start=${zoomSettings.startFrame}&end=${endFrame}&bins=${canvasLogicalWidth}` + `http://localhost:8888/api/peaks?video_id=${videoID}&start=${zoomSettings.startFrame}&end=${endFrame}&bins=${CanvasLogicalWidth}` ); const peaks = await resp.json(); console.log('respBody from peaks =', peaks); @@ -240,13 +243,10 @@ export const Waveform: React.FC = ({ audioContext }: Props) => { zIndex: 1, } as React.CSSProperties; - const overviewCanvasProps = { - width: '90%', - height: '90px', - margin: '0 auto', - display: 'block', - } as React.CSSProperties; + const overviewStyles = { ...wrapperProps, height: '90px' }; + // TODO: why is the margin needed? + const controlPanelStyles = { margin: '1em' } as React.CSSProperties; const clockTextAreaProps = { color: '#999', width: '400px' }; return ( @@ -255,35 +255,31 @@ export const Waveform: React.FC = ({ audioContext }: Props) => {
- - - - - - + style={overviewStyles} + > +
+ + + + + +
); }; diff --git a/frontend/src/WaveformCanvas.tsx b/frontend/src/Waveform/Canvas.tsx similarity index 70% rename from frontend/src/WaveformCanvas.tsx rename to frontend/src/Waveform/Canvas.tsx index a9d8b05..94be0c0 100644 --- a/frontend/src/WaveformCanvas.tsx +++ b/frontend/src/Waveform/Canvas.tsx @@ -1,17 +1,24 @@ -import { useEffect, useState, useRef, MouseEvent } from 'react'; +import { useEffect, useRef } from 'react'; +import { CanvasLogicalWidth, CanvasLogicalHeight } from '../Waveform'; -const maxPeakValue = 32768; +const maxPeakValue = 32_768; type Props = { peaks: number[][] | null; - logicalWidth: number; - logicalHeight: number; strokeStyle: string; fillStyle: string; style: React.CSSProperties; }; -export const WaveformCanvas: React.FC = (props: Props) => { +// Canvas is a generic component that renders a waveform to a canvas. +// +// Properties: +// +// peaks: a 2d array of uint16s representing the peak values. Each inner array length should match logicalWidth +// strokeStyle: waveform style +// fillStyle: background style +// style: React.CSSProperties applied to canvas element +export const Canvas: React.FC = (props: Props) => { const canvasRef = useRef(null); useEffect(() => { @@ -57,8 +64,8 @@ export const WaveformCanvas: React.FC = (props: Props) => { <> diff --git a/frontend/src/Waveform/Overview.tsx b/frontend/src/Waveform/Overview.tsx new file mode 100644 index 0000000..4fd5fd1 --- /dev/null +++ b/frontend/src/Waveform/Overview.tsx @@ -0,0 +1,58 @@ +import { useEffect, useRef } from 'react'; +import { Canvas as WaveformCanvas } from './Canvas'; +import { CanvasLogicalWidth, CanvasLogicalHeight } from '../Waveform'; + +type Props = { + peaks: number[][] | null; + style: React.CSSProperties; +}; + +export const Waveform: React.FC = (props: Props) => { + const hudCanvasRef = useRef(null); + + // handlers + + const handleMouseDown = () => { + console.log('mousedown'); + }; + + // render component + + const canvasStyles = { + width: '100%', + height: '100px', + margin: '0 auto', + display: 'block', + } as React.CSSProperties; + + const hudCanvasStyles = { + width: '100%', + height: '100%', + position: 'absolute', + top: 0, + left: 0, + right: 0, + bottom: 0, + zIndex: 1, + } as React.CSSProperties; + + return ( + <> +
+ + +
+ + ); +};