如何在Wavesurfer JS中检测Canvas内波形加载完成?
解决Wavesurfer.js波形渲染完成后可靠保存图片的方案
我之前做类似项目的时候也踩过这个固定延迟的坑,确实太不靠谱了——不同音频文件大小、设备性能差异都会导致渲染时间波动,很容易出现保存空图的情况。这里有几个更可靠的替代方案,亲测有效:
方案1:监听draw事件(推荐)
Wavesurfer的draw事件会在波形绘制完成后触发,我们可以利用这个事件来执行保存操作,同时加个标记避免重复触发(比如窗口resize时也会触发draw):
// 初始化Wavesurfer实例 const wavediv = WaveSurfer.create({ container: '#canvasRender', waveColor: '#FFFFFF', progressColor: '#000000', cursorColor:'rgba(0,0,0,0)', splitChannels: true, height : 75, plugins: [ ] }); let isWaveSaved = false; // 标记是否已经保存过波形图 // 监听波形绘制完成事件 wavediv.on('draw', () => { if (!isWaveSaved) { isWaveSaved = true; const dataImg = wavediv.exportImage('image/png'); saveWave(dataImg); // 调用你的上传函数 } }); wavediv.load("sounds/test.mp3");
这个方案的优势是精准对应波形绘制完成的时机,不会过早或过晚执行。
方案2:ready事件结合requestAnimationFrame
如果draw事件在某些场景下触发过早,可以用ready事件(音频解码完成时触发)结合requestAnimationFrame,确保等待浏览器完成下一帧渲染后再保存:
const wavediv = WaveSurfer.create({ // 你的配置项... }); wavediv.on('ready', () => { // 等待浏览器下一帧渲染完成,确保波形已经绘制到Canvas上 requestAnimationFrame(() => { const dataImg = wavediv.exportImage('image/png'); saveWave(dataImg); }); }); wavediv.load("sounds/test.mp3");
requestAnimationFrame会在浏览器重绘前执行,这时候Canvas的内容已经稳定,比固定延迟更适配不同设备的渲染速度。
方案3:轮询检查Canvas状态(兜底方案)
如果以上方案都不适用,可以通过轮询检查Canvas的实际宽度来判断波形是否绘制完成——未绘制时Canvas宽度通常为0,绘制完成后会匹配容器宽度:
const wavediv = WaveSurfer.create({ // 你的配置项... }); wavediv.on('ready', () => { const checkWaveReady = () => { const canvas = wavediv.drawer.getCanvas(); if (canvas.width > 0) { // 波形已绘制完成 const dataImg = wavediv.exportImage('image/png'); saveWave(dataImg); } else { // 未完成,继续轮询 requestAnimationFrame(checkWaveReady); } }; checkWaveReady(); }); wavediv.load("sounds/test.mp3");
这个方案虽然是轮询,但用requestAnimationFrame实现,不会造成性能浪费,而且能确保100%捕捉到波形绘制完成的时机。
为什么固定setTimeout不可靠?
固定延迟完全忽略了音频文件复杂度、设备性能的差异:短音频或高性能设备可能0.1秒就完成渲染,长音频或低性能设备可能需要1秒以上,要么提前执行保存空图,要么延迟过久影响体验。而上面的方案都是基于事件或实际渲染状态触发,适配性强得多。
内容的提问来源于stack exchange,提问作者Eduardo Ponce de Leon
相关产品推荐
相关产品推荐

