サイトトップ

Director Flash 書籍 業務内容 プロフィール

HTML5テクニカルノート

PreloadJSで外部画像ファイルの読込みを待つ

ID: FN1205002 Technique: HTML5 and JavaScript

PreloadJSは、画像のほか、サウンドやJavaScriptなどの外部データを読込んで、その経過や完了を捉えて処理するためのライブラリです。本稿では、画像ファイルの読込みを待って、その画像にもとづく処理を加えてみます。 なお、読込み待ちのない外部画像ファイルの扱いについては、「EaselJSで外部ビットマップファイルを読込んで回す」をご参照ください。


01 外部画像ファイルを読込んでCanvasの中央に表示する
PreloadJSのライブラリは、予めサイトからダウンロードして、適切な場所に保存しておいてください(図001)。本稿では、HTMLドキュメントと同じ階層に、ダウンロードしたpreloadjsフォルダが置いてあるものとします。

図001■PreloadJSライブラリのJavaScriptファイル
図001

まずは、PreloadJSのプリロードなしに、外部画像ファイルを読込んでCanvasの中央に表示します(図002)。<script>要素の中身は、つぎのコード001のとおりです。前出「EaselJSで外部ビットマップファイルを読込んで回す」のコード001と基本的に同じです(ただし、「CreateJS Suiteのクラスに名前空間が設定される」02「名前空間を省くには」のscript要素が加えてあります)。

図002■外部から読込んだファイルの画像がCanvasの中央に表示された
図002

コード001■PNGファイルを読込んでCanvasの中央に表示する
  1. <script>
  2. var createjs = window;
  3. </script>
  4. <script src="easeljs/utils/UID.js"></script>
  5. <script src="easeljs/geom/Matrix2D.js"></script>
  6. <script src="easeljs/events/MouseEvent.js"></script>
  7. <script src="easeljs/display/DisplayObject.js"></script>
  8. <script src="easeljs/display/Container.js"></script>
  9. <script src="easeljs/display/Stage.js"></script>
  10. <script src="easeljs/display/Bitmap.js"></script>
  11. <script type="text/javascript">
  12.   var stage;
  13.   var myBitmap;
  14.   function xInitialize() {
  15.     var canvasObject = document.getElementById('myCanvas');
  16.     stage = new Stage(canvasObject);
  17.     xDraw(canvasObject.width / 2, canvasObject.height / 2);
  18.   }
  19.   function xDraw(nX, nY) {
  20.     myBitmap = new Bitmap("images/large.png");
  21.     myBitmap.x = nX - myBitmap.image.width / 2;
  22.     myBitmap.y = nY - myBitmap.image.height / 2;
  23.     stage.addChild(myBitmap);
  24.     stage.update();
  25.   }
  26. </script>

スクリプトそのものに、とくに問題はありません。ただ、画像の容量が大きかったりすると、読込みが間に合わなくて画像のサイズが正しくとれなかったり(コード001第21〜22行目)、描画の更新(第24行目)に間に合わずに表示されないことがあり得ます。


02 PreloadJSで外部ファイルを読込む
そこで、PreloadJSを用いて、画像ファイルは先読みしておくことにしましょう。まずは、<script>要素にPreloadJSのライブラリを加えます(前掲図001参照)。なお、行頭の番号は後にまとめて掲げるコード002のステートメント番号を示します。

  1. <script src="preloadjs/AbstractLoader.js"></script>
  2. <script src="preloadjs/PreloadJS.js"></script>
  3. <script src="preloadjs/TagLoader.js"></script>
  4. <script src="preloadjs/XHRLoader.js"></script>

つぎに、初めに呼出される初期設定の関数(xInitialize())に手を加えます。PreloadJSで外部画像ファイルを先読みします。コンストラクタメソッドPreloadJS()には、XMLHttpRequestを使うかどうかブール(論理)値で引数に渡します。

new PreloadJS(XMLHttpRequestの使用)

ファイルをひとつ読込み終えたかどうかは、AbstractLoader.onFileLoadイベントにハンドラの関数を設定して捉えます(AbstractLoaderはPreloadJSのスーパークラスです)。

