Skip to content

Commit 7029e72

Browse files
authored
Make canvas ref accessible on AudioVisualizer component (#4)
1 parent a92eddd commit 7029e72

File tree

4 files changed

+123
-87
lines changed

4 files changed

+123
-87
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@ import { AudioVisualizer } from 'react-audio-visualize';
1616

1717
const Visualizer = () => {
1818
const [blob, setBlob] = useState<Blob>();
19+
const visualizerRef = useRef<HTMLCanvasElement>(null)
1920

2021
// set blob somewhere in code
2122

2223
return (
2324
<div>
2425
{blob && (
2526
<AudioVisualizer
27+
ref={visualizerRef}
2628
blob={blob}
2729
width={500}
2830
height={75}
@@ -49,6 +51,7 @@ const Visualizer = () => {
4951
| **`barPlayedColor`** | Color for the bars that have been played | `"rgb(160, 198, 255)""` | Yes |
5052
| **`currentTime`** | Current time stamp till which the audio blob has been played. Visualized bars that fall before the current time will have `barPlayerColor`, while that ones that fall after will have `barColor` | N/A | Yes |
5153
| **`style`** | Custom styles that can be passed to the visualization canvas | N/A | Yes |
54+
| **`ref`** | A `ForwardedRef` for the `HTMLCanvasElement` | N/A | Yes |
5255

5356
---
5457

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "react-audio-visualize",
33
"private": false,
4-
"version": "1.0.0",
4+
"version": "1.1.0",
55
"license": "MIT",
66
"author": "",
77
"repository": {
@@ -65,7 +65,7 @@
6565
"vite-plugin-dts": "^2.3.0"
6666
},
6767
"peerDependencies": {
68-
"react": "^18.2.0",
69-
"react-dom": "^18.2.0"
68+
"react": ">=16.2.0",
69+
"react-dom": ">=16.2.0"
7070
}
7171
}
Lines changed: 113 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
1-
import { useRef, useState, type ReactElement } from "react";
2-
import { useEffect } from "react";
1+
import {
2+
useRef,
3+
useState,
4+
forwardRef,
5+
type ForwardedRef,
6+
type ForwardRefExoticComponent,
7+
type RefAttributes,
8+
useImperativeHandle,
9+
useEffect,
10+
} from "react";
311
import { type dataPoint } from "./types";
412
import { calculateBarData, draw } from "./utils";
513

@@ -45,93 +53,118 @@ interface Props {
4553
* Custome styles that can be passed to the visualization canvas
4654
*/
4755
style?: React.CSSProperties;
56+
/**
57+
* A `ForwardedRef` for the `HTMLCanvasElement`
58+
*/
59+
ref?: React.ForwardedRef<HTMLCanvasElement>;
4860
}
4961

50-
const AudioVisualizer: (props: Props) => ReactElement = ({
51-
blob,
52-
width,
53-
height,
54-
barWidth = 2,
55-
gap = 1,
56-
currentTime,
57-
style,
58-
backgroundColor = "transparent",
59-
barColor = "rgb(184, 184, 184)",
60-
barPlayedColor = "rgb(160, 198, 255)",
61-
}: Props) => {
62-
const canvasRef = useRef<HTMLCanvasElement>(null);
63-
const [data, setData] = useState<dataPoint[]>([]);
64-
const [duration, setDuration] = useState<number>(0);
65-
66-
useEffect(() => {
67-
const processBlob = async (): Promise<void> => {
68-
if (!canvasRef.current) return;
62+
const AudioVisualizer: ForwardRefExoticComponent<
63+
Props & RefAttributes<HTMLCanvasElement>
64+
> = forwardRef(
65+
(
66+
{
67+
blob,
68+
width,
69+
height,
70+
barWidth = 2,
71+
gap = 1,
72+
currentTime,
73+
style,
74+
backgroundColor = "transparent",
75+
barColor = "rgb(184, 184, 184)",
76+
barPlayedColor = "rgb(160, 198, 255)",
77+
}: Props,
78+
ref?: ForwardedRef<HTMLCanvasElement>
79+
) => {
80+
const canvasRef = useRef<HTMLCanvasElement>(null);
81+
const [data, setData] = useState<dataPoint[]>([]);
82+
const [duration, setDuration] = useState<number>(0);
6983

70-
if (!blob) {
71-
const barsData = Array.from({ length: 100 }, () => ({
72-
max: 0,
73-
min: 0,
74-
}));
75-
draw(
76-
barsData,
77-
canvasRef.current,
78-
barWidth,
79-
gap,
80-
backgroundColor,
81-
barColor,
82-
barPlayedColor
83-
);
84-
return;
85-
}
84+
useImperativeHandle<HTMLCanvasElement | null, HTMLCanvasElement | null>(
85+
ref,
86+
() => canvasRef.current,
87+
[]
88+
);
8689

87-
const audioBuffer = await blob.arrayBuffer();
88-
const audioContext = new AudioContext();
89-
await audioContext.decodeAudioData(audioBuffer, (buffer) => {
90+
useEffect(() => {
91+
const processBlob = async (): Promise<void> => {
9092
if (!canvasRef.current) return;
91-
setDuration(buffer.duration);
92-
const barsData = calculateBarData(buffer, height, width, barWidth, gap);
93-
setData(barsData);
94-
draw(
95-
barsData,
96-
canvasRef.current,
97-
barWidth,
98-
gap,
99-
backgroundColor,
100-
barColor,
101-
barPlayedColor
102-
);
103-
});
104-
};
10593

106-
processBlob();
107-
}, [blob, canvasRef.current]);
94+
if (!blob) {
95+
const barsData = Array.from({ length: 100 }, () => ({
96+
max: 0,
97+
min: 0,
98+
}));
99+
draw(
100+
barsData,
101+
canvasRef.current,
102+
barWidth,
103+
gap,
104+
backgroundColor,
105+
barColor,
106+
barPlayedColor
107+
);
108+
return;
109+
}
108110

109-
useEffect(() => {
110-
if (!canvasRef.current) return;
111+
const audioBuffer = await blob.arrayBuffer();
112+
const audioContext = new AudioContext();
113+
await audioContext.decodeAudioData(audioBuffer, (buffer) => {
114+
if (!canvasRef.current) return;
115+
setDuration(buffer.duration);
116+
const barsData = calculateBarData(
117+
buffer,
118+
height,
119+
width,
120+
barWidth,
121+
gap
122+
);
123+
setData(barsData);
124+
draw(
125+
barsData,
126+
canvasRef.current,
127+
barWidth,
128+
gap,
129+
backgroundColor,
130+
barColor,
131+
barPlayedColor
132+
);
133+
});
134+
};
111135

112-
draw(
113-
data,
114-
canvasRef.current,
115-
barWidth,
116-
gap,
117-
backgroundColor,
118-
barColor,
119-
barPlayedColor,
120-
currentTime,
121-
duration
136+
processBlob();
137+
}, [blob, canvasRef.current]);
138+
139+
useEffect(() => {
140+
if (!canvasRef.current) return;
141+
142+
draw(
143+
data,
144+
canvasRef.current,
145+
barWidth,
146+
gap,
147+
backgroundColor,
148+
barColor,
149+
barPlayedColor,
150+
currentTime,
151+
duration
152+
);
153+
}, [currentTime, duration]);
154+
155+
return (
156+
<canvas
157+
ref={canvasRef}
158+
width={width}
159+
height={height}
160+
style={{
161+
...style,
162+
}}
163+
/>
122164
);
123-
}, [currentTime, duration]);
165+
}
166+
);
124167

125-
return (
126-
<canvas
127-
ref={canvasRef}
128-
width={width}
129-
height={height}
130-
style={{
131-
...style,
132-
}}
133-
/>
134-
);
135-
};
168+
AudioVisualizer.displayName = "AudioVisualizer";
136169

137170
export { AudioVisualizer };

0 commit comments

Comments
 (0)