我正在尝试在HTML Canvas元素上绘制多个图像。
assetData
是对象的数组,每个对象包含从数据库中获取的将图像写入画布所需的数据。至关重要的是,assetData
可以是任意长度:它可以包含一个图像,也可以包含100个图像。
下面的代码不起作用,因为gfxCtx.drawImage()
多次绘制数组中指定的最终图像,而不是每个单独的图像。
for(var x = 0; x < assetData.length; x++) {
var layer = eval(assetData[x])
var gfx = new Image
gfx.src = "images/" + layer.src
gfx.onload = function() {
gfxCtx.drawImage(gfx, layer.x, layer.y, layer.w, layer.h)
compile()
}
}
compile()
处理将图像绘制到画布上
如果要绘制固定数量的图像,我将每个图像分配给一个单独的变量。但是,在这种情况下,我不一定知道要绘制多少张图像,而是想使代码保持简洁。
是否有一个干净,直接的解决方案来解决这个问题?
谢谢!
答案 0 :(得分:1)
要解决此问题,请考虑在forEach()
数组上使用assetData
方法,而不要像当前那样使用常规的for
循环。
这具有为每次循环迭代创建唯一的“关闭”的优势,从而使您可以根据需要将每个唯一的图像正确地绘制到画布中:
assetData.forEach(function(assetItem) {
// This function has a unique closure which
// allows you to draw the current assetItem
// to the canvas to achieve the desired result
var layer = eval(assetItem);
var gfx = new Image();
gfx.src = "images/" + layer.src;
gfx.onload = function() {
gfxCtx.drawImage(gfx, layer.x, layer.y, layer.w, layer.h);
compile();
}
});
答案 1 :(得分:1)
这是关于异步代码效果的常见问题解答。稍后调用图像onload
处理程序时,它将看到在上一次循环迭代中设置的layer
和gfx
的值。这将导致最后一张图像被多次绘制到最后一层的画布区域中。 (如果有时控制台上也没有生成错误,我会感到惊讶。)
最简单的解决方案是使用layer
声明gfx
和let
变量。这使它们成为块作用域,并为每个循环迭代创建一个单独的绑定:回调将查看在其中创建了回调函数对象的迭代的变量值。
有关该主题的更多讨论,请参阅JavaScript closure inside loops – simple practical example
答案 2 :(得分:0)
尝试引用onload事件目标而不是gfx
,因为在图像加载时gfx
的值可能已更改。
for(var x = 0; x < assetData.length; x++) {
var layer = eval(assetData[x])
var gfx = new Image
gfx.src = "images/" + layer.src
gfx.onload = function(e) {
gfxCtx.drawImage(e.target, layer.x, layer.y, layer.w, layer.h)
compile()
}
}