PreloadJSオブジェクト.onFileLoad = イベントハンドラ

PreloadJS.loadFile()メソッドで外部ファイルの読込みを始めます。引数に渡す外部ファイルの情報は、ふたつの定め方があります。ひとつは、画像ファイルのURLを文字列でそのまま渡すことです。端的で手軽といえます。

PreloadJSオブジェクト.onFileLoad(URL)

もうひとつは、URLに加えていくつかのデータをObjectインスタンスのプロパティとして納めて渡すことです。プロパティsrcにURL、idに読込んだデータの識別子がともに文字列で定められます。後述03のとおり、この他にも加えられるプロパティがあって応用もしやすいので、こちらのやり方を採ります。

PreloadJSオブジェクト.onFileLoad({src:URL, id:識別子})

初期設定の関数(xInitialize())は、つぎのように書替えます。<canvas>要素(canvasObject)は、後の関数からも参照したいので、ローカル変数にするのは止めて関数の外で宣言しました(コード002第18および20行目)。

  1. var canvasObject;
  2. function xInitialize() {
      // var canvasObject = document.getElementById('myCanvas');
  3.   canvasObject = document.getElementById('myCanvas');
  4.   var file = {src:"images/large.png", id:"image"}
  5.   var loader = new PreloadJS(false);
  6.   stage = new Stage(canvasObject);
      // xDraw(canvasObject.width / 2, canvasObject.height / 2);
  7.   loader.onFileLoad = xFileLoaded;
  8.   loader.loadFile(file);
  9. }

イベントハンドラ(xFileLoaded())から呼出すのは、読込んだ画像をCanvasに描く関数(xDraw())です。ハンドラが引数に受取ったObjectインスタンスのプロパティresultで読込んだ画像の参照(<image>要素)が得られます。その参照は、呼出す関数の第3引数に加えました(コード002第28行目)。

そのため、呼出される関数(xDraw())にも、受取る第3引数が設けてあります(コード002第30行目)。第3引数で<image>要素の参照が得られますので、関数本体の3ステートメントもその引数を用いるように修正しました(第31〜33行目)。

  1. function xFileLoaded(eventObject) {
  2.   xDraw(canvasObject.width / 2, canvasObject.height / 2, eventObject.result);
  3. }
    // function xDraw(nX, nY) {
  4. function xDraw(nX, nY, myImage) {
      // myBitmap = new Bitmap("images/Pen.png");
  5.   myBitmap = new Bitmap(myImage);
      // myBitmap.x = nX - myBitmap.image.width / 2;
  6.   myBitmap.x = nX - myImage.width / 2;
      // myBitmap.y = nY - myBitmap.image.height / 2;
  7.   myBitmap.y = nY - myImage.height / 2;
  8.   stage.addChild(myBitmap);
  9.   stage.update();
  10. }

これらの手を加えて書き上がった<script>要素全体が、つぎのコード002です。PreloadJSで外部画像ファイルの読込みが終わってから、Canvas上の位置決めと描画を行っています。これで読込む外部ファイルの容量にかかわらず、正しく画像が描かれます(前掲図002参照)。

