在Canvas中使用for循环绘制img

时间:2012-06-06 14:57:20

标签: javascript image loops canvas for-loop

var c=document.getElementById("cvs");
var ctx=c.getContext("2d");
var imgArray = [];          
for (var i=0;i<data.length;i++){
    var drawRepeat = Math.floor((data[i]/divider)); 
    imgArray[i] = [];   
    for (var j=0;j<drawRepeat;j++){
            //alert(j);
        var xPos = ((i*30)+10);
        var yPos = 250-((j*30)+30);
        imgArray[i][j] = new Image();
        imgArray[i][j].src="assets/orange.png";
        imgArray[i][j].onload = function(){
        ctx.drawImage(imgArray[i][j],xPos,yPos);
        };

    }
}

我想用for循环绘制多个图像。奇怪的是当我用for循环放置一个alert()时它有效吗?但如果我发表评论,它只会显示1张图片。

有没有解决方案?

3 个答案:

答案 0 :(得分:3)

这是与闭包有关的问题。我会在给出代码后解释。

var c = document.getElementById("cvs");
var ctx = c.getContext("2d");
var imgArray = [];
for (var i = 0; i < data.length; i++) {
    var drawRepeat = Math.floor((data[i] / divider));
    imgArray[i] = [];
    for (var j = 0; j < drawRepeat; j++) {
        //alert(j);
        (function (_i, _j) {
            var xPos = ((_i * 30) + 10);
            var yPos = 250 - ((_j * 30) + 30);
            imgArray[_i][_j] = new Image();
            imgArray[_i][_j].src = "assets/orange.png";
            imgArray[_i][_j].onload = function () {
                ctx.drawImage(imgArray[_i][_j], xPos, yPos);
            };
        })(i, j);
    }
}

<强>更新

我正在做这个奇怪的事情的原因是注册到onload事件的函数将被异步调用 - 即循环将继续并且函数将在图像加载时被调用,而不是在那时时刻。所以会发生这样的循环,并且一旦完成(注意这可能在完成之前发生),i的值将是data.length - 1。现在,加载一些图像,然后调用该函数。此函数引用i(在您提供的代码中),现在为data.length - 1。因此,只绘制最后一张图像。我知道这很令人困惑 - 当我第一次偶然发现关闭时,我感到很困惑。我建议你阅读一些关于它们的好文章,你会看到问题所在。

我们做的是创建一个范围(专家可能会发现这个表达式存在问题),创建一个立即调用的匿名函数,并传递i的值和j因为它是参数 - _i_j(请注意,我们可以使用相同的名称,但为了避免混淆,我没有使用相同的名称)。现在,这些是函数的本地函数,不会被更改。因此,当加载i图像时,会调用onload函数来绘制数组中的_i图像。

我没有很好地解释,所以正如我所说,请阅读关于闭包的一些文章。

答案 1 :(得分:0)

预加载图像,而不是使用onload处理程序。

答案 2 :(得分:0)

var c=document.getElementById("cvs");
        var ctx=c.getContext("2d");
        var img = new Image();
        img.src="assets/orange.png";
        img.onload = function(){
            for (var i=0;i<data.length;i++){
                var drawRepeat = Math.floor((data[i]/divider));
                for (var j=0;j<drawRepeat;j++){
                    //alert(j);
                    var xPos = ((i*30)+10);
                    var yPos = 250-((j*30)+30);
                    ctx.drawImage(img,xPos,yPos);
                }
            }
        }

我设法通过将onload放在for循环外面并将drawImage命令放在onload函数和for循环中来解决onload的问题。也适用。