新しくなったPreloadJSのLoadQueueクラスで外部ファイルを読み込もう

PreloadJSは、画像・音声・XML・JS・CSSなどの外部ファイルの読み込みをサポートしてくれるJavaScriptライブラリです。CreateJSのサイトからダウンロードできます。以前の投稿「PreloadJSで外部ファイルを読み込む」では、PreloadJS 0.1.0時点の使い方を紹介しましたが、先日公開された新バージョンPreloadJS 0.3.xでは仕様が大幅に変更になりました。そこで新しくなったPreloadJSの変更点や基本的な使い方をレポートしたいと思います。

PreloadJSクラスからLoadQueueクラスへ

PreloadJS 0.3.xの最も大きな変更点は、メインとなるクラス名がPreloadJSからLoadQueueへ変わった点です。しかし、それ以外の基本的な使い方はPreloadJS 0.2以前と似ているため、それほど違和感なく移行することができると思います。下記のサンプルでは、LoadQueueインスタンスを生成し、loadFile()で画像ファイルを読み込んでいます。loadFile()の引数はオブジェクト形式で、srcはファイルのパスになります。また、idを指定しておくことでファイルの判別や取得に利用できます。

サンプルでは、読み込んだファイルをLoadQueueインスタンスのgetResult()で取得しています。getResult()の引数にloadFile()で指定したidまたはsrcを指定することで読み込んだファイルを取得できます。以前のバージョンでは、getResult()の戻り値のresultプロパティから読み込んだファイルを取得していましたが、getResult()の戻り値が読み込んだファイルとなるように仕様が変更されたようです。

また、PreloadJS 0.3.xでは、EaselJS 0.6.xと同様にイベントリスナーが導入されました。イベントリスナーの使い方については、「新しくなったCreateJSのイベントリスナーを理解しよう」で解説していますので、よろしければ合わせてご覧下さい。

JavaScript

function load() {
  var loader = new createjs.LoadQueue();
  loader.addEventListener("complete", completeHandler);
  loader.loadFile({src:"img/image_1.jpg", id:"image1"});
}

function completeHandler(evt) {
  var loader = evt.target;
  loader.removeEventListener("complete", completeHandler);
  _image = loader.getResult("image1");
  init();
}

複数のファイルを読み込むならloadManifest()が便利

複数のファイルを読み込む場合は、loadManifest()が便利です。loadManifest()の第1引数に読み込むファイルの情報を保持したオブジェクトを配列に入れて渡すことで、複数のファイルを同時に指定することができます。loadFile()とloadManifest()は第2引数のオプションを持っています。第2引数にfalseを指定すると読み込み開始が自動では行われなくなり、LoadQueueインスタンスのload()メソッドで読み込みが開始されるようになります。第2引数は省略可能でデフォルト値はtrueです。

また、PreloadJSの旧バージョンではファイルのパスにクエリーを付加した場合、typeでファイル形式を指定する必要がありましたが、新バージョンではクエリーを付加した場合も拡張子でファイル形式を判別できるように改良されたようです。

下記のサンプルでは、loadManifest()を使って複数の画像をロードし、"fileload"イベントのリスナー関数で受け取ったイベントオブジェクトのresultプロパティから読み込んだファイルを取得しています。PreloadJSの旧バージョンでは、"fileload"のイベントオブジェクト.idで読み込んだファイルを判別していましたが、新バージョンではイベントオブジェクト.item.idで判別するように変更されたようです。

JavaScript

function load() {
  var loader = new createjs.LoadQueue();
  var query = "?" + new Date().getTime();
  var manifest = [
    {src:"img/image_1.jpg" + query, id:"image1"},
    {src:"img/image_2.jpg" + query, id:"image2"},
    {src:"img/image_3.jpg" + query, id:"image3"}
  ];
  loader.loadManifest(manifest, false);
  function fileloadHandler(evt) {
    switch(evt.item.id) {
      case "image1" :
        _image1 = evt.result;
        break;
      case "image2" :
        _image2 = evt.result;
        break;
      case "image3" :
        _image3 = evt.result;
        break;
    }
  }
  function completeHandler(evt) {
    loader.removeEventListener("fileload", fileloadHandler);
    loader.removeEventListener("complete", completeHandler);
    init();
  }
  loader.addEventListener("fileload", fileloadHandler);
  loader.addEventListener("complete", completeHandler);
  loader.load();
}

LoadQueueクラスのイベント

LoadQueueクラスのイベントを見てみましょう。どのイベントでもリスナー関数に渡されるイベントオブジェクトから情報を得ることができます。共通の項目として、typeでイベントの種類、targetでイベントを送出したLoadQueueインスタンスの参照が得られます。

