Use setInterval to infinitely draw rectangles

1.1k Views Asked by At

I'm trying to learn how to learn basic animation using ONLY canvas with the setInterval function. I'm trying to draw a simple rectangle to the screen and move it to the right 1 pixel every 100 milliseconds. However when I do it paints over the previous rectangle. I called clearRect() but that doesn't seem to do anything.

How can I make this rectangle smoothly travel across the screen without leaving a trail? Also if there is a better way to do this rather than using clearRect() and translate() please do share.

var ctx = document.getElementById('mycanvas').getContext('2d');
var a = setInterval(draw,100);

var x = 50;
function draw()
{
    ctx.clearRect(0,0,300,300);
    ctx.translate(1,0);
    ctx.rect(x,50,50,50);
    ctx.stroke();
}
5

There are 5 best solutions below

0
On BEST ANSWER

You can do it two different ways:

You can continue to use rect() and stroke(), but you need to call beginPath() beforehand. When you call methods like rect(), a list, called the "path," is kept of all of the shapes, or "subpaths," that you've created. Then, when you call stroke(), the entire path is drawn. Thus, even if you clear the screen, all of the past rectangles are still remembered in the path, and drawn again. beginPath() clears that list.

var x = 50;
function draw() {
    ctx.clearRect(0, 0, 300, 300);
    ctx.beginPath();
    ctx.rect(x, 50, 50, 50);
    ctx.stroke();
    x++;
}

Or, you can combine the rect() and stroke() into one line, and not need to call beginPath(). That's because the rectangle is both created and drawn at the same time, and isn't put in the list.

var x = 50;
function draw() {
    ctx.clearRect(0, 0, 300, 300);
    ctx.strokeRect(x, 50, 50, 50);
    x++;
}

Either way, I advise incrementing x instead of using translate(), because translate() basically moves the imaginary "pen" that is drawing on the canvas. So if you translate(50, 50), and then you try to draw a rectangle at (0, 0) on the canvas, it will actually be at (50, 50).

As Microsoft puts it on MSDN, "The translate method effectively remaps the (0,0) origin on a canvas."

If you repeatedly do that, it will become difficult to keep track of where you're actually drawing.

0
On

Try beginPath() and closePath():

var maxX, x = 0,
  s = 50,
  maxY;

var repaint = function(ctx) {
  if (x + s >= maxX) { //reached end of the canvas
    return;
  }
  ctx.clearRect(0, 0, maxX, maxY); //clear previous
  ctx.beginPath(); //start drawing
  ctx.rect(x, s, s, s);
  ctx.stroke();
  ctx.closePath(); //stop drawing
  x++;
  setTimeout(function() {
    repaint(ctx); //continue here
  }, 100);
};

var cnvs = document.getElementById('canvas');
maxX = cnvs.width;
maxY = cnvs.height;
repaint(cnvs.getContext('2d'));
canvas {
  border: 1px solid grey;
}
<canvas width="360" height="180" id='canvas'>HTML5 canvas not supported</canvas>

0
On

Your x variable never changes, so your shape will not move. You need to increment x to get movement:

var x = 50;
function draw(){
    ctx.clearRect(0,0,300,300);
    ctx.translate(1,0);
    ctx.rect(x,50,50,50);
    ctx.stroke();
    x++;
}
2
On

In order to get a smooth animation with shapes and other sprites moving across the screen (or even staying still) it would be better to make a clearScreen method that will basically draw over the entire canvas in whatever background color the canvas is. It is basically just a function that will draw a white (or whatever background color you are using) rectangle over the entire canvas. Then, you call the draw function that will make all the necessary drawings. That way, there won't be any trail or anything of the past movements and you won't have to call clearRect() on every single rectangle you make.

Basically, the function will erase the canvas and you can redraw whatever you need to in order to make the animation of the box moving across the screen.

Does that make sense?

EDIT: Also, to be clear, you would make your own clearScreen method based on what size your canvas is and what color your background is. Its not hard, all it does is draw a rectangle over the screen.

0
On

Simply increment x on every call:

var canvas = document.getElementById('mycanvas')
var ctx = canvas.getContext('2d');
var a = setInterval(draw,100);

        var x = 50;
        function draw(){
            canvas.width = canvas.width; // clears the canvas
            ctx.rect(x++,50,50,50);
            ctx.stroke();
            if (x > 250) // resets the position
              x = 50;
        }
<canvas id="mycanvas"></canvas>

I also removed that translation since there's no need to do it just for the square animation.