POPSブログ

CreateJS、で「TickerクラスのaddEventListener設定」を考える

213

  Category:  javascript2013/04/17 pops 

CreateJSで作るコンテンツ類のほとんどは「アニメーション」などの変化を伴う。AS3で言えばenterFrame機能のような「Tickerクラス」を使い変化させたり、Tween実行時、あるいは通常のCanvas更新に利用される。easeljs-0.8用に書き直した。

 

CreateJS、で「TickerクラスのaddEventListener設定」を考える


2014/12/13/EaselJSなどバージョンUPされました(easeljs-0.8)。easeljs-0.8用に更新しています。(2015/02/27)


「Tickerクラス」はバージョン easeljs-0.8 addEventListenerメソッドで説明しますので、昔のaddListenerメソッドは言及しません。on() off()で設定する方法が増えている。
以下、説明はテストなどの結果であり、記述方法などは個人により違うかとは思います。
あくまでも私は「初心者」ですので、正確を期すには「専門家」の記事等を参照クダサイ

 

[ 目次 ]


addEventListenerメソッドの使用方法

▲[ 目次 ]

addEventListenerメソッドは色々なイベントに対するリスナー設定して処理する関数であるが、ここでは「Ticker」クラスに限定しての説明です。他のイベントは別ページで説明します。
「Ticker」クラスはAS3のenterFrame機能と同じようなものです。


Ticker

▲[ 目次 ]

一定時間内にtickイベントを配信する仕組みです。AS3で言えばenterFrame機能と同じような仕組みです。
tickイベントを拾うリスナーはtickイベントに反応して何らかの処理を行う様に設定します。


1.「Canvasを更新」するため、stage.update() の目的にのみ「Tickerクラス」を設定する。
2. インスタンスを動かしたり、計算処理をする「Tickerクラス」を設定する。
3. Tickerのtick配信間隔は負荷によって変わり、必ずしも正確ではない。


Canvasを更新するupdate()

▲[ 目次 ]

Canvasを更新するには、任意の場所でstage.update()を実行すれば、該当ステージのそれまでの更新などが再描画される。その正体はステージCanvasエレメントに描画されたPNG画像です。


● その都度、stage.update()を行う。
変更された箇所が、stage.update()で再描画、反映されます。対象は、stageに成ります。



//ステージに640x300のShapeを描画

var backrect=new createjs.Shape();
backrect.graphics.beginFill("#FFFFFF").drawRect(0,0,640,300);
stage.addChild(backrect);
stage.update();

------------------------------------------
これは画像処理に時間がかかり表示されるとは限らない

var welcomeImage;
//welcome画像層画像ロード表示
welcomeImage=new createjs.Bitmap("/main/images/yakeix.png");
//画像処理が終わらないのに実行する
stage.addChild(welcomeImage);

------------------------------------------
これはすぐ表示される

var welcomeImage;
//welcome画像層画像ロード表示
welcomeImage=new createjs.Bitmap();//空
stage.addChild(welcomeImage);
//ImageLoaderクラス
var bkloader=new createjs.ImageLoader("/main/images/yakei.png",false);
bkloader.addEventListener("complete",function(event) {
	//Bitmap代入
	welcomeImage.image=new createjs.Bitmap(event.result).image;

});
bkloader.load();

Canvasを更新する「Tickerクラス」設定

▲[ 目次 ]

CanvasではAS3の様に最初から自動で画面描画の更新するようにはなっていませんので、一定の間隔で、再描画、stage.update()を行う仕組みを作らねば成りません。
それが「Tickerクラス」なのですが、使用者がリスナーを作くり設定します。
その事により、更新された箇所、グラフイックアニメーションなども連続して描画されます。


update()はステージ単位になります。中のインスタンス単位では有りません。


[ マニュアル拠り抜粋 ]



createjs.Ticker.addEventListener("tick", handleTick);
function handleTick(event) {
	// Actions carried out each frame
}
-------------------------------------------------
Methods
addEventListener (type listener) listener Function | Object
removeEventListener (type listener)
removeAllEventListeners ([type])

