POPSブログ

CreateJS 画像クロスフェード、一括画像読み込み、タイマー形式

210

  Category:  javascript2013/04/06 pops 

CreateJSを利用して、HTML5のCanvasで画像をクロスフェードさせます。別段特徴のあるものでは有りませんが、階層ごとにコンテナに収容したりして標準化しています。Loading ProgressBarを付けてみました。
エフェクトは単純な「クロスフェード」のみですがスライド形式などに変更可能な構造です。

 

CreateJS 画像クロスフェードのテスト


2013/09/25/EaselJSなどバージョンUPされました(easeljs-0.7)。動作など確認してeaseljs-0.7用に更新しています。(2013/10/11)


基本的には、前回の構造の踏襲ですが色々とテストして簡単な効率よい方法を探っています。当方では画像を使用することが多いのでソレに適したものでこれから色々と利用して見たいと思います。コンテナが多い分長くは成りますが、


DEMO


 

画像クロスフェード、一括画像読み込み、タイマー形式 (createJS007.js)

このページはHTML5では有りませんので、デモページでご覧ください。「IE7.8」ではご覧いただけません。


Chrome Firefox Safari(Win) IE9、で動作確認済み。 (Safari(Mac)、IE10は未確認です)


HTML JS CSS


ライブラリの読み込み

ダウンロードしたJSを使用する場合。記述は一例です。(バージョン 0.7.0 使用)


<script type="text/javascript" src="js/easeljs-0.7.0.min.js"></script>
<script type="text/javascript" src="js/preloadjs-0.4.0.min.js"></script>
<script type="text/javascript" src="js/tweenjs-0.5.0.min.js"></script>

重要、バージョン違いでは動かない場合が有りますので必ず合わせて下さい。


HTML (HTML5)


<div id="demo-wrap">
	<div id="image-box" class="radius">
		<canvas id="mainCanvas" width="640" height="300"></canvas>
	</div>
</div>

DIV #demo-wrap は外側ラップ要素ですが必ずしも必要ではない。「デモ」では中の要素 #image-box を中央に配置するために使用している。


JS

createJS007.js、JS名は任意に変更可


//日本語
//createJS007.js
//crossfade
//easeljs-0.7用

//------------------------------------------------------
//初期設定

var speed=1200;//アニメ速度
//canvasの大きさ/全てこの値を使用
var canvasWidth=640;
var canvasHeight=300;
//タイマーの使用、useであること
var timer_use="use";
//タイマー値 5000-10000
var time=8000;

//画像manifestリスト/idは利用していない
var manifest=[
{src:"/main/images/toyota_car10.jpg",id:"PHOTO1"},
{src:"/main/images/toyota_car11.jpg",id:"PHOTO2"},
{src:"/main/images/toyota_car12.jpg",id:"PHOTO3"},
{src:"/main/images/toyota_car13.jpg",id:"PHOTO4"},
{src:"/main/images/toyota_car15.jpg",id:"PHOTO5"},
{src:"/main/images/toyota_car16.jpg",id:"PHOTO6"}
];

//最初の画像0のこと
var image_no=0;
//画像数
var image_max;

//------------------------------------------------------

//ステージ
var stage;
//コンテナ
var container;
var backcontainer;
var loadingcontainer;
var progresscontainer;
//welcome画像
var welcomeImage;
//画像result
var mainImage;
//下画像
var backImage;
//上画像
var topImage;
//Loading
var loadingShape;
var progressbar;
//TEXT
var viewtext;

//読み込み画像URL保存容器
var assets=[];

//変数
var globalflag=false,timerID=null;
//loading変数
var loading=false;
//ProgressBar変数
var bar_v=0;

//shadowフィルター
var shadow=new createjs.Shadow("#000000",0,0,4);

