サイトトップ

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

HTML5 / Flash ActionScript講座
HTML5のCanvasでつくる
ダイナミックな表現
―CreateJSを使う
Twitter: @FumioNonaka
Facebook Page: CreateJS

CreateJS Workshop

外部ファイルの読込みとサウンドの再生
〜新しいPreloadJSとSoundJS〜

    お品書き
  • 01 画像イメージを読込んでCanvasに置く
    • 01-01 前回までのあらすじ ー CanvasにStageオブジェクトをつくる
    • 01-02 Stageオブジェクトに外部画像ファイルの含まれたBitmapインスタンスを置く
  • 02 PreloadJSで外部画像ファイルの読込みを待つ
    • 02-01 LoadQueueクラスで外部ファイルを読込む
    • 02-02 読込んだ画像イメージにもとづいてBitmapインスタンスの基準点を定める
  • 03 SoundJSでサウンドを操作する
    • 03-01 LoadQueueクラスにより読込んだサウンドファイルをSoundクラスで再生する
    • 03-02 サウンドの一時停止と再開
    • 03-03 サウンドの再生終了のイベントと再生
    • 03-04 SoundJSライブラリのメモリの扱いが改善された

日本時間2013年2月14日に公開されたCreateJSの新バージョンにもとづいて解説する。リンクしたサンプルのHTMLファイルは、ライブラリをダウンロードしなくて済むよう、CDN(Content Delivery Network)のライブラリを使った。このレジュメをもとに解説したCreateJS勉強会の録画は「第二回勉強会フォローアップ」で公開されている。

01 画像イメージを読込んでCanvasに置く

まずはおさらいも兼ねて、外部PNGファイルの画像イメージが含まれたオブジェクトを、Canvasに置いてみよう。

01-01 前回までのあらすじ ー CanvasにStageオブジェクトをつくる

HTMLドキュメントのbody要素にcanvas要素を加え、id属性にJavaScriptで参照するための名前("myCanvas")をつける。また、body要素のonload属性には、初期設定の関数の呼出し("initialize()")を定めておく。

<body onLoad="initialize()">
  <canvas id="myCanvas" width="240" height="180"></canvas>
</body>

HTMLドキュメントのhead要素には、script要素でEaselJSライブラリを読込む(ライブラリは予めダウンロードしておく)。なお、抜書きするステートメントの行番号は、後にscript要素全体を掲げるコード001にもとづく。

  1. <script src="lib/easeljs-0.6.0.min.js"></script>

EaselJSを使うには、まずCanvasにステージ(Stageオブジェクト)をつくらなければならない。new演算子でStageクラスのコンストラクタを呼出し、引数にはcanvas要素の参照を渡す。なお、CreateJSのクラスを参照するときは、頭に「名前空間」として「createjs」を添える。

new createjs.Stage(canvas要素)

canvas要素の参照は、document.getElementById()メソッドにidを渡すと得られる(第5行目)。初期設定の関数(initialize())で、Stageオブジェクトをつくった(第6行目)。

  1. var stage;
  2. function initialize() {
  1.   var canvasElement = document.getElementById("myCanvas");
  2.   stage = new createjs.Stage(canvasElement);
  1. }

01-02 Stageオブジェクトに外部画像ファイルの含まれたBitmapインスタンスを置く

画像イメージはBitmapインスタンスに入れる。new演算子でBitmapクラスのコンストラクタを呼出し、引数には外部画像ファイルのURLを渡す。

new createjs.Bitmap(画像ファイルのURL)

インスタンスをCanvasに表示するためには、Stageオブジェクトの子に加えなければならない。Stageオブジェクトに対してContainer.addChild()メソッドを呼出し、加えたい子オブジェクトを引数に渡す。

親オブジェクト.addChild(子オブジェクト)

Bitmapインスタンスをつくる関数(createBitmap())は、別に定めた(第12〜17行目)。関数の引数に配置するxy座標と画像ファイルのURLを渡すと、つくったインスタンスが返される(第8行目)。そのインスタンスをStageオブジェクトの子に加えている(第9行目)。なお、Canvasの描画を更新するためには、必ずStage.update()メソッドを呼出さなければならない(第10行目)。

  1. function initialize() {
  2.   var url = "images/Pen.png";
  1.   var myBitmap = createBitmap(canvasElement.width / 2, canvasElement.height / 2, url);
  2.   stage.addChild(myBitmap);
  3.   stage.update();
  4. }
  5. function createBitmap(nX, nY, url) {
  6.   var myBitmap = new createjs.Bitmap(url);
  7.   myBitmap.x = nX;
  8.   myBitmap.y = nY;
  9.   return myBitmap;
  10. }

