2010-06-06
指定した画像のロードが全て終わった後のタイミングで任意のスクリプトを実行するJavaScript
JavaScript | |
今会社にお金になるような仕事がなくて、ちょっと社長がピリピリしてて精神的にちょっと疲れるなぁ…といった毎日が続いてて、休日もあんまりJS書く状態にありつけませんでした。。なかなか。
そしてブログ書き込もうとしたらログアウトされてた関係で内容消えて書き直しになるし、踏んだり蹴ったり…うおー…
とりあえずソース
今のところIEでは実行できません。
Safari, Opera, Chrome, Firefoxで実行できます。
IEも対応しました。IE用にExplorerCanvasを用意してくださいませ。
HTML
<!DOCTYPE html> <head> <title>preload</title> <meta charset="UTF-8"> <!--[if IE]><script type="text/javascript" src="excanvas.compiled.js"></script><![endif]--> <script type="text/javascript" src="preload.js"></script> <script type="text/javascript"> // 画像URLを指定しておく var imageList = [ "6c506c24.jpg", "f832866c.jpg", "e3a35892.jpg" ]; onload = function(){ new preload(imageList, function(imageObjs){ // ここに、画像読み込み完了時の処理 var canvas = document.getElementById('c1'); if ( ! canvas || ! canvas.getContext ) { return false; } var ctx = canvas.getContext('2d'); ctx.drawImage(imageObjs[2], 0,0, 640,480); }); }; </script> </head> <body> <canvas id="c1" width="640" height="480" style="border:1px solid #CCC"></canvas> </body>
preload.js
var preload = function(a,b){ this.initialize(a,b); }; preload.prototype = { loaded:[], ip:0, // クロスブラウザにaddEventListener addEvent: function(target, type, listener) { //@cc_on target./*@if (@_jscript_version < 5.9) attachEvent('on' + @else@*/addEventListener(/*@end@*/type, listener, false); }, imageFunc:function(nextFunc, len){ this.loaded[this.ip++] = true; var j=0; var loadedFlg = true; for(; j<len; j++){ if(!this.loaded[j]){ loadedFlg = false; break; } } if(loadedFlg) nextFunc(imageList); }, // コンストラクタ initialize: function(imageList, nextFunc){ var self = this; var i=0, len = imageList.length; for(; i<len; i++){ self.loaded[i] = false; var img = new Image(); img.src = imageList[i]; imageList[i] = img; self.addEvent(imageList[i], "load", function(){ self.imageFunc(nextFunc,len); }); } } };
簡単な流れ
- 一つ目の画像から、onloadイベントを設定→onloadされたら次の画像に対してonloadイベントを設定…を再帰的に繰り返す
- 最後の画像まで終わったら、あからじめ引数として渡しておいた関数を実行する
タイマを設定し、onloadイベントによってロード完了フラグが全て立っていたらあらかじめ引数として渡しておいた関数を実行する- onloadイベントの最後で、ロード完了フラグをチェック。全てフラグが立っていたらあらかじめ引数として渡しておいた関数を実行する
実行してみる
http://esperia.kitunebi.com/javascript/preload/preload.html
(preload.htmlの2つのうち1つは忍者toolsの広告です。)
初回アクセス時から画像がちゃんとcanvas要素に描かれていればOKです。
IEでもaddEventListener辺りをちゃんと解決させてあげるとうまくいきそうな気がします。時間がある時にクロスブラウザにしてみるかも。
ところで画像はどこから?
ハム速まとめから頂いてきました!みんな絵うまいなー。。
http://hamusoku.com/archives/93066.html
追記:ishiducaさんにフォローしていただいて、IEに対応しました!しかし、たまに画像がうまく表示されない時があるっぽいです。。うーん。
あとDOMContentLoadedですが、IE8以下(とSafari3.0.4等)は対応していないので、onload に変更しておきました。今回の主題とは外れるので詳しくは扱いません。
DOMContentLoadedをIE8以下で対応させる場合は、uupaaさんの 140文字以内で DOMContentLoaded - latest logなどをご覧下さい。
追記2:try-catchではなく、ifによる分岐に変更しました。IE9PPのaddEventListener無駄にすんなぁぁぁって言われそうではありますけども。。
追記3:タイマーを使って実装してみました!あと、名前空間をなるべく汚さないようにしてライブラリみたいにしてみました。これでどや!一応、前の版をこちらに残しておきます。
追記4:おぉぉぉ、普通にタイマーいらなかったです。。修正しました!あと、記事タイトルも少しカオスだったので修正。
追記5:若干まだ説明が古いままでした。修正しました。
- 84 http://madobenanami.ni-moe.com/
- 49 http://pipes.yahoo.com/pipes/pipe.info?_id=0kJqAOKW3RGniq6n1ZzWFw
- 21 http://twitter.com/esperia09
- 14 http://pipes.yahoo.com/pipes/pipe.info?_id=3572f9da2c8db3951cc02c59f68f43ba
- 11 http://reader.livedoor.com/reader/
- 8 http://www.google.co.jp/search?q=サクラエディタ 正規表現 色つけ&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:ja:official&hl=ja&client=firefox-a
- 8 http://www.google.co.jp/search?sourceid=navclient&hl=ja&ie=UTF-8&rlz=1T4ADBS_jaJP320JP320&q=jacascript+setInterval
- 6 http://madobenanami.ni-moe.com/Category/1/
- 6 http://madobenanami.ni-moe.com/Entry/107/
- 6 http://www.google.co.jp/search?hl=ja&client=firefox-a&rls=org.mozilla:ja:official&q=javascript+ロード後&aq=5r&aqi=g3g-r7&aql=&oq=javascript+ ロード&gs_rfai=
var addEvent = function (node, handle, func, flg) {
try {
node.attachEvent(('on' + handle), func);
} catch (e) {
node.addEventListener(handle, func, flg);
}
};
// addEvent(window, "DOMContentLoaded", function () { ... }, false);
また、try-catch文より、if文の方がパフォーマンスが良さそうです。
http://dev.opera.com/articles/view/efficient-javascript-ja/?page=2#trycatch
ところで、preload関数は画像の読み込みにかかる時間が、
imageList[0]の画像<imageList[1]の画像<imageList[2]の画像<...
ということを前提にしているように思えます。
<q>たまに画像がうまく表示されない</q>のは、それが原因ではないでしょうか。
>たまに画像がうまく表示されない
それが原因のようですね…。alertを再帰のところに挟んで遅延させると、IE意外でもうまくいかないことを確認しました。。
画像のリクエストを一つずつ出す方法もありますけど、これだとパラレルに画像をロードしてくれないので遅くなっちゃうんですよね…。ということで、今はタイマーを使った方法を検討してます。
これで大丈夫か…な?
//@cc_on
target./*@if (@_jscript_version < 5.9) attachEvent('on' +
@else@*/addEventListener(/*@end@*/type, listener, false);
}
・せっかくなら、imageListもコンストラクタ関数で受け取るようにするといいのでは。
・setIntervalを使わなくても、画像のloadイベントリスナー内でチェックできそうです。
教えていただいた関数を使い、setIntervalの中身をonloadイベントの方に移して、引数の受け渡しの部分を修正してみました!これで今度こそすっきり動くはず!
本当にお手数おかけしました。。ありがとうございます!