【问题标题】:HTML5 Canvas Drawing in Real Time实时 HTML5 画布绘制
【发布时间】:2015-06-26 07:11:22
【问题描述】:

问题:我怎样才能让putImageData()实时更新画布,因为图像的各个部分都已经计算过了?


我正在开发一个 JavaScript/TypeScript 应用程序,以在 HTML5 <canvas> 元素上绘制 Mandelbrot 集。撇开数学和细节不谈,我的应用程序可以很好地绘制集合。但是,如果您熟悉场景的可视化,您就会知道绘制可能需要很长时间。

它会在几秒钟内绘制,但在那之前,画布是完全空白的,然后图像就会出现。我正在寻找一种方法来绘制每一行,因为它是使用putImageData() 计算的。这是我正在尝试的:

// 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?
    }
}

不知何故,putImageData() 函数在计算完图像中的一行后调用,它只显示整个图像生成后的图像。

如何让putImageData() 实时更新画布,因为每一行都已计算完毕?


非工作代码的最新更新:

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);
}

工作代码,感谢 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);
}

【问题讨论】:

  • 解决方案会很复杂,但基本的反应是JavaScript是单线程的,运行在UI线程上;因此,在任何代码运行时,都不会显示任何新内容。大多数 JavaScript 逻辑都可以非常快速地运行,所以这不是问题,但 Mandelbrot 集可能是基于 setTimeout 的解决方案或 Web Worker 的候选者(Web Worker 非常复杂)
  • 调用 setTimeout 的行也会执行 handler,例如你可以将 handler(this, i) 包装在一个函数中,或者让 handler(this, i) 返回一个函数。
  • @ekusela 谢谢。我已经应用了你的函数包装想法,现在没有输出。听起来这个功能可能已经完成了。 JS,你又成功了。
  • 尝试从处理程序返回一个函数?我认为我现在在处理程序执行时总是具有相同的值。 (不要在循环中创建函数)
  • var handler = function(...) { return function() {...}; };

标签: javascript html canvas typescript


【解决方案1】:

尝试包装 putImageData 并将单行计算到 setTimeout 调用以异步执行它(接受编辑后:请参阅问题中的最终代码,这将不起作用,因为 i 将是 @ 987654325@ 在putImageData 行)

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);
    }
}

【讨论】:

  • 我试了一下,但它没有用,并且损坏了我的 CPU。我更新了我的问题以反映这种尝试。
  • 我已经更新了我的答案,您是否尝试过类似的方法,即在同一个异步函数中对单行进行整个计算和绘制?您也可以尝试 requestAnimationFrame 来减少对 CPU 的影响
  • 我只是试了一下,结果还是一样。实际上,由于函数调用开销,它比没有setTimeout() 慢一点。 :(
  • 嗯,图片一下子就出来了?您可以尝试按照此处所述指定脏参数developer.mozilla.org/en-US/docs/Web/API/…
  • 您使用的是我的代码示例还是您帖子中注释掉的代码示例?我的一个在超时回调中包含了不同的部分
猜你喜欢
  • 1970-01-01
  • 2020-04-22
  • 2014-10-16
  • 2012-12-20
  • 2017-03-26
  • 1970-01-01
  • 2016-08-22
  • 2019-04-12
  • 2015-03-06
相关资源
最近更新 更多