Question: How can I make putImageData() update the canvas in real time, as various parts of the image have been computed?
I am working on a JavaScript/TypeScript application to draw the Mandelbrot set on an HTML5 <canvas> element. Math and details aside, my application draws the set just fine. However, if you are familiar with visualizing the set, you know that it can take a long time to draw.
It will draw in a few seconds, but until then, the canvas is completely blank, then the image appears. I'm looking for a way to draw each row as it is computed using putImageData(). Here is what I am trying:
// part of the class definition
private Context: CanvasRenderingContext2D;
private ImageData: ImageData;
private Pixels: number[];
constructor() {
var c: HTMLCanvasElement = <HTMLCanvasElement>document.getElementById("can");
this.Context = c.getContext("2d");
this.ImageData = this.Context.createImageData(this.Size.Width, 1);
this.Pixels = this.ImageData.data;
}
public draw() {
// tried this... does not help
// var handler = function(m: Mandelbrot) {
// m.Context.putImageData(m.ImageData, 0, i)
// };
for(var i: number = 0; i < this.Size.Height; ++i) { // Loop over each row
for(var j: number = 0; j < this.Size.Width; ++j) { // Calc px. for one row
// all the math to compute the set... (works)
this.setPixelColor(j, color); // sets a color in this.Pixels (works)
}
// setTimeout(handler(this), 0); // does not help
this.Context.putImageData(this.ImageData, 0, i); // Draw the row on the canvas?
}
}
Somehow, the putImageData() function, which is called after a row in the image has been computed, only shows the image after the entire image has been generated.
How can I make putImageData() update the canvas in real time, as each row has been computed?
Latest update of non-working code:
var handler = function(m: Mandelbrot, i: number) {
for (var j: number = 0; j < m.Size.Width; ++j) {
// math
m.setPixelColor(j, color);
}
m.Context.putImageData(m.ImageData, 0, i);
};
var that: Mandelbrot = this;
for(var i: number = 0; i < this.Size.Height; ++i) {
setTimeout(function() {
handler(that, i)
}, 0);
}
Working code, thanks to ekuusela:
var handler = function(m: Mandelbrot, i: number) {
return function() {
for (var j: number = 0; j < m.Size.Width; ++j) {
// math
m.setPixelColor(j, color);
}
m.Context.putImageData(m.ImageData, 0, i);
}
};
for(var i: number = 0; i < this.Size.Height; ++i) {
setTimeout(handler(this, i), 0);
}
Try wrapping putImageData and the calculation for a single row to a setTimeout call to execute it asynchronously (post accept edit: see the final code in the question, this won't work since i will be undefined in the putImageData row)
public draw() {
var that = this;
var drawRow = function() {
for(var j: number = 0; j < that.Size.Width; ++j) { // Calc px. for one row
that.setPixelColor(j, color); // sets a color in this.Pixels (works)
}
// TODO specify the dirty region in this call
that.Context.putImageData(that.ImageData, 0, i); // Draw the row on the canvas?
};
for(var i: number = 0; i < this.Size.Height; ++i) { // Loop over each row
setTimeout(drawRow, 0);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With