//ステージ周りセット
function init() {

	//STAGE
	stage=new createjs.Stage('mainCanvas');

	//バックRect/最下位色背景層、無くとも良い
	var backrect=new createjs.Shape();
	backrect.graphics.beginFill("#000000").drawRect(0,0,canvasWidth,canvasHeight);
	stage.addChild(backrect);

	//welcome画像層画像表示
	welcomeImage=new createjs.Bitmap('/main/images/welcome_black.png');
	stage.addChild(welcomeImage);
	//welcome画像を先に表示
	stage.update();

	//下画像層、空画像コンテナを作る/寸法設定なくともOK
	backcontainer=new createjs.Container();
	backImage=new createjs.Bitmap();
	backcontainer.addChild(backImage);
	stage.addChild(backcontainer);
	
	//上画像層、空コンテナを作る
	container=new createjs.Container();
	topImage=new createjs.Bitmap();
	container.addChild(topImage);
	stage.addChild(container);

	//loadingコンテナを作る
	loadingcontainer=new createjs.Container();
	stage.addChild(loadingcontainer);
	//LOADINGを作る
	loadingShape=loadingIndicator();
	loadingShape.x=canvasWidth/2;
	loadingShape.y=canvasHeight/2;
	//tickを設定
	loadingShape.tick=function (){
		if(loading) {
			loadingShape.rotation +=5;
			stage.update();
		}
	}
	//loading addEventListenerを設定
	createjs.Ticker.addEventListener('tick',loadingShape.tick);
	//コンテナに貼り付け
	loadingcontainer.addChild(loadingShape);
	loading=true;//loading表示判定

	//ProgressBar/canvasWidthの幅で描画
	progresscontainer=new createjs.Container();
	progresscontainer.x=0;
	progresscontainer.y=20;
	progressbar=new createjs.Shape();
	progressbar.graphics.s(0).beginFill("#888888").drawRect(0,0,canvasWidth,4);
	//bar_v判定tickを設定
	progressbar.tick=function (){
		if(bar_v > 0) {
			progressbar.graphics.s(0).beginFill("#C00000").drawRect(0,0,canvasWidth*bar_v,4);
			stage.update();
		}
	}
	//Ticker.addEventListener設定
	createjs.Ticker.addEventListener('tick',progressbar.tick);
	//addChild
	progresscontainer.addChild(progressbar);
	stage.addChild(progresscontainer);

	//簡易TEXT
	viewtext=new createjs.Text("Loading Now!","12px Arial","#FFFFFF");
	viewtext.x=20;
	viewtext.y=15;
	viewtext.maxWidth=canvasWidth-40;
	viewtext.lineHeight=20;
	viewtext.textBaseline="bottom";
	viewtext.shadow=shadow;//SHADOW処理
	stage.addChild(viewtext);

	stage.update();

	//画像ロードに進む
	bulkload();

}

//progressBar
function progress(event) {

	//loadedのみ効く
	bar_v=event.loaded;
}

//bulk-load、画像一括ロード
function bulkload() {

	//Loaderを作る
	var loader=new createjs.LoadQueue(false);

	//全体、progressがあれば先に設定
	loader.addEventListener("progress",progress);

	//loader EventListener設定
	loader.addEventListener("fileload",fileload);
	loader.addEventListener("complete",complete);

	//Manifestを使用、manifest読み込み開始
	loader.loadManifest(manifest);

}
//各画像読み込み完了
function fileload (event) {

	var type=event.item.type;
	//画像のみ選別
	if (createjs.LoadQueue.IMAGE == type) {
		//エラー無しの画像をassets容器に保存
		assets.push(event.result);
	}

}
//全ての画像読み込み完了
function complete (event) {

	//画像数確認、再計算
	image_max=assets.length;
	//簡易TEXT
	viewtext.text="Loading End!";

	//loader Listener削除
	event.target.removeEventListener("fileload",fileload);
	event.target.removeEventListener("complete",complete);

	//loading EventListener削除
	createjs.Ticker.removeEventListener('tick',loadingShape.tick);
	//非表示でも良い
	loadingcontainer.visible=false;
	loading=false;//loading表示判定

	stage.update();

	//画像があれば、最初の画像表示
	if (image_max) {

		//早すぎるので調整
		setTimeout(function() {

			//遅延progressbar最後の前にcompleteが反応する
			event.target.removeEventListener("progress",progress);
			//progressTicker削除
			createjs.Ticker.removeEventListener('tick',progressbar.tick);
			//progress非表示
			progresscontainer.visible=false;
			//簡易TEXTクリア非表示
			viewtext.text="";
			viewtext.visible=false;

			//画像表示に進む
			draw();

		},1000);//500-1000
	}

}

