Yván Ecarri
Yván Ecarri

Reputation: 1739

Animating circle in html canvas with javascript

I need to animate a circle moving in a html canvas. For this purpose, I decided to use a typical sprite animation technique which consist in the following general steps:

  1. Initialize the background (in this case, just a gray rectangle)
  2. Calculate new sprite's coordinates
  3. Draw the sprite (the circle)
  4. Reset the backgound
  5. Goto 2

My problem is that the result looks like all the old circles seem to be redrawn each time I call ctx.fill() despite I am reseting the canvas.

What am I doing wrong? Any suggestion?

        var canvas;
        var ctx;
        var canvasPos;

        function rgbToHex(r, g, b) {
            return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
        }

        function init() {
            canvas = document.getElementById("target_temp");
            ctx = canvas.getContext("2d");
            canvasPos = { x: canvas.offsetLeft, y: canvas.offsetTop };
            drawSlider();
        }

        var y = 7;

        function animate() {
            y = y + 1;

            knob.setPosition(8, y);
            knob.clear();
            knob.draw();

            if (y < 93) {
                setTimeout(animate, 10);
            }
        }

        function drawSlider() {
            ctx = canvas.getContext("2d");
            ctx.fillStyle = "#d3d3d3";
            ctx.fillRect(0, 0, 16, 100);
        }

        var knob = {
            position: { x: 8, y: 7 },
            oldPosition: { x: 8, y: 7 },
            setPosition(_x, _y) {
                this.oldPosition = this.position;
                this.position.x = _x;
                this.position.y = _y
            },
            clear() {
                ctx.clearRect(0, 0, canvas.width, canvas.height);
                drawSlider();
            },
            draw() {
                ctx.fillStyle = rgbToHex(0, 0, 112);              
                ctx.arc(8, this.position.y, 7, 0, 2 * Math.PI);
                ctx.fill();
            }
        }

        window.onload = function () { init(); animate(); };
<!DOCTYPE html>
<html>
<boyd>
    <canvas id="target_temp" width="16px" height="100px"></canvas>
</boyd>
</html>

Upvotes: 2

Views: 554

Answers (2)

Helder Sepulveda
Helder Sepulveda

Reputation: 17594

I see you already figured out to use the beginPath but I will disagree with the location I will put that at the very beginning of the function animate, take a look at the code below, I refactored your code, got rid of some unused variables, and made the slider an object just like you have for the knob

var canvas = document.getElementById("target_temp");
var ctx = canvas.getContext("2d");

var slider = {
  width: 16, 
  height: 100,
  draw() {
    ctx.fillStyle = "#d3d3d3";
    ctx.fillRect(0, 0, this.width, this.height);
  }
}

var knob = {
  position: {x: 8, y: 7},
  radius: 8,
  draw() {    
    ctx.fillStyle = "#00D";    
    ctx.arc(this.position.x, this.position.y, this.radius, 0, 2 * Math.PI);
    ctx.fill();
  }
}

function animate() {
  ctx.beginPath()
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  slider.draw();
  if (knob.position.y + knob.radius < slider.height) 
    knob.position.y++;  
  knob.draw();
  setTimeout(animate, 10);
}

window.onload = function() {
  animate()
};
<canvas id="target_temp"></canvas>

Upvotes: 1

Yv&#225;n Ecarri
Yv&#225;n Ecarri

Reputation: 1739

Ok, I found the cause: the arc() method stacks the circle as part of the path, so, for it to work, we need to reset the path like this:

draw() {
  ctx.fillStyle = rgbToHex(0, 2*y, 107);      
  ctx.beginPath();          
  ctx.arc(8, this.position.y, 7, 0, 2 * Math.PI);
  ctx.fill();
}

Upvotes: 1

Related Questions