addEventListener()メソッドの第2引数には,関数名のほかに、オブジェクトを渡す事も出来ると書いてある。


stage指定update()用のaddEventListener

▲[ 目次 ]

初期時にステージに対して、デフォルト50ms(20FPS)のtickイベントが設定されていますので、下記のリスナーを設定配置すればstage.update()を行ように作られています。

下記の簡易形はステージ対象で色々な条件などは指定出来ない形になっています。



//ステージ
stage=new createjs.Stage('mainCanvas');
//ステージtickイベントリスナー
createjs.Ticker.addEventLister('tick',stage);
//削除
createjs.Ticker.removeEventLister('tick',stage);

//on() off()設定の場合
createjs.Ticker.on('tick',stage);
createjs.Ticker.off('tick',stage);

上記の説明。Ticker.addEventListener()で、update目的だけなら、stageを渡せるのだそうだ 。

【参考】gihyo.jp記事: 第2回 トゥイーンをランダムに定める


stageを渡せる/stage update()出来る
createjs.Ticker.addEventListener("tick",stage);
addEventListener()メソッドの第2引数には,オブジェクトを渡すこともできる

引数に stage で自動で update() もしてくれるソウナ。でも、何となく間違いそうだ!。


リスナー関数を指定してupdate()を実行

▲[ 目次 ]

最も、一般的な設定方法だと思います。リスナー関数を指定してupdate()を実行しますので、ここに、stage.update()を記述します。この場合、リスナー関数に色々な条件なども書き込む事が出来ます。描画変更などがあればすぐに反映されるが、時として実行しない場合もあるので注意ください。


リスナー設定は任意の時点で行えます。使用しない場合は一旦削除することが推奨されていますが、ほとんどは設定しっぱなしです。通常は面倒でやってられないです。


リスナー関数を指定する方が細やかな処理が出来ますので、私としてはこちらを使用する。
FPSは20-30位、重い場合はFPS値を小さくする。アニメーションなどの形態によってはそれ以上の場合も有ります。この辺は使用者の都合でしょう。


FPS

AS3で言えばenterFrame機能と同じく、1秒当たりの更新回数も設定できる。デフォルト50ms(20FPS)。
例では、1分間に30回のtickイベントを発信して、対応するリスナーはtickイベント毎ステージの更新を行います。



同じ、前の設定方法と変わらない
createjs.Ticker.setFPS(30);//数値は自由

FPSよりも正確な設定ほうほうがあるそうです。わたしは使ったことがないので、下記記事を参照ください。

Ticker.timingModeプロパティについては下記参照ください。

【参考】HTML5:テクニカルノート記事: EaselJS 0.7.0のTickerクラスでrequestAnimationFrameのAPIを使う - Ticker.timingModeプロパティ

EventLister

「Canvasを更新」するため、stage.update() の目的にのみ「Tickerクラス」を設定するのがベターです。



この設定方法が一番確実です
createjs.Ticker.addEventLister('tick',.....);
createjs.Ticker.removeEventLister('tick',.....);

下記が標準的な設定で任意の場所で設定すれば良い。stage.update()のみ目的とする




//tickイベントの回数設定
createjs.Ticker.setFPS(30);
//リスナー設定
createjs.Ticker.addEventListener("tick", handleTick);

//リスナー、event無くとも動作する
function handleTick(event) {
	stage.update();
}

-------------------------------------------
//stage.updateの制御
//リスナー条件設定
function handleTick(event) {
	if(条件) {
		stage.update();
	}
}


私の場合は、下記の様にstage.update()専用です。
eventは無くとも良い。当初は設定、削除を繰り返していたが、現在は面倒なのでそのままです。
リスナー設定後は何らかの特別な事情がない限り、stage.update()の記述はしません。




//MAIN-Ticker設定
createjs.Ticker.setFPS(30);
createjs.Ticker.addEventListener('tick',tick);

//tickステージ
function tick(event) {
	stage.update();
}

tick()でインスタンスを回転させる例

▲[ 目次 ]

