0

I'm having trouble resizing this canvas that is displaying a video. After resizing, it continually jerks all around into different sizes between the "before" and "after" window sizes.

I tried this posts' idea, and that seemed to calm down Chrome a little, but had no affect on Firefox.

This other post gave me some ideas, but still didn't fix it. It seems like I'm either calling resize multiple times in a loop (which I don't see), or the canvas's context doesn't know how to settle on the final size. Any ideas?

<!DOCTYPE html>

<html>
<head>
    <title>overflow</title>
<style>
#c {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    width: 100%;
    height: 100%;
    z-index: 1;
}
#hold {
    position: fixed;
}

#v {
    position: absolute;
    height: auto;
    width: 100%;
    z-index: 0;

}
#see {
    position: relative;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 2;

}
</style>
</head>

<body>
<canvas id=c></canvas>

<div id=hold>
<video id=v>
</video>
</div>

<canvas id=see></canvas>


<script>
window.onload = start;

function start() {

    var v = document.getElementById('v');
    var house = document.getElementById('hold');
    var base = document.getElementById('c');
    var canvas = base.getContext('2d');
    var cover = document.getElementById('see');
    var canvastwo = cover.getContext('2d');


    v.src=("keyed.ogv")
    v.load();
    v.play();

    resize();

    function resize() {
        var wth = (window.innerWidth * 0.65);
        house.width = wth;
        house.height = (wth * 9/16);
        house.style.marginTop=((window.innerHeight/2) - (house.height/2) + "px");
        house.style.marginLeft=((window.innerWidth/2) - (house.width/2) + "px");
        cover.width = (wth/2);
        cover.height = (house.height/2);
        cover.style.marginTop=((window.innerHeight/2) - (cover.height/2) + "px");
        cover.style.marginLeft=((window.innerWidth/2) - (cover.width/2) + "px");
        var rw = cover.width;
        var rh = cover.height;

        canvastwo.clearRect(0, 0, rw, rh);
        draw(v, canvastwo, rw, rh);
    }

    window.onresize = resize;

function draw(o,j,w,h) {
    if(v.paused || v.ended) return false;
    j.drawImage(o,0,0,w,h);
    setTimeout(draw,20,o,j,w,h);
    }

}
</script>
</body>
</html>
Community
  • 1
  • 1
  • the resize event fires many times, for some reason. Even when I only call the function explicitly and stop listening for window resizes, the jitter still occurs. Note that this is only the canvas's behavior. If I display the video, I can resize all day, without issue. – subtle cinema Jul 21 '13 at 01:47

1 Answers1

0

You seem to lock in the old values you use for the setTimeout function the way you are using it here, as the context changes. So when you re-size the loop still uses the old values which no longer corresponds with the new sizes and results in the video toggle between these sizes.

Try to more "globalize" the values so that the loop call is clean when it comes to arguments. This way you are sure the variables contains the correct values for each round.

Also change setTimeout with requestAnimationFrame to make the loop more low-level (efficient) and fluid as this syncs to the monitor's vblank gap. This is particular important with video as you otherwise will get skipped frames as setTimeout is not able to sync with monitor.

Here is the essential code you need to change:

/// put these into you start block to keep them "global"
/// for the functions within it.
var w, h;

Change this part in the resize function:

/// ...
w = cover.width;
h = cover.height;

canvastwo.clearRect(0, 0, w, h);

/// argument free call to draw:
draw();

And finally the loop:

function draw() {
    if(v.paused || v.ended) return false;
    canvastwo.drawImage(v,0,0,w,h);
    requestAnimationFrame(draw);
}

This will remove the jerking video and also make the update in sync to the monitor like the video element itself does.

ONLINE DEMO