我可以将数组值插入画布的图像绘制功能吗?

时间:2015-08-05 21:19:17

标签: javascript arrays canvas

我想像这样创建一行相同的图片: http://imgur.com/4ylymJz

每张草图片的面积为70x70像素。我想使用for循环和存储25个值的数组来创建它。这就是代码:

var pic = new Image()
var picture = pic.src = "https://encrypted-tbn3.gstatic.com/images?q=tbn:ANd9GcSXEODf7WhGahJl_eRIh5Np063DS1MtQhjem1NDJLfdFB2am4YB";

var grassXs = [];

for (var i = 0; i < 25; i++) {
    grassXs.push(i*70);
}

for (var i = 0; i < grassXs.length;i++) {
    pic.addEventListener("load", function () {
        board.drawImage(pic,grassXs[i],430,70,70)
    }, false)
}

但由于某种原因,它完全没有工作。它不会创建单个图像。可能是因为参数不允许&#34;采取&#34;数组中的值?或者这只是我做错了什么?

2 个答案:

答案 0 :(得分:0)

你必须给草图像加载时间。

您可以使用图像对象上的onload回调来执行此操作。

快速举例:

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");

var count=25;
var width=70;
var img=new Image();
img.onload=start;
img.src="https://encrypted-tbn3.gstatic.com/images?q=tbn:ANd9GcSXEODf7WhGahJl_eRIh5Np063DS1MtQhjem1NDJLfdFB2am4YB";
function start(){
  canvas.width=width*count;
  canvas.height=img.height;
  for(var i=0;i<count;i++){
    ctx.drawImage(img,i*width,0,width,img.height);
  }
}
<canvas id="canvas" width=300 height=300></canvas>

[有关您的代码的其他说明]

例如,您的代码将按以下顺序执行:

// a new image object is created
var pic = new Image()

// "pic" BEGINS to load, but is not yet fully loaded
//       and is not yet ready to draw
var picture = pic.src = "https://encrypted-tbn3.gstatic.com/images?q=tbn:ANd9GcSXEODf7WhGahJl_eRIh5Np063DS1MtQhjem1NDJLfdFB2am4YB";

// This code is immediately executed even though
// "pic" has not yet fully loaded
var grassXs = [];

// This entire loop is immediately executed even though
// "pic" has not yet fully loaded
for (var i = 0; i < 25; i++) {
    grassXs.push(i*70);
}

// This entire loop is immediately executed even though
// "pic" has not yet fully loaded
// Since "pic" is not fully loaded each "drawImage" below is
// drawing empty images onto the canvas
for (var i = 0; i < grassXs.length;i++) {
    // pic is being given 25 event handlers which all point
    // to the final value of "i". Since grassXs[25] is undefined 
    // all of the drawImages are ineffective
    pic.addEventListener("load", function () {
        board.drawImage(pic,grassXs[i],430,70,70)
    }, false)
}

// about this time (or later if the "pic" is a large image)
// "pic" is fully loaded and is now ready to drawImage with.
// Unfortunately, all the "drawImage"s have been executed with 
// invalid grassXs.

答案 1 :(得分:0)

你有一个"closure mistake" 总结上面的链接,当你创建一个函数对象(在这种情况下是你的事件回调)时,它会记住&#34;它的上下文(在本例中是变量i)而不是直接的值 问题是在循环中,变量i会发生变化。当调度onload事件时(在循环结束后),i的值为25.
因此,board.drawImage(pic,grassXs[25],430,70,70)(注意25)在加载图像时被调用24次。 grassXs[25]undefined。这就是为什么没有显示的原因。

为什么i 25而不是24?
因为for循环将执行您的代码(并递增i),直到条件i<24为false。当它停止时,i已增加到25.
当你的回调被执行时,i仍然是25。

解决此问题的最简单方法是纠正代码中的另一个缺陷。你正在做的是你在图像对象上为同一个事件注册了24 EventListener个,并且每个都有一个回调函数来绘制一个图像。 我没有测试过性能,但更简单的做法是使用一个回调函数注册一个EventListener来绘制24个图像。

pic.addEventListener("load", function () {
  for (var i = 0; i < grassXs.length;i++) {
    board.drawImage(pic,grassXs[i],430,70,70);
  }
}, false)

此外,你的两个for循环具有完全相同的条件(grassXs.length在你的第一个循环之后是25)所以你可以通过在第二个循环中乘以70来组合它们。以下是完整代码的更正版本:

var pic = new Image()
var picture = pic.src = "https://encrypted-tbn3.gstatic.com/images?q=tbn:ANd9GcSXEODf7WhGahJl_eRIh5Np063DS1MtQhjem1NDJLfdFB2am4YB";

var count = 25;
pic.addEventListener("load", function () {
  for (var i = 0; i < count;i++) {
    board.drawImage(pic,i*70,430,70,70);
  }
}, false)

如何处理闭包

如果您将来遇到另一个关闭问题,那么如果没有更简单的方法,您可以如何纠正这个问题。您应该阅读我上面发布的链接页面,但这是一个代码示例。

您可以决定将代码放在外部函数中,并使用i作为参数调用此函数:

function setListener(offset)
{
    pic.addEventListener("load", function () {
        board.drawImage(pic,offset,430,70,70);
    }, false) ;   
}

for(i = 0; i < 25; i++)
{
    setListener(i*70);
}

或者您可以使用自动执行的匿名函数(在您的情况下,我将使用第一种方式,直到您对该语言更有经验。)。

for(i = 0; i < 25; i++)
{
    (function(offset) {
        pic.addEventListener("load", function () {
            board.drawImage(pic, offset,430,70,70);
        }, false);
    })(i);
}

将函数包装在括号中并在括号之间传递参数,就像调用普通函数一样。