NS Error not initialized after capturing html canvas

I'm trying to record a svg animation using javascript/html. This is what i've tried so far:

<canvas id="canv">
    <svg width="370" height="370" viewBox="0 0 370 370" fill="none" xmlns="http://www.w3.org/2000/svg">
        <!-- my svg is here, full code is below because i don't think it's important -->
    </svg>
</canvas>
<style>
    @keyframes animation{
        from{
            opacity: 0;
            transform: translateY(20%);
        }to{
            opacity: 1;
            transform: translateY(0);
        }
    }
    #bubbles{
        animation: animation 1s linear;
    }
</style>
<script>
const canvas = document.getElementById("canv")

var videoStream = canvas.captureStream(30);
const render = () => {
    videoStream.getVideoTracks()[0].requestFrame();
}
setInterval(render, 33)
var mediaRecorder = new MediaRecorder(videoStream);
var chunks = [];
mediaRecorder.ondataavailable = function(e) {
    chunks.push(e.data);
};
mediaRecorder.onstop = function(e) {
    var blob = new Blob(chunks, { 'type' : 'video/mp4' });
    chunks = [];
    var videoURL = URL.createObjectURL(blob);
    video.src = videoURL;
};

mediaRecorder.start();
setTimeout(() => {
    mediaRecorder.stop();
}, 1000)
</script>

I have got the source code from https://medium.com/@amatewasu/how-to-record-a-canvas-element-d4d0826d3591 and i'm using firefox. full source: https://paste.gg/p/anonymous/89d475bc50bc469dad827a620d3f7c02

Problem: I get this error and nothing is shown: My Error

Upvotes: 0

Views: 274

Answers (1)

Kaiido
Kaiido

Reputation: 136996

You need to initialize a context on your canvas before being able to capture a stream from it, to do so, you call its getContext() method.

Then you'd need to use that context's methods to actually draw something on it, that's what will get captured by the MediaStream.

Appending an <svg> element inside a canvas won't draw that SVG image on the canvas context. To draw an SVG image on a 2D context you'd generally go through an <img> element, load the SVG image as a standalone document into this <img> and when loaded draw it on the 2D context using its drawImage() method. (cf this answer of mine showing how to do so from an inline <svg>)
However, drawImage() always draws only the first frame of an animated image, so for your case it may not be so useful.
In fact, there is really no easy way to draw an SVG animation on a canvas. You could try to produce one new standalone SVG document per frame manually, updated all the computed styles or the SMIL state and draw that through an <img>. But loading the image will be asynchronous, producing it may be computation heavy, it will probably be memory consumptive and the whole process has big risks of desynchronizing with the actual animation.

An alternative solution would be to use the 2D context's drawing API to reproduce the SVG, that at least would be synchronous, so less risk of desync, but a more complex code to write (some libraries like canvg may help in this task, though you'd still have to find the way to extract the current state of your animation at every frame).

Upvotes: 2

Related Questions