jQueryでcanvasを扱うときは画像読み込みのタイミングに注意

jQueryの $(function(){ ... }) は、ページの load イベントではなく、DOMContentLoaded というイベントをトリガにして実行されます(Firefoxの場合)。このイベントはHTMLファイルがロードされDOMツリー構築が終了したときに実行されます。画像などの重いコンテンツのロードが始まる前に実行されるため体感速度が向上します。

しかし、以下のようにDOMContentLoadedをトリガにしてページ内の画像をcanvasで処理しようとすると、まだ画像が読み込まれていないためエラーになることがあります*1

$(function(){
  $("img").each(function(){
    var canvas = document.createElement('canvas');
    var c = canvas.getContext('2d');
    c.drawImage(this, 0, 0, w, h);  // まだ画像がロードされてないのでエラー
  });
});

imgのloadイベントのハンドラにしても、画像の読み込み完了前に実行されてしまいます。

$(function(){
  $("img").load(function(){ 
    var canvas = document.createElement('canvas');
    var c = canvas.getContext('2d');
    c.drawImage(this, 0, 0, w, h);
  })
});

動的に生成したHTMLImageElementは画像を読み込んだ時にonloadイベントが発生するようです。これでOK

$(function(){
  $("img").each(function(){
    $("<img>").attr("src", this.src).load(function(){
      var canvas = document.createElement('canvas');
      var c = canvas.getContext('2d');
      c.drawImage(this, 0, 0, w, h);
    });
  });
});

windowのloadイベントは、画像など全てのコンテンツのダウンロード完了時に発生するので小細工不要。これでもOK

$(window).load(function(){
  $("img").each(function(){
    var canvas = document.createElement('canvas');
    var c = canvas.getContext('2d');
    c.drawImage(this, 0, 0, w, h);
  });
});

普通はwindowのloadイベントで扱えば問題ないですが、jQueryプラグインにする場合は、$()で使われる事もあるので、動的にHTMLImageElementを生成する方法が良いかもしれません。

以上、jQuerycanvasを扱う時の注意点でした。

*1:画像キャッシュがあるとエラーにならない