script要素全体を以下のコード001にまとめた。まだ、でき上がりではない。HTMLドキュメントを開くと、何もCanvasに描かれず、とくにエラーもでない。再読込みをすれば、画像は表れる(図001)。ただし、Bitmapインスタンスの基準点は、デフォルトでは左上角に置かれる。

図001■ドキュメントを再読込みしないと画像が表れない
図001

コード001■外部画像ファイルのイメージが含まれたBitmapインスタンスをCanvasに置く
  1. <script src="lib/easeljs-0.6.0.min.js"></script>
  2. <script>
  3. var stage;
  4. function initialize() {
  5.   var url = "images/Pen.png";
  6.   var canvasElement = document.getElementById("myCanvas");
  7.   stage = new createjs.Stage(canvasElement);
  8.   var myBitmap = createBitmap(canvasElement.width / 2, canvasElement.height / 2, url);
  9.   stage.addChild(myBitmap);
  10.   stage.update();
  11. }
  12. function createBitmap(nX, nY, url) {
  13.   var myBitmap = new createjs.Bitmap(url);
  14.   myBitmap.x = nX;
  15.   myBitmap.y = nY;
  16.   return myBitmap;
  17. }
  18. </script>

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

画像イメージが初めに表れないのは、読込みをまたずにStage.update()メソッドを呼出しているからだ。そこで、PreloadJSライブラリを使って読込み待ちすることになる。

02-01 LoadQueueクラスで外部ファイルを読込む

まず、PreloadJSライブラリをscript要素に読込む。最新バージョンは0.3.0だ。ステートメントの行番号は、後でscript要素全体を掲げるコード002にもとづく。

  1. <script src="lib/preloadjs-0.3.0.min.js"></script>

PreloadJSライブラリの名前は変わらないものの、おもに用いられるクラス名がPreloadJSからLoadQueueに変わった。LoadQueueクラスのコンストラクタには、引数にXMLHttpRequest(XHR)を使うかどうかのブール(論理)値を渡す(第9行目)。

new createjs.LoadQueue(XMLHttpRequestの使用)

読込み終えたときに呼出す関数は、EventDispatcher.addEventListener()メソッドでLoadQueue.fileloadイベントにリスナーとして定める(第11行目)。

LoadQueue.loadFile()メソッドに外部ファイルのパスを文字列で渡せば、読込みが始まる(第12行目)。

LoadQueue.loadFile(読込むファイルのURL)

LoadQueue.fileloadイベントのリスナー関数(draw())は、Stage.update()メソッドの呼出しによりステージを書替える(第21〜23行目)。そのため、初期設定の関数(initialize())はメソッドを呼出さなくてよい。

  1. function initialize() {
  2.   var url = "images/Pen.png";
  1.   var loader = new createjs.LoadQueue(false);
  1.   loader.addEventListener("fileload", draw);
  2.   loader.loadFile(url);
      // stage.update();
  1. }
  1. function draw(eventObject) {
  2.   stage.update();  
  3. }

ここまで書き加えたスクリプトは、つぎのコード002のとおりだ。これで、HTMLドキュメントを初めて開いても、画像ファイルの読込みを待ってステージが描かれる。

コード002■PreloadJSで外部画像ファイルの読込みを待つ
  1. <script src="lib/easeljs-0.6.0.min.js"></script>
  2. <script src="lib/preloadjs-0.3.0.min.js"></script>
  3. <script>
  4. var stage;
  5. function initialize() {
  6.   var url = "images/Pen.png";
  7.   var canvasElement = document.getElementById("myCanvas");
  8.   stage = new createjs.Stage(canvasElement);
  9.   var loader = new createjs.LoadQueue(false);
  10.   var myBitmap = createBitmap(canvasElement.width / 2, canvasElement.height / 2, url);
  11.   loader.addEventListener("fileload", draw);
  12.   loader.loadFile(url);
  13.   stage.addChild(myBitmap);
  14. }
  15. function createBitmap(nX, nY, url) {
  16.   var myBitmap = new createjs.Bitmap(url);
  17.   myBitmap.x = nX;
  18.   myBitmap.y = nY;
  19.   return myBitmap;
  20. }
  21. function draw(eventObject) {
  22.   stage.update();  
  23. }

02-02 読込んだ画像イメージにもとづいてBitmapインスタンスの基準点を定める

