0

I've not experimented with canvases before. I've made a project which involves a canvas that gets continually extended, with new rows of "data" being appended to the bottom of it.

I've got the actual rendering part working fine; the final output is what I want it to be... but my intention with the project was to be able to watch as it gets drawn on the screen. However, what instead happens is that the canvas just hangs for a few seconds, and then displays all at once. This happens in Chrome at least, I've not tested other browsers.

I'm using a loop like the following:

for(var i = 0; i < 500; i++){
    addRow(data, canvas);
}

And essentially I want to view each row as it's being drawn.

Any ideas how I could do this?

clb
  • 715
  • 9
  • 23
  • I guess the problem is that the canvas is not rerendered before the loop finishes and there is an idle moment (since Javascript is single-threaded). Try to rewrite it using `setInterval` with a delay of 0 (wrap the body of the loop in a call to `setInterval`). – 11684 Nov 05 '16 at 18:03
  • @11684 Thanks for the response. It's definitely along the right lines with `setInterval(addRow, 0, data, canvas)` but I'm unsure about a certain aspect. I oversimplified my example, in reality the contents of the next row is dependent on the previous row. So after each row is drawn I want to recalculate with `data = calculateNextRow(data)`. How might I achieve this do you know? Currently it's just drawing the same row over and over again. I've not used `setInterval` before either! – clb Nov 05 '16 at 18:57
  • You can also pass an anonymous function to `setInterval`. I'll write an answer including an example. – 11684 Nov 05 '16 at 19:33

1 Answers1

0

Since JavaScript is single-threaded, the canvas cannot be redrawn while your loop is running.

You have to create idle moments in between the calls to addRow, so the JavaScript thread is freed to actually act on the new data. You do this by making the calls to addRow asynchronous; the easiest way to do this is to (ab)use the standard function setTimeout1.

setTimeout takes a function and executes this function asynchronously, after a given delay (if you omit the delay parameter, a delay of 0ms is assumed). I called this abusing this function earlier because you don't use the delay functionality, but I do think this is the standard way to execute code asynchronously; if not please let me know.

You can also pass an anonymous function (rather than a named one) to setTimeout, like so:

for(var i = 0; i < 500; i++){
    setTimeout(function() {
        data = calculateNextRow(data)
        addRow(data, canvas);
    });
}

If you need to use i inside the anonymous function, there will be some scope issues which are to complicated to explain here, but this answer does an excellent job of the deeper causes of the issues I alluded to and examples 3 and 5 illustrate exactly these issues.

1: in my earlier comment I suggested setInterval which was a mistake; setInterval calls the passed function repeatedly which is redundant since you would be calling it from a loop. Otherwise setTimeout and setInterval are very similar.

Community
  • 1
  • 1
11684
  • 7,356
  • 12
  • 48
  • 71