Javascript(画布) - for循环和drawImage不能一起工作

时间:2015-10-20 04:01:54

标签: javascript html canvas drawimage

我试图将一堆图像加载到画布上,但是没有出现。源包含指向我要使用的图像的链接。有人有什么想法吗?

这是我第一次使用画布。

    <canvas id ="canvas" width = "500" height = "500"></canvas>
    <script>

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

    loadImages(ctx);

    function loadImages()
    {
        var c = document.getElementById("canvas");
        var ctx = c.getContext("2d");

            var number = 0;
            var bX = 0;
            var bY = 0;
            var images = [];
            images = getImages();

            for(var i = 0;i<images.length;i++){
                var t = images[i];
                document.write(t.src+"<br>");
                ctx.drawImage(t,0,0,100,100);
                if(i%4==0)
                {
                    bX = 0;
                    bY -= 110;
                }
                else
                {
                    bX+=110;
                }

            }

    }

我做了这个功能来预加载图像并将它们以数组形式返回

    function getImages()
    {
        var imgList = [];
        var sources = 
        [             "http://terminus.scu.edu/~ntran/csci168-f15/hw/hw3/tile_00.png",
                      "http://terminus.scu.edu/~ntran/csci168-f15/hw/hw3/tile_01.png",
                      "http://terminus.scu.edu/~ntran/csci168-f15/hw/hw3/tile_02.png",
                      "http://terminus.scu.edu/~ntran/csci168-f15/hw/hw3/tile_03.png",
                      "http://terminus.scu.edu/~ntran/csci168-f15/hw/hw3/tile_04.png",
                      "http://terminus.scu.edu/~ntran/csci168-f15/hw/hw3/tile_05.png",
                      "http://terminus.scu.edu/~ntran/csci168-f15/hw/hw3/tile_06.png",
                      "http://terminus.scu.edu/~ntran/csci168-f15/hw/hw3/tile_07.png",
                      "http://terminus.scu.edu/~ntran/csci168-f15/hw/hw3/tile_08.png",
                      "http://terminus.scu.edu/~ntran/csci168-f15/hw/hw3/tile_09.png",
                      "http://terminus.scu.edu/~ntran/csci168-f15/hw/hw3/tile_10.png",
                      "http://terminus.scu.edu/~ntran/csci168-f15/hw/hw3/tile_11.png",
                      "http://terminus.scu.edu/~ntran/csci168-f15/hw/hw3/tile_12.png",
                      "http://terminus.scu.edu/~ntran/csci168-f15/hw/hw3/tile_13.png",
                      "http://terminus.scu.edu/~ntran/csci168-f15/hw/hw3/tile_14.png" ];
            var s = 0;
            var length = sources.length;
            for(s; s< length;++s)
            {
                imgList[s] = new Image();
                imgList[s].src = sources[s];
            }
            return imgList;
        }


    </script>
</body>



</html>

3 个答案:

答案 0 :(得分:1)

首先,确保正确检索和加载图像。然后将代码调整为以下内容:

   for (var i = 1; i <= images.length; i++) {
       var t = images[i];
       document.write(t.src+"<br>");
       ctx.drawImage(t,bX,bY,100,100);
       if (i%4 === 0) {
           bX = 0;
           bY += 110;
       }
       else {
           bX += 110;
       }
   }

您想要从索引1而不是0进行迭代,这样就不会立即实现if语句i % 4 === 0。然后,您希望使用变量bXbY作为图像的位置偏移。您使用ctx.drawImage(t,0,0,100,100);之前将所有图像堆叠在同一位置。最后,增加bY以便按下图像。

答案 1 :(得分:0)

问题是在尝试绘制图像之前图像没有加载。您应该创建imgs并将它们附加到正文

images = getImages();

for(var i = 0; i<images.length; i++){
    var img = document.createElement("img");
    img.src= images[i].src;
    document.body.appendChild(img);
    img.style.display = "none";
    img.id="img"+String(i);
}

然后像这样画出它们

loadImages(images);

function loadImages(images){
    var c = document.getElementById("canvas");
    var ctx = c.getContext("2d");

    for(var i = 0;i<images.length;i++){
            ctx.drawImage(document.getElementById("img"+String(i)),i*10,0,100,100);
            if(i%4==0)
            {
                bX = 0;
                bY -= 110;
            }
            else
            {
                bX+=110;
            }

        }

}

我测试了它并且它有效

答案 2 :(得分:0)

除了其他原因之外,它不起作用,因为您在尝试使用它们之前不等待图像加载。您可以使用Image对象load event执行此操作。我会写这样的东西,用Promise来管理加载状态。

