我想使用Canvas制作一个简单的火焰效果。目前我不理解在此上下文中使用双缓冲区的编码方面(错误)。我使用Brackets编写代码并且JSLint代码已经通过。错误是“无法设置未定义的属性'NaN'。”我在这个例子中做错了什么?
/*global document: false */
/*global setInterval */
function getPixel(imageData, x, y) {
"use strict";
var index = 0, r, g, b;
index = (x + y * imageData.width) * 4;
r = imageData.data[index];
g = imageData.data[index + 1];
b = imageData.data[index + 2];
return [r, g, b];
}
function setPixel(imageData, x, y, r, g, b, a) {
"use strict";
var index = 0;
index = (x + y * imageData.width) * 4;
imageData.data[index] = r;
imageData.data[index + 1] = g;
imageData.data[index + 2] = b;
imageData.data[index + 3] = a;
}
var element = document.getElementById("canvas");
var c = element.getContext("2d");
var w = element.width;
var h = element.height;
// set buffer
var offScreenCanvas = document.createElement('canvas');
offScreenCanvas.width = w;
offScreenCanvas.height = h;
var ctxOffscreen = offScreenCanvas.getContext('2d');
function init() {
"use strict";
var x, y, i, j, r, g, b;
for (j = 0; j < 10; j += 1) {
for (i = 0; i < 800; i += 1) {
x = i;
y = j;
r = 255 - Math.round(Math.random() * 50);
g = 0;
b = 0;
setPixel(ctxOffscreen, x, y, r, g, b, 255);
}
}
c.putImageData(ctxOffscreen, 0, 0);
}
function animation() {
"use strict";
var a1, a2, a3, a4, r, g, b, i, j;
// draw
for (j = 9; j < 100; j += 1) {
for (i = 0; i < 800; i += 1) {
a1 = getPixel(offScreenCanvas, i, j - 1);
a2 = getPixel(offScreenCanvas, i, j + 1);
a3 = getPixel(offScreenCanvas, i - 1, j);
a4 = getPixel(offScreenCanvas, i + 1, j);
r = Math.round((a1[0] + a2[0] + a3[0] + a4[0]) / 4);
g = Math.round((a1[1] + a2[1] + a3[1] + a4[1]) / 4);
b = Math.round((a1[2] + a2[2] + a3[2] + a4[2]) / 4);
setPixel(offScreenCanvas, i, j, r, g, b, 255);
}
}
// copy buffer onto the canvas
c.putImageData(offScreenCanvas, 0, 0);
}
init();
setInterval(animation, 20);
错误在setPixel定义中。
imageData.data[index] = r;
答案 0 :(得分:1)
首先,与您的调试器交朋友。它会帮助你很多。我发现Chrome上的那个(按Ctrl-Shift-I)最容易使用,但你的里程可能会有所不同。
其次,发布带有画布宽度和高度的html会很有帮助。从您的代码中,我推断它显然是800x100。
所以我的想法是传递给setPixel的imageData变量在某种程度上是未定义的,但调试器却向我展示了。这是一个正确定义的context2d。但这确实会导致您遇到的问题。
你正确地将一个名为ctxOffscreen的变量传递给setPixel,但在setPixel中,你假设它是imageData对象。不是。他们是不同的。
由于您使用的是两个上下文,因此您可能只想简单地getImageData
屏幕外的上下文。 (您可以通过调用c.createImageData
来避免这两个上下文并简单地使用两个imageDatas,但我将使用您当前获得的内容。)
在var ctxOffscreen line
之后,添加一个新的:
var imgData = ctxOffscreen.getImageData(0, 0, w, h);
将其传递到setPixel
和getPixel
而不是(ctxOffscreen),例如
setPixel(imgData, y, y, r, g, b, 255);
查看此FIDDLE。它运行。我想它可能会按你想要的方式运行。