ステージに置かれたBitmapインスタンスの基準点は、まだデフォルトの左上角にあるままだ。これを画像イメージの真ん中に移したい。基準点はDisplayObject.regXDisplayObject.regYプロパティで変えられる。けれど、Bitmapオブジェクトにはwidthやheightといったプロパティはない。読込んだ画像イメージの大きさは、LoadQueue.fileloadイベントのリスナー関数が受取るイベントオブジェクトからresultプロパティで調べる。

Bitmapインスタンスの基準点を変えるには、オブジェクトの参照を何らかのかたちで得なければならない。もちろん、グローバルな変数に入れれば簡単だ。けれど、ここではLoadQueue.loadFile()メソッドで渡してみる。

LoadQueueオブジェクト.loadFile({src:読込むファイルのURL, data:任意のデータ})

LoadQueue.loadFile()メソッドの引数にはURLの文字列でなく、Objectインスタンスが渡せる。URLはオブジェクトのsrcプロパティに定める。さらに、dataプロパティとして任意のデータが加えられる。ここにBitmapインスタンスを入れよう(第9行目)。抜書きした行番号は、後にスクリプト全体をまとめたコード003にもとづく。

LoadQueue.fileloadイベントのリスナー関数(draw())は、引数に受取ったイベントオブジェクトのitemプロパティからdataプロパティに与えたデータが取出せる(第19行目)。

  1. function initialize() {
  2.   var url = "images/Pen.png";
  1.   var loader = new createjs.LoadQueue(false);
  2.   var myBitmap = createBitmap(canvasElement.width / 2, canvasElement.height / 2, url);
  3.   loader.addEventListener("fileload", draw);
      // loader.loadFile(url);
  4.   loader.loadFile({src:url, data:myBitmap});
  1. }
  1. function draw(eventObject) {
  2.   var myBitmap = eventObject.item.data;
  3.   var myImage = eventObject.result;
  4.   myBitmap.regX = myImage.width / 2;
  5.   myBitmap.regY = myImage.height / 2;
  6.   stage.update();  
  7. }

これで、LoadQueue.fileloadイベントのリスナー関数(draw())は、読込んだ画像の大きさにもとづいて、Bitmapインスタンスの基準点を画像イメージの真ん中に定める(図002)。スクリプト全体は、以下のコード003のとおりだ。

図002■読込んだ画像メージの大きさにもとづいてBitmapインスタンスの基準点が中心に定められた
図002

コード003■PreloadJSで外部画像ファイルが読込まれたらインスタンスの基準点を定める
  1. var stage;
  2. function initialize() {
  3.   var url = "images/Pen.png";
  4.   var canvasElement = document.getElementById("myCanvas");
  5.   stage = new createjs.Stage(canvasElement);
  6.   var loader = new createjs.LoadQueue(false);
  7.   var myBitmap = createBitmap(canvasElement.width / 2, canvasElement.height / 2, url);
  8.   loader.addEventListener("fileload", draw);
  9.   loader.loadFile({src:url, data:myBitmap});
  10.   stage.addChild(myBitmap);
  11. }
  12. function createBitmap(nX, nY, url) {
  13.   var myBitmap = new createjs.Bitmap(url);
  14.   myBitmap.x = nX;
  15.   myBitmap.y = nY;
  16.   return myBitmap;
  17. }
  18. function draw(eventObject) {
  19.   var myBitmap = eventObject.item.data;
  20.   var myImage = eventObject.result;
  21.   myBitmap.regX = myImage.width / 2;
  22.   myBitmap.regY = myImage.height / 2;
  23.   stage.update();  
  24. }

03 読込んだサウンドファイルをSoundJSで操作する

外部MP3サウンドファイルをPreloadJSで読込んで、SoundJSを用いて再生する。ふたつのライブラリはCanvasが要らないので、EaselJSは使わなくてよい。

03-01 LoadQueueクラスにより読込んだサウンドファイルをSoundクラスで再生する

script要素には、PreloadJSとSoundJSのライブラリを読込む。SoundJS 0.4.0でおもに用いるクラス名が、SoundJSからただのSoundに変わった。サウンドの操作の仕方も前のバージョンとは異なる。

  1. <script src="lib/preloadjs-0.3.0.min.js"></script>
  2. <script src="lib/soundjs-0.4.0.min.js"></script>