//DRAW、アニメ
function draw() {

	globalflag=false;

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

	//上画像更新、透明度0
	var newimage=new createjs.Bitmap(mainImage);
	topImage.alpha=0;
	topImage.image=newimage.image;

	//TWEENの実行
	var tw=createjs.Tween.get(topImage)
	.to({alpha:1},speed)
	.call(finshtween);

	//Ticker設定
	createjs.Ticker.setFPS(60);
	createjs.Ticker.addEventListener('tick',tick);

}

//フェードアニメ完了
function finshtween () {

	//Tween全てが完了してから下画像表示
	backImage.image=new createjs.Bitmap(mainImage).image;

	//上画像に空Bitmap挿入
	var newimage=new createjs.Bitmap();
	topImage.image=newimage.image;
	stage.update();

	//アニメ作業中である、現在は未使用
	globalflag=true;

	//welcome表示中なら削除、遅延して削除している
	if(welcomeImage.visible) {
		stage.removeChild(welcomeImage);
	}

	//画像処理に時間がかかるので、少し遅延させる、あったほうが良い
	setTimeout(function() {
		//Ticker削除
		createjs.Ticker.removeEventListener('tick',tick);
		//タイマー次ぎ開く
		if (timer_use == 'use') {
			set_timer();
		}
	},500);

}

//tick
function tick() {
	stage.update();
}

//次ぎの開く要素を計算
function next_set() {

	//次ぎの番号
	image_no +=1;
	if (image_no > (image_max-1)) {image_no=0;}
	draw();

}

//タイマー
function set_timer() {

	//タイマー再セット
	if (timer_use == 'use') {

		//一旦切ってからセット
		clearTimeout(timerID);
		timerID=setTimeout(next_set,time);
	}

}

//簡単なLOADING
function loadingIndicator(){

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

	//描画データ
	var cx,cy,
	numNeedles=12,
	innerR=10,
	outerR=5,
	cAngle= -Math.PI/2,
	nAngle;

	//ライン描画
	nAngle=Math.PI*2/numNeedles;
	for (var i=0; i < numNeedles; i++){
		cAngle +=nAngle;
		cx=Math.cos(cAngle)*innerR;
		cy=Math.sin(cAngle)*innerR;
		graphics.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
}

//START
init();

当方のサンプルの例です。背景画像使用の場合は用意ください。


CSS

createJS007.css、CSS名は任意に変更可


/*日本語createJS007.css*/

#demo-wrap {
text-align:center;
}

#image-box {
position:relative;
top:0;left:0;
width:640px;
height:300px;
margin:0 auto;
padding:0;
box-shadow:0 0 10px #000;
-moz-box-shadow:0 0 10px #000;
-webkit-box-shadow:0 0 10px #000;
-o-box-shadow:0 0 10px #000;
-ms-box-shadow:0 0 10px #000;
background-color:#000000;
}

#image-box #mainCanvas {
border-radius:10px;
}
canvas {
border-style:none;
background-color:transparent;
}

.radius {
border-radius:10px;
-moz-border-radius:10px;
-webkit-border-radius:10px;
-o-box-border-radius:10px;
-ms-border-radius:10px;
}

当方のサンプルの例です。


簡単な説明


簡単な説明など


使用する事は可能ですが、あくまでもテストですので個人の判断で使用ください。


基本的に7階層構成にしました。本当に必要なのは、「下画像層」「上画像層」です。その外は無くとも良いが一応作っておけば再利用できる。クロスフェードだけなら「下画像層」に画像をaddChildしてフェード終了後にremoveChildする方法もあるが、一応色々なエフェクトなどに応用できる構造とした。


1. 最下位色背景層(Back背景着色用)。他の用途にも利用可能
2. 補助画像層(welcome画像)有っても無くとも良い画像層です。他の用途にも利用可能
3. 下画像層(上画像のフェード終了で画像を切り替える)。
4. 上画像層(フェードなどのアニメ処理用)。
5. ローデング層(回転ローデング収容)。選択可
6. ProgressBar層(簡単なProgressBar収容)。選択可
7. 簡易テキスト層(簡単なテキスト表示用、shadowを付けた方が読み易い)。他の用途にも利用可能