AS3のenterFrameで色々な処理を行っていたように、リスナー関数 (下記例では、tick()、名前は随意です) の中で同様のことが出来る、
● Tweenでは出来ないインスタンスを動かすのが本業だ。
● Canvas更新stage.updateはアルバイトです。
下は単に画像を回転させているだけですが。(topImage、backImageは、Bitmap()の画像インスタンスとする)
tick イベント毎に画像インスタンス(topImage)が回転すると言う訳です。


これは、余り使用されない。インスタンスに固有のリスナーを設定する方が合理的。
この辺は設計次第であり、その時の描画などの条件により変わります。


stage.update()は専用の「Ticker」で行ったは方がベターと思う。



関数名は随意です

//tick
function tick() {
	topImage.rotation +=5;
	stage.update();
}

-------------------------------------------------

updateさせるかの変数で制御
var update=true;
function tick() {
	if (update) {
		stage.update();
	}
}

-------------------------------------------------

tick()処理させるかの変数で制御
var topImage_flag=true;
function tick() {
	if (topImage_flag) {
		//左巻き回転は健康に良くない
		topImage.rotation -=5;
	}
	stage.update();
}

-------------------------------------------------

tick()処理させるかの変数で、複数を制御
var topImage_flag=true;
var backImage_flag=false;
function tick() {
	if (topImage_flag) {
		topImage.rotation +=5;
	}
	if (backImage_flag) {
		backImage.rotation +=10;
	}
	stage.update();
}

CreateJSでの処理速度はFLASHの1/3程度である。プラグインでは無いので、つまりは重い。

tick()は1秒当たりの処理回数が多い分、中に判定など入れる場合は「単純で判定も早くなる」ように各自工夫している様である。
仮に画像の「表示」「非表示」の状態で判別するならなら、if (topImage.visible) {}、とした場合 topImage.visible の判定に時間がかかる。そこで何らかの変数を用意して識別する。これらは各自の判断による。


複数のインスタンスにTicker機能を個別に設定

▲[ 目次 ]

インスタンスに固有のリスナーを設定する

createjs.Ticker...の「Ticker」クラスではなく、通常のイベントリスナーに「tickイベント」を拾うようにしたものです。

あっちこっちで、stage.update()を実行するのは効率的ではなく、むしろ負荷が大きくマシンが狂うので、
インスタンス (たとえばLoadingなど) に固有のリスナーを設定した方が良い。
stage.update()は、専用のTickerに任せてここではしない。

tickイベントの処理は結構面倒なので、tweenで実行出来るものはtweenで実行して、それ以外のものを処理した方が利口である。tickイベントではupdate()はしない。


通常は、関数を分離して処理する。(推奨)


インスタンス.addEventListener('tick',xxxTick);

function xxxTick (event){
	//処理を書くupdate()はしない、エラー
}

インスタンスに直接、関数を処理すると削除が出来ない。