コード002■PreloadJSで外部画像ファイルの読込みを待って描画する
  1. <script>
  2. var createjs = window;
  3. </script>
  4. <script src="easeljs/utils/UID.js"></script>
  5. <script src="easeljs/geom/Matrix2D.js"></script>
  6. <script src="easeljs/events/MouseEvent.js"></script>
  7. <script src="easeljs/display/DisplayObject.js"></script>
  8. <script src="easeljs/display/Container.js"></script>
  9. <script src="easeljs/display/Stage.js"></script>
  10. <script src="easeljs/display/Bitmap.js"></script>
  11. <script src="preloadjs/AbstractLoader.js"></script>
  12. <script src="preloadjs/PreloadJS.js"></script>
  13. <script src="preloadjs/TagLoader.js"></script>
  14. <script src="preloadjs/XHRLoader.js"></script>
  15. <script type="text/javascript">
  16.   var stage;
  17.   var myBitmap;
  18.   var canvasObject;
  19.   function xInitialize() {
  20.     canvasObject = document.getElementById('myCanvas');
  21.     var file = {src:"images/large.png", id:"image"}
  22.     var loader = new PreloadJS(false);
  23.     stage = new Stage(canvasObject);
  24.     loader.onFileLoad = xFileLoaded;
  25.     loader.loadFile(file);
  26.   }
  27.   function xFileLoaded(eventObject) {
  28.     xDraw(canvasObject.width / 2, canvasObject.height / 2, eventObject.result);
  29.   }
  30.   function xDraw(nX, nY, myImage) {
  31.     myBitmap = new Bitmap(myImage);
  32.     myBitmap.x = nX - myImage.width / 2;
  33.     myBitmap.y = nY - myImage.height / 2;
  34.     stage.addChild(myBitmap);
  35.     stage.update();
  36.   }
  37. </script>

03 PreloadJSについてもう少し深く知る
PreloadJSについて、あとふたつ解説を加えましょう。第1に、AbstractLoader.onFileLoadイベントのハンドラが引数に受取るイベントオブジェクトの使い方です。第2は、複数のファイルをまとめて読込むPreloadJS.loadManifest()メソッドのご紹介です。

第1のイベントオブジェクトからご説明します。このObjectインスタンスには、プロパティとしてresultのほか、PreloadJS.loadFile()メソッドの引数に渡したObjectからsrcidが加えられます。さらに、typeというプロパティがあり、読込むファイルの形式を示します。

typeプロパティの値は文字列で、PreloadJSクラスに定数として備えられています(表001)[*1]。PreloadJSは、読込むファイルの拡張子で形式を判別します。けれど、PHPスクリプトなど標準的でない形式のときには、PreloadJS.loadFile()メソッドに渡すObjectにtypeプロパティを定めて明らかにしましょう。

表002■読込むファイルのtypeプロパティを定めるPreloadJSクラスの定数
PreloadJSクラスの定数 ファイル形式 おもな拡張子
CSS CSS .css
IMAGE 画像 .png/.gif/.jpg
JAVASCRIPT JavaScript .js
JSON JSON .json
SOUND サウンド .mp3/.ogg/.wav
TEXT テキスト .txt
XML XML .xml

AbstractLoader.onFileLoadイベントのハンドラが受取るイベントオブジェクトには、もうひとつdataというプロパティに自由な値が定められます。このdataプロパティをPreloadJS.loadFile()メソッドの引数のObjectに加えて渡せば、イベントオブジェクトに納められて、イベントハンドラで受取れるという訳です。

前掲コード002では、AbstractLoader.onFileLoadイベントのハンドラ(xFileLoaded())は、読込んだ画像をCanvasに描く関数(xDraw())とは別に定めました。これは、描画の関数に引数を渡して呼出すためでした。でも、イベントオブジェクトにdataプロパティを定めれば、それ以外の引数はなしで済ませられます。

読込んだ<image>要素はイベントオブジェクトから参照が得られますので、配置する座標をPointオブジェクトにしてdataプロパティに納めます(<script>要素にEaselJSのPointクラスを加えます)。そうすれば、描画の関数(xDraw())を直接イベントハンドラに定められるでしょう。

function xInitialize() {
  // ...[中略]...
  var position = new Point(canvasObject.width / 2, canvasObject.height / 2);
  // var file = {src:"images/large.png", id:"image"}
  var file = {src:"images/large.png", id:"image", data:position}
  // ...[中略]...
  // loader.onFileLoad = xFileLoaded;

  loader.onFileLoad = xDraw;  // 直接イベントハンドラとして設定
  // ...[中略]...
}
/* 削除
function xFileLoaded(eventObject) {
  xDraw(canvasObject.width / 2, canvasObject.height / 2, eventObject.result);
}
*/
// function xDraw(nX, nY, myImage) {

