2

I'm wondering what is wrong with my code (why is the animation so jerky):

<html>
<head>

</head>
<body style="background:black;margin:0;padding:0;">
<canvas id="canvas" style="background:white;width:100%;height:100%;"/>
<script>
var img=new Image();
img.onload=function(){
  var c=document.getElementById('canvas');
  var ctx = c.getContext('2d');
  var left,top;
  left=top=0;
  ctx.drawImage(img,left,top,20,20);
  var f=function(){
    left+=1;
    top+=1;
    c.width=c.width;
    ctx.drawImage(img,left,top,20,20);
  };
  setInterval(f,20);
};
img.src="http://a.wearehugh.com/dih5/aoc-h.png";
</script>
</body>
</html>

From what I know canvas is supposed to be good at doing these kinda stuff? But if instead I used an element and manipulate its left and top it ended up being faster (less jerky)..

Is there something wrong with my script? or is this the best canvas can do?

David Hall
  • 32,624
  • 10
  • 90
  • 127
Pacerier
  • 86,231
  • 106
  • 366
  • 634
  • 1
    Have you read http://stackoverflow.com/questions/4842872/performance-of-moving-image-on-web-page-via-css-vs-html5-canvas? – Kijewski May 30 '11 at 06:16
  • On a side note, `style="width:..` actually stretches the canvas. If you want to change the viewport size, use `width=...` sttributes instead. – pimvdb May 30 '11 at 06:17
  • @pimvdb heys sry can you explain urself.. do you mean **width=500px** is different from **style.width:500px** ? – Pacerier May 30 '11 at 08:43
  • @Pacener: That's correct for a `` element - using `style` doesn't change the resolution. – pimvdb May 30 '11 at 18:09

1 Answers1

4
  1. There is no need to clear the whole canvas on each iteration. It's possible to use clearRect method.

  2. Every time to draw image it's necessary to scale image. To avoid this you can draw on invisible canvas only once and then draw this canvas on visible one.

Your code with improved readability and performance:

<html>
<head>
</head>
<body style="background:black;margin:0;padding:0;">
    <canvas id="canvas" style="background:white;width:100%;height:100%;"/>
    <script>
        var img=new Image()
            buf = document.createElement('canvas');

        img.onload=function(){
            var c = document.getElementById('canvas'),
                ctx = c.getContext('2d'),
                left = 0, top = 0,
                width = 20, height = 20;

            buf.width = width;
            buf.height = height;
            buf.getContext('2d').drawImage(img, 0, 0, width, height);

            var f=function(){
                ctx.clearRect(left-1, top-1, width + 1, height + 1)
                left+=1;
                top+=1;
                ctx.drawImage(buf, left, top, width, height);
            };
            setInterval(f,20);
        };
        img.src="http://a.wearehugh.com/dih5/aoc-h.png";
    </script>
</body>
</html>
bjornd
  • 22,397
  • 4
  • 57
  • 73
  • heys btw just a question. is the buffering a standard way to do it? (i was thinking so when the game starts having a ton of images, we're gonna have a ton of buffers? – Pacerier May 30 '11 at 08:43
  • Standard way of doing it is having image of proper size, so you don't need to scale it. – bjornd May 30 '11 at 09:29
  • btw when you clear rect why did you width + 1, height + 1 instead of width and height? – Pacerier May 30 '11 at 10:11
  • 1
    This is because of one feature of canvas coordinate system. To draw a line of one pixel width you should write like this: ctx.moveTo(0.5, 0.5); ctx.lineTo(0.5, 10.5). If you write ctx.moveTo(0, 0); ctx.lineTo(0, 10) you'll get a grey a line, two pixels in width, because of interpolation algorithm. So when you draw image it can occupy area one pixel more in some direction. This feature is more clearly described here http://diveintohtml5.org/canvas.html#pixel-madness – bjornd May 30 '11 at 10:22
  • erm btw i was pretty sure that images do not suffer from interpolation.. (only lines do).. or am i mistaken? – Pacerier May 30 '11 at 10:26
  • You can easily insure by just removing this 1s. – bjornd May 30 '11 at 10:27