クロスフェード

クロスフェードのため画像層が2つ必要である、上の画像の透明度を 0 から 1 にしているに過ぎない。
画像層が2つあるから色々なエフェクトに利用できる構造である。下の処理をタイマーで繰り返している。


1. 新画像を上の画像Bitmapに挿入してフエード。
2. フエード完了後、下の画像Bitmapに同じ画像を挿入。
(フエードなどの作業を行わない時は常に、下の画像Bitmapを表示している)
3. 上の画像Bitmapをクリア。




	//上画像更新、透明度0
	var newimage=new createjs.Bitmap(mainImage);
	topImage.alpha=0;
	topImage.image=newimage.image;

	//TWEENの実行
	var tw=createjs.Tween.get(topImage)
	.to({alpha:1},speed)
	.call(finshtween);


フェードアニメ完了での上画像のクリア

クロスフェードが終了したら上画像は用が無いのでクリアする。例えば、
※ 空の Bitmap を挿入する。
※ 非表示にする。
※ 欄外に移動する。
※ removeChild する。
などの方法があろうと思うが、ここでは空のBitmapを挿入する処理を行う。


//フェードアニメ完了
function finshtween () {

	途中略

	空のBitmap()を挿入してクリアする

	var newimage=new createjs.Bitmap();
	topImage.image=newimage.image;
	stage.update();

	途中略

}

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

	次ぎの方法でも問題は起きないようだ

	topImage.image=null;
	stage.update();

色々な方法があるようだが、nullするのは全てに通じるかは不明である。一応エラーがないから良いのだろうの判断だ。


ProgressBarの処理

ProgressBarのテストのためですのでLoadingと重複しています。ProgressBarの描画はTickerの反応でgraphicsを塗り替えていますが、イベントの発生タイミングの関係も有りますが画像Load終了処理(complete)が速く、最後のProgressBarの描画のために遅延Timerを入れて調整しました。
(setTimeoutが無いと最後までProgressBarを描画しないうちに、complete処理が終了して画像表示に行く。他にも方法はあると思うが、単なるProgressBar見栄えのためのsetTimeout処理です)


function complete (event) {

	途中略

	if (image_max) {

		//早すぎるので調整
		setTimeout(function() {

			progress、progressbar関連の削除処理


			//画像表示に進む
			draw();

		},1000);//500-1000
	}
}

progress、progressbarの無い場合はsetTimeout処理は不要です。しいて言えば if (image_max) の判定も削除できる。厳密にしているだけ。


fileloadでの画像選定処理

配列assetsにpushで読み込まれた画像のみ処理、前にtype判定を加えた。


//各画像読み込み完了
function fileload (event) {

	var type=event.item.type;
	//画像のみ選別
	if (createjs.LoadQueue.IMAGE == type) {
		//エラー無しの画像をassets容器に保存
		assets.push(event.result);
	}

}

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

簡略すればこれだけでもOK、result は重要

function fileload (event) {
	assets.push(event.result);
}

ローデングtickで変数での判定処理

ローデングなどのtickでは、動作させる時の判定がキーポイントみたいだ。loadingShape.visible などの判定も使用できるが、旨く変数を利用したほうが早い。
createJSの処理を通さない分速くなる理屈だ、tickは1秒間の処理回数が多いからこのような配慮が要るのだろう。またAS3拠り処理が遅いことも理由かな。


予め変数loadingの役割を決めておき、判定する
loading=trueはloadingの使用中を意味するので

loadingShape.tick=function (){
	if(loading) {
		loadingShape.rotation +=5;
		stage.update();
	}
}

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

これでも判定できるが、上のほうが早い
if(loadingShape.visible) {
	//
}

アニメ(Fade)部分を変えれば、色々利用できる1つのテンプレートになる構造である。


一応、完動しますが全てテストです。効率化のため、予告無くJSなど修正する場合がありますので了承下さい。
また、CreateJSの「仕様」もクルクル変わっていますので、バージョン違い等に充分注意下さい


以上です。

 


[ この記事のURL ]


 

ブログ記事一覧



[1]