drawimage error. Is there a way to Unmount/Kill all processes when leaving peaksjs component
sshadmand opened this issue · 2 comments
Thank you for the awesome library! Everything works wondefully, but there is this one issue I haven't been able to resolve. I am using a React app, and I load the page that contains the PeaksJS audio waveform. If I leave the page for any reason BEFORE the wave form fully loads, then I get the following error. Otherwise no issue. I have tried all the suggestion here (added canvas tags with heights etc) but they don't resolve the issue #433
It seems like if I had a way to unmount the peaks instance or kill it completely on unmount in my React.useEffect it could be avoided.
Using the "destroy" doesn't seem to do it either.
useEffect(() => {
console.log('loaded')
mounted.current = true
return () => {
console.log('unload')
peaksInstanceRef.current.destroy()
mounted.current = false
peaksInstanceRef.current = null
}
}, [])
Uncaught DOMException: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The image argument is a canvas element with a width or height of 0.
at
SceneContext.drawImage(http://localhost:3001/static/js/9.chunk.js:5194:18)
at Rect.drawScene (http://localhost: 3001/static/js/9.chunk.js: 8622:17)
at http://localhost:3001/static/js/9.chunk.js: 4842:26 at Array.Torcach (canonymous?)
at Layer._drawChildren (http://localhost: 3001/static/is/9.chunk.js: 4841:68)
at Layer. drawScene (http://localhost:3001/static/js/9.chunk.js: 4783:14) at Layer. drawScene (http://localhost:3001/static/js/9.chunk.js: 6397:49)
at Layer.draw (http://localhost:3001/static/js/9.chunk.js:7933:12)
at http://localhost:3001/static/js/9.chunk.js:6325:18
at http://localhost:3001/static/is/9.chunk.js:10613:11
at Array. forEach (anonymous>)
at http://localhost:3001/static/is/9.chunk.js: 10612:15
au sentrywrapped (http://localhost:3001/static/js/8.chunk.js: 116157:17)
Thank you. Are you using peaksInstance.setSource()
?
I can see it's possible for the container element to be removed from the page or resized to zero width/height while Peaks.js is fetching the waveform or audio file, during Peaks.init()
or peaks.Instance.setSource()
- and we only check that the element is valid in Peaks.init()
, before the waveform is fetched.
I'll think about how to fix this. I guess ideally we'd also want to abort the fetch.
I use Peaks.init() like so.
useEffect(() => {
if (mounted.current === false) return console.log('No longer mounted')
const options = {
containers: {
zoomview: document.getElementById('zoomview-container'),
overview: document.getElementById('overview-container')
},
emitCueEvents: true,
showPlayheadTime: true,
overviewHighlightOffset: 0,
fontSize: 8,
zoomLevels: [256],
zoomWaveformColor: 'rgba(0,0,200,0.2)',
height: 80,
mediaElement: document.getElementById('audio')
}
if (peaks?.data?.length > 0) {
const max = peaks.data.reduce((max, el) => (el > max ? el : max), -100)
const denom = max > 125 ? 3 : 1
const normalizedPeaks = peaks.data.map(el => el / denom)
options.waveformData = {json: {...peaks, data: normalizedPeaks}}
} else {
const AudioContext = window.AudioContext || window.webkitAudioContext
const audioContext = new AudioContext()
options.webAudio = {audioContext}
}
Peaks.init(options, (err, peaksInstance) => {
err && console.log(err)
if (mounted.current === false) return console.log('No longer mounted')
if (!peaksInstance) return
peaksInstance.off('player.seeked', handleSeekEvent)
peaksInstance.on('player.seeked', handleSeekEvent)
onReady()
setLoading(false)
peaksInstanceRef.current = peaksInstance
})
}, [peaksInit]) // peaks wave form data
....
return (
<div>
<div>
<div id='waveform-container' >
<div id='zoomview-container' />
<div id='overview-container' />
</div>
<audio id='audio' >
<source src={url} type='audio/mpeg' />
<track src={subtitles} kind="captions" srcLang={languageCode} label={`${languageCode}_captions`} />
Your browser does not support the audio element.
</audio>
</div>
</div>
)