Suppose for example you want to go really fancy and didn't want to just show a old boring slider, instead you want some waves, we have got you covered. useWave
hook takes care of all that, its just a wrapper of waversurfer.js
Here's classic example of creating Wsj.com style based wave animation
See how he came up with this custom renderer function in this article
tsx
import { renderWsjWaveform } from "./render"
export function Wsj() {
const containerRef = React.useRef<HTMLDivElement>(null)
const { isWaveReady } = useWave({
container: containerRef,
progressColor: "#f50",
renderFunction: renderWsjWaveform
})
return (
<div>
<a className="hover:text-black hover:bg-neutral-100 hover:px-2" href="https://wsj.com">
wsj.com
</a>
{!isWaveReady && <LoaderCircle className="size-5 animate-spin" />}
<div className="mt-2" ref={containerRef} />
</div>
)
}
ts
export function renderWsjWaveform(channels: Array<Float32Array | number[]>, ctx: CanvasRenderingContext2D) {
const { width, height } = ctx.canvas
const scale = channels[0].length / width
const step = 10
ctx.translate(0, height / 2)
ctx.strokeStyle = ctx.fillStyle
ctx.beginPath()
for (let i = 0; i < width; i += step * 2) {
const index = Math.floor(i * scale)
const value = Math.abs(channels[0][index])
let x = i
let y = value * height
ctx.moveTo(x, 0)
ctx.lineTo(x, y)
ctx.arc(x + step / 2, y, step / 2, Math.PI, 0, true)
ctx.lineTo(x + step, 0)
x = x + step
y = -y
ctx.moveTo(x, 0)
ctx.lineTo(x, y)
ctx.arc(x + step / 2, y, step / 2, Math.PI, 0, false)
ctx.lineTo(x + step, 0)
}
ctx.stroke()
ctx.closePath()
}
TIP
Remember don't inline the renderFunction parameter of useWave
hook since it will result in stack overflow.
tsx
useWave({
container: containerRef,
progressColor: "#f50",
// don't inline the function directly since this will result in max depth stack trace
renderFunction: (channels: Array<Float32Array | number[]>, ctx: CanvasRenderingContext2D) => {
...
}
})