loadStart
読み込み開始時に送出されます。
filestart
個々のファイルの読み込み開始時に送出されます。イベントオブジェクトのitemプロパティから読み込みの始まったファイルの情報が得られます。
error
エラーが発生した際に送出されます。イベントオブジェクトのitemプロパティからエラーとなったファイルの情報が得られます。
progress
読み込み中に継続的に送出されます。イベントオブジェクトのprogress, loadedプロパティから全体の読み込み状況を0〜1の比率で取得できます。
fileprogress
個々のファイルの進行状況が変化したときに送出されます。イベントオブジェクトのprogress, loadedプロパティから個々のファイルの読み込み状況を0〜1の比率で取得できます。
fileload
個々のファイルの読み込み完了時に送出されます。イベントオブジェクトのitemプロパティから読み込んだファイルのidやsrcが取得できる他、resultプロパティではHTMLタグやパース済みのデータ、rawResultプロパティで生データを取得できます。
complete
すべてのファイルの読み込み完了時に送出されます。

PreloadJSを使ったローディングのサンプル

PreloadJSのLoadQueueクラスを使って、簡単なローディングのサンプルを作ってみました。外部ファイルの読み込み中にローディングのパーセンテージを表示し、読み込みが終わるとスライドショーが始まります。左右のスライドをクリック、中央のスライドをドラッグ or スワイプでスライドを切り替えられます。

LoadQueueインスタンスの生成とXMLの読み込み

サンプルの処理の流れをステップ毎に見てみましょう。まず、LoadQueueインスタンスを生成し、loadFile()でXMLファイルを読み込みます。XMLには、コンテンツで使用するjsonファイル、jsファイル、画像ファイルのパスを記述しています。LoadQueueインスタンスの"fileload"イベントにXMLの読み込みが終わった時に実行するリスナー関数を登録しておきます。

JavaScript

_loader = new createjs.LoadQueue();
var query = "?" + new Date().getTime();
_loader.addEventListener("fileload", xmlLoadedHandler);
_loader.loadFile({src:"xml/files.xml" + query, id:"xml"});

その他ファイルの読み込みとロード状況の取得

XMLの読み込みが終わったら、読み込んだXMLをパースしてloadManifest()の引数に渡す配列を作成します。その他のファイルの読み込みを始める前に、より正確な読み込みのパーセンテージを取得するため、LoadQueueインスタンスのremoveAll()メソッドで先程ロードしたXMLファイルを削除しておきます。

読み込み状況は、"progress"イベントのリスナー関数progressHandler()で取得しています。イベントオブジェクトのprogressプロパティから読み込みの進行状況を取得し、ロードのパーセンテージを表示するProgressArcインスタンスのupdate()メソッドに渡します。

JavaScript

function xmlLoadedHandler(evt) {
  _loader.removeEventListener("fileload", xmlLoadedHandler);
  _loader.removeAll();
  var xml = evt.result;
  var nodes = xml.getElementsByTagName("file");
  var manifest = [];
  var query = "?" + new Date().getTime();
  for (var i = 0, l = nodes.length; i < l; i++) {
    var node = nodes[i];
    var src = node.getAttribute("src");
    var id = node.getAttribute("id");
    manifest.push({src:src + query, id:id});
  }
  function progressHandler(evt) {
    _progressArc.update(evt.progress);
  }
  function fileloadHandler(evt) {
    if (evt.item.type === "image") {
      _images.push(evt.result);
    } else if (evt.item.type === "javascript") {
      document.getElementsByTagName("head")[0].appendChild(evt.result);
    }
  }
  function completeHandler(evt) {
    _loader.removeAllEventListeners();
    _progressArc.exit();
    var config = _loader.getResult("json");
    _slider = new SlideContainer(_images, config);
    _slider.regX = -_canvas.width >> 1;
    _slider.regY = -_canvas.height >> 1;
    _stage.addChild(_slider);
    _loader.removeAll();
    _loader = null;
  }
  _loader.addEventListener("progress", progressHandler);
  _loader.addEventListener("fileload", fileloadHandler);
  _loader.addEventListener("complete", completeHandler);
  _loader.loadManifest(manifest);
}

読み込みのパーセンテージを表示する

下記は、読み込みのパーセンテージを表示するProgressArcクラスのupdate()メソッドです。プログレスバーとして、Graphicsクラスのarc()メソッドでロード状況を表示するサークルを描画します。また、Textクラスで読み込みのパーセンテージを表示しています。

JavaScript

p.update = function(ratio) {
  var endAngle = ((-90 + ratio * 360) >> 0) * createjs.Matrix2D.DEG_TO_RAD;
  var g = this.shape.graphics;
  g.c().ss(this.thickness, 0, 0, 10, true).s(this.color).a(0, 0, this.radius, this.startAngle, endAngle).es();
  var percent = (ratio * 100) >> 0;
  var percent_txt;
  if (percent < 100) {
    percent_txt = (percent < 10) ? "  " + percent : " " + percent;
  } else {
    percent_txt = "100";
  }
  this.text.text = percent_txt + "%";
};