var images,
  nameList = document.getElementById('image-names'), // just a div to display the stuff you were writing out to document. write.
  // this function returns a Promise which will resolve once all of the
  // images are done loading
  preloadImages = function () {
    var imagePromises,
      sources = [
        "http://terminus.scu.edu/~ntran/csci168-f15/hw/hw3/tile_00.png",
        "http://terminus.scu.edu/~ntran/csci168-f15/hw/hw3/tile_01.png",
        "http://terminus.scu.edu/~ntran/csci168-f15/hw/hw3/tile_02.png",
        "http://terminus.scu.edu/~ntran/csci168-f15/hw/hw3/tile_03.png",
        "http://terminus.scu.edu/~ntran/csci168-f15/hw/hw3/tile_04.png",
        "http://terminus.scu.edu/~ntran/csci168-f15/hw/hw3/tile_05.png",
        "http://terminus.scu.edu/~ntran/csci168-f15/hw/hw3/tile_06.png",
        "http://terminus.scu.edu/~ntran/csci168-f15/hw/hw3/tile_07.png",
        "http://terminus.scu.edu/~ntran/csci168-f15/hw/hw3/tile_08.png",
        "http://terminus.scu.edu/~ntran/csci168-f15/hw/hw3/tile_09.png",
        "http://terminus.scu.edu/~ntran/csci168-f15/hw/hw3/tile_10.png",
        "http://terminus.scu.edu/~ntran/csci168-f15/hw/hw3/tile_11.png",
        "http://terminus.scu.edu/~ntran/csci168-f15/hw/hw3/tile_12.png",
        "http://terminus.scu.edu/~ntran/csci168-f15/hw/hw3/tile_13.png",
        "http://terminus.scu.edu/~ntran/csci168-f15/hw/hw3/tile_14.png" 
    ];

    // if we have already loaded and cached the images,
    // return them right away wrapped in a resolved Promise
    if (images) {
      nameList.innerHTML += 'Using cached images.<br>';
      return Promise.resolve(images);
    }

    // otherwise we use .map to iterate over the items in sources and
    // create a new array of promises and store them in imagePromises
    imagePromises = sources.map(function (src) {
      // each of the promises that are created by this function
      // are stored in imagePromises and will resolve when the image
      // it represents fires its load event
      return new Promise(function (resolve, reject) {
          var img = new Image();

          // once the image has loaded, resolve its Promise
          img.onload = function () {
            resolve(img);
          };
          // if there is an error reject this image's Promise
          img.onerror = function () {
            reject(src + ' failed to load.');
          };

          img.src = src;
      });
    });

    // Promise.all will create a Promise that will resolve when all of the
    // images are loaded (because all of the Promises representing those
    // images will have resolved). If there is an error loading any of the
    // images it will be rejected, which we can handle later.
    return Promise.all(imagePromises)
      // after Promise.all returns a resolved Promise, we create a new Promise
      // using .then, which is what actually gets returned by preloadImages.
      .then(function (loadedImages) {
        // cache the loaded images in case we need them later
        images = loadedImages;
        // return the images so that anything chained off of this Promise
        // has access to them.
        return loadedImages;
      });

  },
  displayImages = function () {
    var c = document.getElementById("canvas"),
      ctx = c.getContext("2d"),
      bX = 0,
      bY = 0;

    // preloadImages will return a Promise that will resolve once all of the
    // images have been loaded. The .then chained off of that Promise receives
    // the list of images via the images parameter
    preloadImages().then(function (images) {
      var i,
        img;

      for(i = 0; i < images.length; /* no increment expression, see below */) {
          img = images[i];
          nameList.innerHTML += img.src + "<br>";
          ctx.drawImage(img, bX, bY, 100, 100); // you need to make sure to
                                                // use your offset here

          // incrementing here instead of in the increment expression of
          // for statement makes this part work correctly
          i += 1;

          if (i % 4 === 0) {
              bX = 0;
              bY += 110;
          } else {
              bX += 110;
          }
      }
    }).catch(function (msg) {
      // if there was an error loading any of the images, this .catch
      // will display an error
      nameList.innerHTML += msg + '<br>';
    });
};

displayImages();

有一个working fiddle here。如果您将不存在的图像添加到源列表,您会注意到它显示错误消息而不是绘制到画布。

您不必使用Promises,您可以将preloadImages作为参数进行回调,然后在加载所有图像后调用它。在这种情况下,您必须手动跟踪已加载的图像数量,并在每个图像的load事件中检查是否在调用回调之前加载了所有图像。

我的编码风格可能看起来有点奇怪,因为我习惯使用function expressions instead of function statements和其他一些东西,比如严格的等于运算符(===)。如果您想了解更多关于这种编码风格以及我使用它的原因,我会推荐Douglas Crockford的书 JavaScript:The Good Parts 。 (这是一本很棒的书,即使你不这样做,我也推荐它。)