Search code examples
javascriptcanvashtml5-canvashtml5-videorequestanimationframe

Run canvas animation and video synchronously


I want to animate stuff on a canvas using the window.requestanimationframe() method on top of two video (e.g. for highlighting important stuff in both videos). Currently, the animation runs and after that, the videos start playing together. So how can I execute everything (both videos and canvas animation) simultaneously?

class Animation {

    constructor(canvas, data) {
        this.canvas = document.getElementById(canvas);
        this.ctx = this.canvas.getContext('2d');
        this.data = data;
        this.start = 0;
        this.counter = 0;
        this.running = false;

        this.draw = function(){
            console.log(this);
            console.log("Draw");
            if(!document.querySelector('video').playing){
                // init
                this.ctx.clearRect(0, 0, 300, 300); // clear canvas

                // get data
                var in_video_data = this.data['in_video'];

                // draw CircleLineTimeSeries
                for (var i=0; i<in_video_data.length; i++){
                    var item = in_video_data[i];
                    // if counter in phase intervall
                    if (this.counter >= item['start'] && this.counter <= item['end']){
                        console.log(item);
                        if (item['object'] == 'CircleLineTimeSeries'){
                            this.visualizeCircleLine(item['raw_kps'][0][this.counter],
                                                     item['raw_kps'][1][this.counter]);
                        }
                    }
                }

                // Increase time variable
                this.counter += 1;

            }
            if (this.running){
                window.requestAnimationFrame(this.draw.bind(this));
            }
        }
    }


    visualizeCircleLine(kps0, kps1){
        this.ctx.beginPath();
        this.ctx.moveTo(kps0[0], kps0[1]);
        this.ctx.lineTo(kps1[0], kps1[1]);
        this.ctx.stroke();
    }

    play(){
        this.running = true;
        window.requestAnimationFrame(this.draw.bind(this));
    }

    pause(){
        this.running = false;
    }
}

The code for running the video and the canvas animation:

/**
* Event handler for play button
*/
function playPause(){
    if (running){
        running = false;
        animation.pause();
        video0.pause();
        video1.pause();
    } else {
        running = true;
        animation.play();
        video0.play();
        video1.play();
    }
}

Thank you in advance :)


Solution

  • As @Kaiido noted, you have to listen for updates in current time of the video. There is respective media event - timeupdate. Furthermore you should have a list of key frames of the video when to show your animation. Whenever timeupdate event fires, check the current time for reaching some key frame and, if so, notify your requestanimationframe callback to run animation via some shared variable.