インスタンス.addEventListener('tick',function(event){
	//処理を書くupdate()はしない、エラー
}

インスタンスに対してイベントリスナーを設定するだけであるが、削除できる形式で作るかの問題だけです。

tickイベントで処理する場合は注意が必要です。


1. インスタンス.addEventListener('tick',listener)、で作ると削除できる。
2. インスタンス.addEventListener('tick',function () {...})、で作ると問題がでる。(危ない書き方、参照)
3. インスタンス.tick=function () {...}、などと工夫して作ると良いようで有る。これは削除できる。


● リスナーを設定してもupdate()を実行しない場合もあります。

グラフイック描画変更などの場合に多く見受けられますは、たとえば次のようなグラフイック描画変更で更新されない場合は、強制的にstage.update()を実行すれば良い。



グラフイック描画変更で更新されない時もある、気分の問題でしょう

btn.shadow=new createjs.Shadow("#000000",0,0,4);
//rollover
btn.addEventListener("rollover",function(){
	btn.graphics.clear();
	btn.graphics.beginFill("#FF0000").........
	stage.update();//必要であれば
});

on() off()で設定する

▲[ 目次 ]

easeljs-0.8では全てがクラス化されて、on() off()の設定できる範囲、イベントの種類も増えていますので、下記設定でも機能します。loadingを例にとれば、
どれが良いのか判別が付かない。loadingShape.on()は回転が速い。

最近は on() off() で設定するのが多くなっている。便利だが「tickイベント」は色々と確認が必要です。
createjs.Ticker.... 形式で設定がマチガイが少ないようです。




loading addEventListenerを設定
createjs.Ticker.addEventListener('tick',loadingShape_tick);
と同等である
createjs.Ticker.on('tick',loadingShape_tick);
loadingShape.on('tick',loadingShape_tick);//回転が早い

------------------------------------------------

loading EventListener削除
createjs.Ticker.removeEventListener('tick',loadingShape_tick);
と同等である
createjs.Ticker.off('tick',loadingShape_tick);
loadingShape.off('tick',loadingShape_tick);


● インスタンスに設定した on('tick',...) リスナーを削除するには


//loadingインスタンス
loadingShape.on('tick',loadingShapeListener);

//リスナーはこの形式で書く事
functin loadingShapeListener() {

	//処理
}
------------------------------------------------
//これは削除できない
loadingShapeListener=function() {
	//
}

危ない書き方

▲[ 目次 ]

危険な設定(削除し難い、エラーになる)

下記のような設定は、削除出来なくなるので使用しない方が良い。(削除する方法はあるのだが面倒です)
設定が手軽なので、もし使用する場合は、削除しない条件で設定したほうが良い。


注意、stage.update()を書いてはいけない。エラーになります。(tickイベントを拾って動作しているので、tickイベントを発行するstage.updateは記述できない、これがエラーの原因のようだ)



loadingShape.addEventListener('tick',function(event){

	loadingShape.rotation +=5;
	//stage.update()を書いてはいけない、エラー

});


//上と同等/削除できない
loadingShape.on('tick',function(event){

	loadingShape.rotation +=5;

});

削除の参考


第2引数 function名 が無いので削除が困難だ

これでも削除出来ない、書き方が悪いのか
loadingShape.removeEventListener('tick',arguments.callee);

全て削除で、削除はできる
loadingShape.removeAllEventListeners('tick');

確認は、loadingShape.hasEventListener('tick') で出来る
在れば true、削除されていれば false

● この形は、tickイベント以外で使われることが多い

tickイベントでは使い難い面はあるが、その他のイベントなら使い易い。clickイベントの例、



//クリックアクション
btn.addEventListener('click',function(event){
	//処理を書く
});
//上と同等
btn.on('click',function(event){
	//処理を書く
});

btn.addEventListener('click',handleClick);
btn.on('click',handleClick);

//リスナー
function handleClick(event){
	//処理を書く

}

削除出来る設定方法

オブジェクト、Function、にもリスナー設定が出来るので、下記のような設定は削除出来る。負荷が大きい様なのでstage.update()は書かない方が良い。
loadingShape.tickの「tick」はイベントの tick ではない。動作はするが正しい方法であるかは判らない。


リスナー設定の役目が終わったら削除するのはあくまでも理想である。



プロパティtickに設定(Object)
loadingShape.tick=function(){
	loadingShape.rotation +=5;

};

リスナー設定
createjs.Ticker.addEventListener('tick',loadingShape.tick);
リスナー削除
createjs.Ticker.removeEventListener('tick',loadingShape.tick);

---------------------------------------------------

こちらはFunctionの書き方ちがい
var loadingShapeTick=function(){
	loadingShape.rotation +=5;

};

リスナー設定
createjs.Ticker.addEventListener('tick',loadingShapeTick);
リスナー削除
createjs.Ticker.removeEventListener('tick',loadingShapeTick);

tickリスナー一括削除


createjs.Ticker.removeAllEventListeners('tick');

インスタンスを動かす「Tickerクラス」を設定する

▲[ 目次 ]

画像読み込みの際に表示する「Loading」に付いての例です。ProgressBarも同じ要領で作れます。


回転するLoadingの例

▲[ 目次 ]

たとえばLoading、ProgressBarなどを動かす場合を想定するとわかり易い。
loadingを作りコンテナ中央に配置する。当初は「非表示」にしているが。画像のロードの際には「表示」すれば、loadingインスタンスが回転する仕組みである。tweenよりこちらの方が処理し易い。
stage.update()は、上記のTickerがあるので、ここでは記載していない。


リスナー類は使用しない場合は、「設定しない」あるいは「削除する」様に推奨されていますが。実際運用は使用者の自由です。面倒なので「削除」しない場合が多い。


● loading、progressbarに応用
1つ、作っておけば後は使い回し出来ます。これはリスナーを分離した。(リスナーを分離した方が問題が少ない)




var canvasWidth=640;
var canvasHeight=300;
var loadingShape;

//loadingコンテナを作る
loadingcontainer=new createjs.Container();
stage.addChild(loadingcontainer);
//LOADINGを作る
loadingShape=loadingIndicator3();
loadingShape.x=canvasWidth/2;
loadingShape.y=canvasHeight/2;

//loading addEventListenerを設定
createjs.Ticker.addEventListener('tick',loadingShape_tick);
//コンテナに貼り付け
loadingcontainer.addChild(loadingShape);
loadingcontainer.visible=false;//非表示

-------------------------------------------

//loadingShape-tick
function loadingShape_tick(){
	loadingShape.rotation +=5;
}

-------------------------------------------

//簡単なLOADING3
function loadingIndicator3 () {

	//graphicのスタイル
	var graphics=new createjs.Graphics();
	graphics.setStrokeStyle(2,"round");//round

	//描画データ
	var alpha_v=1;//透明度
	var alphaback;

	var cx,cy;
	var numNeedles=12;
	var innerR=15;
	var outerR=10;
	var cAngle=-Math.PI/2;
	var nAngle;

	//ライン描画
	nAngle=Math.PI*2/numNeedles;
	for (var i=0; i < numNeedles; i++){

		//回転補正
		rotateflag=cAngle -=nAngle;
		//透明度を描画毎に変更
		if (i > 0) {alpha_v -=0.05;}

		//#CCCCCC
		alphaback=createjs.Graphics.getRGB(204,204,204,alpha_v);
		cx=Math.cos(cAngle)*innerR;
		cy=Math.sin(cAngle)*innerR;
		graphics.beginStroke(alphaback).moveTo(cx,cy);
		cx=Math.cos(cAngle)*outerR;
		cy=Math.sin(cAngle)*outerR;
		graphics.lineTo(cx,cy);

	}
	//Shapeに格納
	var s=new createjs.Shape(graphics);
	return s;
}


● loadingShape.tick=function(){}形式
削除可能な書き方を探したら、このようになった。個人的に使用したもので、一般的使用例は少ない。
.tickはイベントのtickではない。予約されたプロパティ以外であれば何でも良い。



var loadingcontainer;
var loadingShape;

function init() {

	前後など略す

	//loadingコンテナを作る
	loadingcontainer=new createjs.Container();
	stage.addChild(loadingcontainer);
	//LOADINGを作る
	loadingShape=loadingIndicator();
	loadingShape.x=canvasWidth/2;
	loadingShape.y=canvasHeight/2;
	//tickを設定
	loadingShape.tick=function (){
		loadingShape.rotation +=5;
	}
	//loading Listenerを設定
	createjs.Ticker.addEventListener('tick',loadingShape.tick);

	//コンテナに貼り付け
	loadingcontainer.addChild(loadingShape);

	前後など略す

}

● loadingShapeTick=function(){}形式
削除可能な書き方を探したらこれでも可能だ。一般的な使用例は無い。

無理やり作った感じです。インスタンス.off()が機能しないので注意。



var loadingcontainer;
var loadingShape;
var loadingShapeTick;//グローバル

function init() {

	前後など略す

	//loadingコンテナを作る
	loadingcontainer=new createjs.Container();
	stage.addChild(loadingcontainer);
	//LOADINGを作る
	loadingShape=loadingIndicator();
	loadingShape.x=canvasWidth/2;
	loadingShape.y=canvasHeight/2;
	//tickを設定
	loadingShapeTick=function (){
		loadingShape.rotation +=5;
	};
	//loading Listenerを設定
	createjs.Ticker.addEventListener('tick',loadingShapeTick);

	//コンテナに貼り付け
	loadingcontainer.addChild(loadingShape);

	前後など略す

}

● リスナーの設定の書き方は色々あります
分離している書き方は「削除」し易く、分離しない書き方は「削除」し難いだけの理由です。
(削除する方法はありますが......)


重要、削除するならば、createjs.Ticker..... の形式で設定すること。



現在の書き方
createjs.Ticker.addEventListener('tick',loadingShape_tick);

on形式の書き方
createjs.Ticker.on('tick',loadingShape_tick);

分離しない書き方
loadingShape.addEventListener('tick',function(event){
	loadingShape.rotation +=5;
});
-----------------------------------

//設定はできるが削除できない
loadingShape.on('tick',function(event){
	loadingShape.rotation +=5;
});


● ローカルでのloadingの回転が悪い
画像のロードの際は大きな負荷が掛ります。ましてローカルのテスト時にはローカルサーバー、ブラウザなどが平行して処理を行うので、loadingの回転が悪い状態に陥ります。実際NET上ではサーバーは別ですから思ったより回転も良く、画像読み込みもテストより早い。


TweenとTicker

▲[ 目次 ]

CreateJSにはTween機能として、tweenjs が分離され用意されている。
Tweenを実行しても動きは「Canvasを更新」しないと反映されない。CreateJSでは stage.update() 実行をTickerに組み込む訳です。Tweenを実行中は常に stage.update() を実行する様に仕組みます。


DEMOでは、繰り返しdraw()を実行するので、その都度Ticker設定し、アニメ完了でTicker設定を削除している。tick()で行っているのは、stage.update()のみである。「Canvasを更新」update()はステージ(ここではstage)単位です。


1. 「Tween」はインスタンスなどを動かす専用係りで、Canvas更新はしない。
2. 「Ticker」のアルバイトで、Canvas更新 stage.update() をする訳だ。


Tweenとstage.update()

▲[ 目次 ]

Tweenの実行毎にstage.update()のリスナーを設定して、Tween終了後に削除する。
負荷などを考慮すれば理想ではあるが現実には、面倒で行っていない。tickイベント垂れ流し状態である。


Tweenの実行毎にstage.update()をします(例)。


記載の例

//DRAWアニメ実行
function draw() {
	前後など略す

	//画像result取得/Tween後も使用する
	mainImage=assets[image_no];

	//上画像更新画像Bitmap挿入
	topImage.image=new createjs.Bitmap(mainImage).image;

	//Tweenの実行全て終了したら、finshtweenに行く
	var tw=createjs.Tween.get(topImage)
	.to({x:0,y:0,scaleX:1,scaleY:1,rotation:0,alpha:1},speed)
	.call(finshtween);

	//Ticker設定
	createjs.Ticker.setFPS(30);
	createjs.Ticker.addEventListener('tick',tick);
}
//アニメ完了
function finshtween () {
	前後など略す

	//Ticker削除
	createjs.Ticker.removeEventListener('tick',tick);
}
//tick
function tick() {
	stage.update();
}

DEMO (easeljs-0.8用)

▲[ 目次 ]


「Tickerクラス」addEventListener を使用したスライドショウ。

このページはHTML5では有りませんので、デモページでご覧ください。「IE7.8」ではご覧いただけません。
/// 注意、ブラウザ、マシン性能により描画品質などに大きな差が有ります事了承下さい ///


demo


Chrome Opera Firefox IE9-11で動作確認済み。 Mac系統は未確認です。


「デモ」の HTML、JS、CSS は「デモ」ページに有ります。

 


 

【参照】当方の記事: CreateJS-画像をロードして表示するを考える(easeljs-0.8)

【参照】当方の記事: CreateJS easeljs-0.8のLoadQueueクラスでの画像表示の変更など

一応、完動しますが全てテストです。効率化のため、予告無くJSなど修正する場合がありますので了承下さい。

CreateJSは結構「仕様」が変わりますので特に注意が必要です。


以上です。

 


[ この記事のURL ]


 

ブログ記事一覧

年別アーカイブ一覧



[1]