Search code examples
javascripthtmlcanvasiterationeaseljs

staggering iterations over setTimeout


I'm trying to stagger for loops over time to draw a grid and keep system load down. For example: for a 100x100 grid that would be 10,000 iterations, instead of doing them all instantly, I want to do 1,000 then wait 250ms and carry on the next 1,000 until it's complete.

I can't seem to figure out why it isn't working.

In this example i am trying to do just that, but it only draws the first 1,000 squares, but console.log('iterate'); still runs and the iteration values follow on!

http://jsfiddle.net/FMJXB/2/

In this example, i have removed the setTimeout and instead calling the function twice, to simulate 2 loops with instant effect, and that draws 2,000 squares!

http://jsfiddle.net/FMJXB/3/

Why does having the function in a setTimeout stop the code from working?


Solution

  • Here’s a coding pattern to stagger drawing iterations using setTimeout

    The logic goes like this:

    • Use variable ”j” to track horizontally draws across your grid.
    • Use variable “i” to track vertical draws down your grid.
    • Use variable “iterations” to cut the drawing into blocks of 1000 draws at a time
    • When iterations has finished it’s 1000 draws, call setTimeout.

    This code is for illustration—you will need to adapt it for your easelJS specific needs.

    function draw(){
    
        // reset iterations for this block of 1000 draws
        var iterations = 0;
    
        // loop through 1000 iterations
        while(iterations++<1000){
    
            // put drawing code here
            graphics.drawRect(pixl.pixelSize*j, pixl.pixelSize*i, pixl.pixelSize, pixl.pixelSize);
    
            // increment i and j
            if(++j>canvas.width-1){ i++; j=0; }
    
            // if done, break
            if(i*j>pixelCount) { break; }
    
        }
    
        // schedule another loop unless we've drawn all pixels
        if(i*j<=pixelCount) {
            setTimeout(function(){ draw();  }, 1000);
        }
    
    }
    

    Here’s code and a Fiddle: http://jsfiddle.net/m1erickson/Z3fYG/

    <!doctype html>
    <html>
    <head>
    <link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
    <script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
    
    <style>
        body{ background-color: ivory; padding:20px; }
        canvas{border:1px solid red;}
    </style>
    
    <script>
        $(function(){
    
            var canvas=document.getElementById("canvas");
            var ctx=canvas.getContext("2d");
    
            var i=0;
            var j=0;
            var pixelCount=canvas.width*canvas.height;
    
            draw();
    
            function draw(){
    
                ctx.beginPath();
                var iterations = 0;
                while(iterations++<1000){
    
                    // put drawing code here
                    ctx.rect(j,i,1,1);
    
                    // increment i and j
                    if(++j>canvas.width-1){ i++; j=0; }
    
                    // if done, break
                    if(i*j>pixelCount) { break; }
    
                }
                ctx.fill();
    
                // schedule another loop unless we've drawn all pixels
                if(i*j<=pixelCount) {
                  setTimeout(function(){ draw();    }, 1000);
                }
    
            }
    
    
        }); // end $(function(){});
    </script>
    
    </head>
    
    <body>
        <canvas width="100" height="100" id="canvas"></canvas>
    </body>
    </html>