LoadQueueクラスを用いた外部サウンドファイルの読込み方は、基本的に画像ファイルの場合と同じ。ただし、LoadQueue.installPlugin()メソッドの引数にSoundクラスの参照を渡して、プラグインを登録しなければならない(第8行目)。抜書きするステートメントの行番号は、後にscript要素に書いたスクリプト全体を掲げるコード004にもとづく。

LoadQueueオブジェクト.installPlugin(createjs.Sound)

LoadQueue.loadFile()メソッドに渡すObjectインスタンスには、idプロパティを定めておくと、後でサウンドが扱いやすい(第10行目)。

  1. function initialize() {
  2.   var url = "sounds/test.mp3";
  3.   var loader = new createjs.LoadQueue(false);
  4.   loader.installPlugin(createjs.Sound);
  5.   loader.addEventListener("fileload", soundLoaded);
  6.   loader.loadFile({src:url, id:"music"});
  7. }

LoadQueue.fileloadイベントのリスナー関数(soundLoaded())は、静的メソッドSound.play()でサウンドを再生する。メソッドの引数には、イベントオブジェクト(eventObject)のitemプロパティから前に定めた(第10行目)idプロパティの値を取出して渡す(第13〜14行目)。メソッドの返すSoundInstanceオブジェクトは、後でサウンドの操作に用いるので、グローバルな変数(instance)にとっておく(第4行目)。

createjs.Sound.play(サウンドのID)
  1. var instance;
  1. function soundLoaded(eventObject) {
  2.   var sound = eventObject.item.id;
  3.   instance = createjs.Sound.play(sound);
  4. }

つぎのコード004は、PreloadJSにより外部MP3サウンドを読込んで、SoundJSで再生する。body要素には何も加えていないので、HTMLドキュメントは空白のままだ。

コード004■PreloadJSにより外部サウンドファイルを読込んでSoundJSで再生する
  1. <script src="lib/preloadjs-0.3.0.min.js"></script>
  2. <script src="lib/soundjs-0.4.0.min.js"></script>
  3. <script>
  4. var instance;
  5. function initialize() {
  6.   var url = "sounds/test.mp3";
  7.   var loader = new createjs.LoadQueue(false);
  8.   loader.installPlugin(createjs.Sound);
  9.   loader.addEventListener("fileload", soundLoaded);
  10.   loader.loadFile({src:url, id:"music"});
  11. }
  12. function soundLoaded(eventObject) {
  13.   var sound = eventObject.item.id;
  14.   instance = createjs.Sound.play(sound);
  15. }
  16. </script>

03-02 サウンドの一時停止と再開

再生しているサウンドの一時停止や再開には、SoundInstanceクラスのメソッドSoundInstance.pause()およびSoundInstance.resume()を用いる。

SoundInstanceオブジェクト.pause()
SoundInstanceオブジェクト.resume()

一時停止と再生(再開)はボタンひとつで切替えることにして、body要素にinput要素のボタンを置く(図003)。そして、JavaScriptで操作するためのid属性("control")を定めておく。

図003■body要素にはinput要素のボタンを置く
図003

<body onLoad="initialize()">
  <input type="button" value="準備中" id="control">
</body>

まず、ボタンのinput要素の参照は、グローバルな変数にとっておく(第2および第9行目)。そして、LoadQueue.fileloadイベントのリスナー関数(soundLoaded())は、ボタンのonclickイベントにサウンドの一時停止の関数(pauseSound())をハンドラとして定める(第15行目)。スクリプト全体は、後にコード005として掲げた。

ボタンがクリックされると、ハンドラ(pauseSound())がSoundInstance.pause()メソッドでサウンドを一時停止するとともに、onclickハンドラをサウンド再開の関数(resumeSound())に差替える(第19〜20行目)。再びボタンを押すと、SoundInstance.resume()メソッドにより、サウンドが再開される(第24行目)。そして、onclickハンドラの関数は一時停止(pauseSound())に戻される(第25行目)。

  1. var control;
  2. function initialize() {
  1.   control = document.getElementById("control");
  1. }
  1. function soundLoaded(eventObject) {
  1.   control.onclick = pauseSound;
  1. }
  2. function pauseSound(eventObject) {
  3.   instance.pause();
  4.   control.onclick = resumeSound;
  1. }
  2. function resumeSound(eventObject) {
  3.   instance.resume();
  4.   control.onclick = pauseSound;
  1. }

つぎのコード005は、再生されたサウンドが、ボタンを押すと一時停止し、ふたたびクリックすれば再開する。ただし、再生し終わったサウンドは、ボタンを押しても再生されない。なお、サウンドの再生状況がわかるように、ボタンのvalueプロパティの文字列を切替えている(図004)。

