seckie's programming memo

プログラミングするにあたって調べたことなどのメモ。たまにひどい英語で書く。

canvas に次々に drawImage() するときの覚え書き

例えば連番の画像 0.png〜100.png があったとしてそれを次々に drawImage() でcanvasに描きこみたい。

canvas 要素には width, height 属性を必ず書く

そうしないとうまく描画できない。CSS の width, height は代用にならない。

NG:
<canvas id="c"></canvas>

#c {
  width: 640px;
  height: 400px;
}

OK:
<canvas id="c" width="640" height="400"></canvas>

画像はプリロード必須

今回は以下のような関数を書いた。

var preloadImages = function (srcs) {
  if (!srcs.length) {
    return;
  }
  var dfd = $.Deferred();
  var imgs = [];
  for (var i=0, l=srcs.length; i<l; i++) {
    var img = new Image();
    img.src = srcs[i];
    imgs.push(img);
  }
  var check = function () {
    for (var i=0, l=imgs.length; i<l; i++) {
      if (imgs[i].complete !== true) {
        setTimeout(check, 250);
        return false;
      }
    }
    dfd.resolve(imgs);
  };
  check();
  return dfd.promise();
}

画像はすべて別々に image オブジェクトを作る

それらを順に drawImage() する。そうしないと Chrome ではうまく描画できない。Firefox では同じ image オブジェクトを使い回しても描画できた。

// NG:
var srcs = [ '0.png', '2.png' .. '100.png' ]
var img = new Image();
preloadImages(srcs).done(function () {
  for (var i=0, l=srcs.length; i<l; i++) {
    img.src = srcs[i];
    ctx.drawImage(img, 0, 0);
  }
});

// OK:
var srcs = [ '0.png', '2.png' .. '100.png' ];
preloadImages(srcs).done(function () {
  for (var i=0, l=srcs.length; i<l; i++) {
    var img = new Image();
    img.src = srcs[i];
    ctx.drawImage(img, 0, 0);
  }
});