1

I am trying to make a light weight progress bar using canvas. The target for this project is to have a progress bar filled to N percent from a given variable. For the purpose of this demo, I have manually set a 50% fill.

There are two colors: red which is filled by when loaded and green represents the progress completed.

How can I animate the progression of the green fill?

http://jsfiddle.net/ZpRm7/

var canvas = document.getElementById('myProgress');
var myPerc = 500;
ctx = canvas.getContext('2d');

ctx.fillStyle = "rgb(255, 0, 0)";  //red

ctx.fillRect(0,0,myPerc,100);
ctx.save();
    for (var i=0;i<(myPerc*0.5);i++)
    { 
        ctx.fillStyle = "rgb(0, 255, 0)";  //green
            setTimeout(function() {
                    ctx.fillRect(0,0,+i,100);
            }, 1000);   

    }
JerryHuang.me
  • 1,790
  • 1
  • 11
  • 21

1 Answers1

1

There are 2 issues with the code as posted. First, you are setting the duration of each timeout to 1000. This means that each timeout will finish in one second, all at the same time. I'm assuming instead that you want them to be one second apart.

The 2nd is a very common issue with using i in a loop in setTimeout. You can find answers to that all over SO. This seems to be one of the more thorough: JavaScript closure inside loops – simple practical example

With both of those issues fixed, you get this:

var canvas = document.getElementById('myProgress');
var myPerc = 500;
ctx = canvas.getContext('2d');

ctx.fillStyle = "rgb(255, 0, 0)";  //red

ctx.fillRect(0,0,myPerc,100);
ctx.save();

for (var i=0;i<(myPerc*0.5);i++)
{ 
    ctx.fillStyle = "rgb(0, 255, 0)";  //greeen

    (function(i){
        setTimeout(function() {
            ctx.fillRect(0,0,+i,100);
        }, 1000*i);
    })(i);
}

http://jsfiddle.net/ZpRm7/1/

You might consider setInterval or some other approach to avoid creating so many timeouts at once.

Community
  • 1
  • 1
James Montagne
  • 77,516
  • 14
  • 110
  • 130
  • Thank you and I have accepted your answer. Can you elaborate on this:(function(i){ setTimeout(function() { ctx.fillRect(0,0,+i,100); }, 1000*i); })(i); – JerryHuang.me Jan 08 '13 at 19:55
  • The link I provided on closures above has some pretty good explanations. This one in particular I think does a good job of explaining the underlying issue: http://stackoverflow.com/a/750560/717383 It may be a bit easier to read if you use a named function in place of an anonymous function: http://jsfiddle.net/ZpRm7/10/ In your original code, each execution of `setTimeout` had a reference to the SAME `i`. The function sort of gives each one their own `i` with the value as it was when `setTimeout` was called. – James Montagne Jan 08 '13 at 21:00