図004■サウンドの再生状況によりボタンの表記が変わる
←→

コード005■再生したサウンドをボタンで一時停止および再開する
  1. var instance;
  2. var control;
  3. function initialize() {
  4.   var url = "sounds/test.mp3";
  5.   var loader = new createjs.LoadQueue(false);
  6.   loader.installPlugin(createjs.Sound);
  7.   loader.addEventListener("fileload", soundLoaded);
  8.   loader.loadFile({src:url, id:"music"});
  9.   control = document.getElementById("control");
  10.   control.value = "読込み中";
  11. }
  12. function soundLoaded(eventObject) {
  13.   var sound = eventObject.item.id;
  14.   instance = createjs.Sound.play(sound);
  15.   control.onclick = pauseSound;
  16.   control.value = "一時停止";
  17. }
  18. function pauseSound(eventObject) {
  19.   instance.pause();
  20.   control.onclick = resumeSound;
  21.   control.value = "再生";
  22. }
  23. function resumeSound(eventObject) {
  24.   instance.resume();
  25.   control.onclick = pauseSound;
  26.   control.value = "一時停止";
  27. }

03-03 サウンドの再生終了のイベントと再生

再生が終わったサウンドを改めて頭から再生し直すにはSoundInstance.play()メソッドを用いる。また、サウンドが再生し終わったことは、SoundInstance.completeイベントで捉えられる。

SoundInstanceオブジェクト.play()

そこでまず、EventDispatcher.addEventListener()メソッドでSoundInstance.completeイベントにリスナー関数(resetSound())を加える(第15行目)。この関数は、ボタンのonclickイベントにサウンドが改めて再生されるハンドラの関数(restartSound())を定める(第30行目)。そして、ボタンが押されると、ハンドラが呼出されて、サウンドは頭から再生される(第34行目)。スクリプト全体は、後にコード006として掲げた。

  1. function soundLoaded(eventObject) {
  2.   var sound = eventObject.item.id;
  3.   instance = new createjs.Sound.play(sound);
  4.   instance.addEventListener("complete", resetSound);
  1. }
  1. function resetSound(eventObject) {
  2.   control.onclick = restartSound;
  1. }
  2. function restartSound() {
  3.   instance.play();
  4.   control.onclick = pauseSound;
  1. }

これで、サウンドの再生中に一時停止と再開ができるとともに、再生が終わっても頭から再生し直せるようになった。

コード006■サウンドの一時停止と再開に加えて再び再生する処理を定めた
  1. var instance;
  2. var control;
  3. function initialize() {
  4.   var url = "sounds/test.mp3";
  5.   var loader = new createjs.LoadQueue(false);
  6.   loader.installPlugin(createjs.Sound);
  7.   loader.addEventListener("fileload", soundLoaded);
  8.   loader.loadFile({src:url, id:"music"});
  9.   control = document.getElementById("control");
  10.   control.value = "読込み中";
  11. }
  12. function soundLoaded(eventObject) {
  13.   var sound = eventObject.item.id;
  14.   instance = new createjs.Sound.play(sound);
  15.   instance.addEventListener("complete", resetSound);
  16.   control.onclick = pauseSound;
  17.   control.value = "一時停止";
  18. }
  19. function pauseSound() {
  20.   instance.pause();
  21.   control.onclick = resumeSound;
  22.   control.value = "再生";
  23. }
  24. function resumeSound() {
  25.   instance.resume();
  26.   control.onclick = pauseSound;
  27.   control.value = "一時停止";
  28. }
  29. function resetSound(eventObject) {
  30.   control.onclick = restartSound;
  31.   control.value = "再生";
  32. }
  33. function restartSound() {
  34.   instance.play();
  35.   control.onclick = pauseSound;
  36.   control.value = "一時停止";
  37. }

03-04 SoundJSライブラリのメモリの扱いが改善された

旧バージョンのSoundJSライブラリは、一時停止や再開も含めて静的メソッドにサウンドのIDを渡してコントロールした。SoundInstanceオブジェクトの参照をもたなくても済む半面、つくったオブジェクトがクラスに残ったままメモリから除けなかった。SoundJS 0.4.0では、再生し終えたSoundInstanceオブジェクトは、参照をもち続けないかぎりメモリから消されるように改善された(詳しくは、「新CreateJSでSoundJS 0.4.0のメモリの扱いが向上した」参照)。



作成者: 野中文雄
作成日: 2013年3月16日


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