window.onload = ->
boxOrig1 = 10
boxOrig2 = 30
canvasW = 400
canvasH = 300
ctx = $("#canvas")[0].getContext('2d');
draw = (origin,dimension) ->
ctx.clearRect(0, 0, canvasW, canvasH)
ctx.fillStyle = 'rgb(200,0,0)'
ctx.fillRect(origin + boxOrig1, boxOrig1, dimension, dimension)
ctx.fillStyle = 'rgba(0, 0, 200, 0.5)'
ctx.fillRect(origin + boxOrig2, boxOrig2, dimension, dimension)
for m in [10..100] by 10
t = setTimeout (-> draw(m, 150)), 1000
t.clearTimeout
# draw(m,150)
# alert m
As an exercise, the code above is meant to draw a little design on a canvas, pause for a second, then redraw it again 10 pixels to the right.
I can see that the mechanics work fine when I interrupt the loop with an alert (as in those last two commented lines), but I’m not getting the expected behavior with the setTimeout function. The design just appears at the rightmost position after the timeout, skipping the incremental steps in between.
I’ve tried many different ways of doing this from other examples, but it’s just melting my brain. Any suggestions?
Geoff has outlined one approach (using
setIntervaland clearing it from the callback), so I’ll outline the other: UsingsetTimeoutfrom the callback. Something likeNote that there is a subtle timing difference between the two approaches that you should be aware of:
setInterval func, 1000will run the function once every 1000ms; the chainedsetTimeoutwill put a 1000ms delay between each function call. So ifdrawtook 100ms, say, the chainedsetTimeoutwould be equivalent tosetInterval func, 1100. It probably doesn’t matter, but it’s worth being aware of.Bonus approach: You don’t have to abandon your loop; you could just set all the timeouts from it at once:
The
do (m)is necessary so that the closure passed tosetTimeoutsees each value ofm, not just its final value in the loop. See my article A CoffeeScript Intervention for more info on this.Finally: I know this all seems very confusing at first, but timing in JS is actually very simple because the language is single-threaded. That means that events you schedule with
setTimeoutorsetIntervalor any other async function will never occur during a loop, even if the loop is infinite. They only occur after all of your code has finished executing. I talk about this in a little more detail in my book on CoffeeScript.