function xDraw(eventObject) {   // 引数にイベントオブジェクトのみ受取る

画像を配置する座標はPointインスタンスでイベントオブジェクトのdataプロパティとして加え、描画の関数(xDraw())をAbstractLoader.onFileLoadイベントのハンドラに設定したのが、以下のコード003です。 イベントハンドラの関数は、イベントオブジェクトから描画する<image>要素と位置座標のPointオブジェクトを取出して(コード003第30〜31行目)、Bitmapインスタンスの配置と描画を行いました。

コード003■イベントオブジェクトにdataプロパティを加えてハンドラで受取る
  1. <script>
  2. var createjs = window;
  3. </script>
  4. <script src="easeljs/utils/UID.js"></script>
  5. <script src="easeljs/geom/Matrix2D.js"></script>
  6. <script src="easeljs/geom/Point.js"></script>
  7. <script src="easeljs/events/MouseEvent.js"></script>
  8. <script src="easeljs/display/DisplayObject.js"></script>
  9. <script src="easeljs/display/Container.js"></script>
  10. <script src="easeljs/display/Stage.js"></script>
  11. <script src="easeljs/display/Bitmap.js"></script>
  12. <script src="preloadjs/AbstractLoader.js"></script>
  13. <script src="preloadjs/PreloadJS.js"></script>
  14. <script src="preloadjs/TagLoader.js"></script>
  15. <script src="preloadjs/XHRLoader.js"></script>
  16. <script type="text/javascript">
  17.   var stage;
  18.   var myBitmap;
  19.   var canvasObject;
  20.   function xInitialize() {
  21.     canvasObject = document.getElementById('myCanvas');
  22.     var position = new Point(canvasObject.width / 2, canvasObject.height / 2);
  23.     var file = {src:"images/large.png", id:"image", data:position}
  24.     var loader = new PreloadJS(false);
  25.     stage = new Stage(canvasObject);
  26.     loader.onFileLoad = xDraw;
  27.     loader.loadFile(file);
  28.   }
  29.   function xDraw(eventObject) {
  30.     var myImage = eventObject.result;
  31.     var position = eventObject.data
  32.     myBitmap = new Bitmap(myImage);
  33.     myBitmap.x = position.x - myImage.width / 2;
  34.     myBitmap.y = position.y - myImage.height / 2;
  35.     stage.addChild(myBitmap);
  36.     stage.update();
  37.   }
  38. </script>

補足の第2は、複数ファイルの読込みです。PreloadJS.loadFile()メソッドは読込みの処理をキューに加えます。ですから、とくに前の読込みが終わるのを待たずに、複数のファイルを続けざまにロードして構いません(その場合どのファイルが読込まれたのかは、イベントオブジェクトのidプロパティで確かめられます)。

けれど、PreloadJS.loadManifest()メソッドを用いれば、読込むファイルは配列にまとめて入れて引数に渡せるので、呼出しは1度で済みます。ファイルはPreloadJS.loadFile()メソッドと同じように、URLの文字列またはObjectインスタンスとして配列エレメントに加えます。各ファイルの読込みも、AbstractLoader.onFileLoadイベントで捉えます。

var ファイルリスト = [];
ファイルリスト.push({src:URL, id:識別子});
// 複数ファイルを同じように加える
PreloadJSオブジェクト.onFileLoad = イベントハンドラ;
PreloadJSオブジェクト.loadManifest(ファイルリスト);

すべてのファイルを読込み終えると、AbstractLoader.onCompleteイベントが発生します。なお、読込みを途中で止めて、キューから除きたいときには、PreloadJS.close()メソッドを呼出します[*2]

[*1] リファレンスには「Properties」として掲載されています。けれど、その役割は定数と捉えてもよいでしょう。

[*2] ただし、PreloadJS v0.1.0ではこのメソッドは完全ではなく、読込み処理が続いてしまうこともあるそうです。


作成者: 野中文雄
更新日: 2013年1月23日 コードに名前空間を省くscript要素とMouseEventクラスの読込み追加。
作成日: 2012年5月16日


Copyright © 2001-2012 Fumio Nonaka.  All rights reserved.