POPSブログ

CreateJS 画像を分割(複数)してBitmap処理、Tweenさせる処理を考える

248

  Category:  javascript2013/09/19 pops 

画像を分割するには、Canvas処理の drawImage() を使用して画像を複数回トリミング、Bitmap化処理すれば良い事に成ります。Tweenさせるには少々の問題も出ますが意外と簡単に出来ます。他の記事でも扱っていますが今回は、簡単な「デモ」と共にまとめてみます。
easeljs-0.7 (easeljs-0.7.0)でのテストです。

 

CreateJS 画像を分割(複数)してBitmap処理、Tweenさせる処理を考える


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


前ページの「トリミング」を発展させたものですので、drawImage()の基礎的なことは、前ページの記事を参照下さい。
「画像分割」の記事は他のページにも有ります。全て繁雑ですから簡単な「デモ」と共に概要を記しますが、重複する説明もあります。


この画像分割は、toDataURL()を使用してBitmap処理していましたが、効率よい、toDataURL()を使用しない方法が判明しましたので修正しました。但し、このJSでは問題有りませんが正式なBitmap処理では有りません。


[説明図]

 

1. HTML5、Canvas処理の drawImage() を使用して分割する(複数回トリミングするのと同じ)。
2. CreateJSでTwennなどするにはdrawImage()処理後、Bitmap処理してインスタンス化する。
3. drawImage()処理は、画像が完全にロードされた状態でなければ処理出来ませんので注意下さい
4. 分割された複数の「画像要素」に「時間差」を与えてTweenさせます。
5. CreateJS バージョン 0.7.0 使用のものです。


DEMO


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


CreateJS 画像を分割してBitmap処理、Tweenさせる例 1 / その場でフエード、(createJS036.js)
画像を1枚を javascript の onload で読み込み分割しています。


CreateJS 画像を分割してBitmap処理、Tweenさせる例 2 / 簡単なランダム分割、(createJS036b.js)
画像を1枚を preloadjs の LoadQueue() で読み込み分割しています。


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


 

HTML JS CSS


使用するライブラリ

easeljs preloadjs tweenjs

配布元 : CreateJS createjs.com


ライブラリの読み込み

ダウンロードした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>

重要、バージョン違いでは動かない場合がありますので必ず合わせて下さい。
サンプルの中に、preloadjs-0.4.0.min.js が必要な場合も有ります。「デモ」createJS036b.jsでは必要です。


HTML (HTML5)


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

JS

// JSは2種類有りますので注意下さい。こちら preloadjs-0.4.0.min.js は使用しません。//

createJS036.js、JS名は任意に変更可。(onload 読み込み)、修正済み


//日本語
//createJS036.js
//easeljs-0.7デモ用

//------------------------------------------------------
//初期設定
//canvasの大きさ/全てこの値を使用
var canvasWidth=640;
var canvasHeight=300;
//テキスト表示の使用 use=true
text_use=true;//true false

var speed=1200;//拡大移動、アニメ速度
var delay_speed=200;//出現間隔、delay基準時間 100-200
//分割
var split_h=11;//標準の横方向分割数、奇数値
var split_v=5;//標準の縦方向分割数、奇数値
var split_all=split_h*split_v;

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

//ステージ
var stage;
//コンテナ
var container;
var backcontainer;

//分割大きさ位置保存容器
var chip_W=[],chip_H=[],chip_pos_X=[],chip_pos_Y=[];
//実際配置位置
var set_pos_X=[],set_pos_Y=[];
//移動配置位置
var mov_pos_X=[],mov_pos_Y=[];
//スライスObject容器
var chip=[];

//変数
var globalflag=false,backImage,mainImage,keep_mainImage,timerID=null;
var kcount=0
var viewtext;

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

//ボタン
var btncontainer;
var myhitBtn;

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

	//STAGE
	stage=new createjs.Stage('mainCanvas');
	//MouseOver設定/必要に応じ設定
	stage.enableMouseOver(20);

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

	//下画像層、空画像コンテナを作る/寸法設定なくともOK
	backcontainer=new createjs.Container();
	backImage=new createjs.Bitmap();
	backcontainer.addChild(backImage);
	stage.addChild(backcontainer);
	
	//スライス画像層、空コンテナを作る、使いまわし
	container=new createjs.Container();
	stage.addChild(container);

	//TEXT text_useが有効なら作る
	if (text_use) {

		//注意 大きさを設定しないと文字は表示しない
		viewtext=new createjs.Text("---","12px Arial","#FFFFFF");
		viewtext.x=20;
		viewtext.y=18;
		viewtext.lineWidth=canvasWidth-40;
		viewtext.lineHeight=20;
		viewtext.textBaseline="bottom";
		stage.addChild(viewtext);

		//テキスト陰影
		viewtext.shadow = new createjs.Shadow("#000000",1,1,3);

		text_set("START");
	}

	//BTNcontainer
	//Click-Buttonボタンを作る
	btncontainer=new createjs.Container();
	btncontainer.x=600;
	btncontainer.y=20;

	//ラベル文字生成
	var label="CLICK";
	//x,y,w,h,r,c,label,lc,overc,outc
	//RoundRect center補正ボタン/xyをずらした設定を送る
	//RoundRectは中心であるがテキストがづれる
	myhitBtn=createbtn_center (-30,-10,60,20,5,"#FFFFFF","CLICK","#FF0000","#48D1CC","#FFFFFF");
	myhitBtn.cursor="pointer";
	myhitBtn.x=0;
	myhitBtn.y=0;
	//クリックプロローグ
	myhitBtn.addEventListener("click",restart);
	//addChild
	btncontainer.addChild(myhitBtn);
	//非表示
	myhitBtn.visible=false;
	stage.addChild(btncontainer);

	stage.update();

	//画像ロードに進む
	//画像読み込みに失敗すれば何もしません
	image_load();

}

//image_load、画像ロード
function image_load() {

	text_set("LOADING NOW");

	var img_url="/main/images/toyota_car10.jpg";//640x300
	//imgタグを作る(またはオブジェクト)
	var img=document.createElement("img");//Chrome
	//var img=new Image();//これでも同じ/Chrome OK
	//srcにURLを入れて画像をロード
	//完全に画像をロードしてから処理
	img.onload=function(){

		text_set("LOADED");

		//画像取得
		mainImage=img;

		//時間調整
		setTimeout(function() {

			//フエードインのみ
			slice_draw();

		},2000);

	};
	img.src=img_url;

}

//DRAW、分割アニメ、フエードインのみ
function slice_draw() {

	globalflag=false;//未使用

	text_set("");

	//カウントクリア
	kcount=0;

	//スライス寸法データを得る
	slice_set(canvasWidth,canvasHeight,split_h,split_v);
	//分割合計要素数計算
	split_all=split_h*split_v;

	//画像分割貼り付け
	var srcArr=[];//URL容器
	var k=0;
	for (var i=0; i < split_h; i++) {
		for (var j=0; j < split_v; j++) {

			var sliceCanvas=document.createElement("canvas");
			//大きさ重要
			sliceCanvas.setAttribute("width",chip_W[k]);
			sliceCanvas.setAttribute("height",chip_H[k]);
			var context=sliceCanvas.getContext("2d");
			//貼り付け
			context.drawImage(mainImage,chip_pos_X[k],chip_pos_Y[k],chip_W[k],chip_H[k],0,0,chip_W[k],chip_H[k]);
			//srcArr[k]=sliceCanvas.toDataURL("image/png");
			srcArr[k]=sliceCanvas;

			k++;
		}
	}

	//アニメ条件設定など
	//配列クリア
	var delay_st=[];

	//位置確定delay計算
	var k=0;
	for (var i=0; i < split_h; i++) {
		for (var j=0; j < split_v; j++) {

			//Bitmap配列に保存
			chip[k]=new createjs.Bitmap(srcArr[k]);
			//大きさ
			chip[k].width=chip_W[k];
			chip[k].height=chip_H[k];
			//中央補正
			chip[k].regX=chip_W[k]/2;
			chip[k].regY=chip_H[k]/2;

			//保存値を中央補正の位置にする
			chip_pos_X[k] +=chip_W[k]/2;
			chip_pos_Y[k] +=chip_H[k]/2;

			//位置確定
			chip[k].x=chip_pos_X[k];
			chip[k].y=chip_pos_Y[k];
			//透明度補正 0
			chip[k].alpha=0;

			//delay計算
			delay_st[k]=(i+j)*delay_speed;

			//表示リストaddChild、stage.updateはしないこと
			//コンテナに収容
			container.addChild(chip[k]);

			k++;

		}
	}

	//TWEENの実行
	var k=0;
	for (var i=0; i < split_h; i++) {
		for (var j=0; j < split_v; j++) {

			var tw=createjs.Tween.get(chip[k])
			.wait(delay_st[k])
			.call(indexchg)
			.to({alpha:1},speed)
			.call(function () {
				//要素ごとのアニメ完了処理
				//全て完了
				if(kcount == split_all-1 ){
					finshAll();
				}
				//0からカウント加算
				kcount ++;
			});

			k++;

		}
	}

	//Firefox
	setTimeout(function() {
		//Ticker設定
		createjs.Ticker.setFPS(30);
		createjs.Ticker.addEventListener('tick',tick);
	},20);

}

//重ね順を一番上にする
function indexchg () {
	container.setChildIndex(this,split_all-1);
	//container.setChildIndex(this,0);
}

//アニメ全て完了
function finshAll () {

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

	//コンテナの中を削除
	container.removeAllChildren();

	//removeAllTweens バージョン4.2.1
	//createjs.Tween.removeAllTweens();
	//個別removeTweens
	for (var i=0; i < split_all; i++) {
		//removeTween
		createjs.Tween.removeTweens(chip[i]);
	}

	kcount=0;
	globalflag=true;

	//画像処理に時間がかかるので、少し遅延させる
	setTimeout(function() {
		//Ticker OFF
		createjs.Ticker.removeEventListener('tick',tick);

		//ボタン表示
		myhitBtn.visible=true;
		stage.update();

	},1000);

}

//再スタート
function restart () {

	//ボタン非表示
	myhitBtn.visible=false;
	//下画像クリア
	backImage.image=new createjs.Bitmap().image;
	stage.update();

	//時間調整
	setTimeout(function() {

		//分割アニメ再スタートフエードインのみ
		slice_draw();

	},2000);

}

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


//スライス要素の位置大きさ決定、保存
function slice_set(bw,bh,slh,slv) {
	//スライス
	slice_W=Math.round(bw/slh);//YOKO
	slice_H=Math.round(bh/slv);//TATE
	slice_Wb=bw-slice_W*(slh-1);
	slice_Hb=bh-slice_H*(slv-1);
	var k=0;
	for (var i=0; i < slh; i++) {
		for (var j=0; j < slv; j++) {
			//大きさ保存
			chip_W[k]=slice_W;
			if (i == slh-1) {chip_W[k]=slice_Wb;}
			chip_H[k]=slice_H;
			if (j == slv-1) {chip_H[k]=slice_Hb;}
			//位置保存中央補正前
			chip_pos_X[k]=(slice_W*i);
			chip_pos_Y[k]=(slice_H*j);
			k ++;
		}
	}
}

//TEXT表示
function text_set (t) {
	if (text_use) {
		viewtext.text=t;
		stage.update();
	}
}

//create-bottunベタ塗り/center補正
function createbtn_center (x,y,w,h,r,c,label,lc,overc,outc) {

	//BTNコンテナ
	var btn=new createjs.Container();
	var s=new createjs.Shape();
	s.graphics.s(0).beginFill(outc);
	operaRoundRect(s,x,y,w,h,r);
	btn.addChild(s);
	//myBtn shadow onMouseOverでupdate()すると濃くなる
	//テキスト以外で使用は注意
	btn.shadow=shadow;
	var tx=new createjs.Text(label,"12px Arial",lc);
	tx.maxWidth=w;
	tx.textAlign="center";
	tx.textBaseline="middle";
	tx.shadow=shadow;//テキストは濃くなら無い
	tx.name="btntext";//name挿入

	btn.addChild(tx);
	//文字の食み出し防止mask
	tx.mask=s;

	//rollover
	btn.addEventListener("rollover",function () {
		s.graphics.clear();
		s.graphics.s(0).beginFill(overc);
		operaRoundRect(s,x,y,w,h,r);
		stage.update();
	});
	//rollout
	btn.addEventListener("rollout",function () {
		s.graphics.clear();
		s.graphics.s(0).beginFill(outc);
		operaRoundRect(s,x,y,w,h,r);
		stage.update();
	});
	return btn;
}
//quadraticCurveTo、こちら使用
function operaRoundRect(s,x,y,w,h,r) {
	s.graphics.moveTo(x+r,y)
	.lineTo(x+w-r,y)
	.quadraticCurveTo(x+w,y,x+w,y+r)
	.lineTo(x+w,y+h-r)
	.quadraticCurveTo(x+w,y+h,x+w-r,y+h)
	.lineTo(x+r,y+h)
	.quadraticCurveTo(x,y+h,x,y+h-r)
	.lineTo(x,y+r)
	.quadraticCurveTo(x,y,x+r,y);
}

//START
init();

注釈文を削除すれば、幾分早くなります。
(画像使用の場合は、登録画像パスは当方の記述ですから使用の際は環境に合わせてください)


 

// JSは2種類有りますので注意下さい。こちら preloadjs-0.4.0.min.js が必要です。//

createJS036b.js、JS名は任意に変更可。(LoadQueue() 読み込み)、修正済み


//日本語
//createJS036b.js
//easeljs-0.7デモ用

//------------------------------------------------------
//初期設定
//canvasの大きさ/全てこの値を使用
var canvasWidth=640;
var canvasHeight=300;
//テキスト表示の使用 use=true
text_use=true;//true false

var speed=1200;//拡大移動、アニメ速度
var delay_speed=200;//出現間隔、delay基準時間 100-200
//分割
var split_h=11;//標準の横方向分割数、奇数値
var split_v=5;//標準の縦方向分割数、奇数値
var split_all=split_h*split_v;

//スケール方向番号データ 0-3
var scales=[0,0,0,1,1,1,2,3];
//回転データ、余り回転しない、回転は120度x回転データ
var rotates=[0,0,0,0,1,2,3];

//画像manifestリスト
var manifest=[
{src:"/main/images/toyota_car10.jpg",id:"PHOTO1"}
];

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

//ステージ
var stage;
//コンテナ
var container;
var backcontainer;
var loadingcontainer;
//ローダー
var loader;
//LoadingShape
var loadingShape;

//読み込み画像URL保存容器
var assets=[];
//分割大きさ位置保存容器
var chip_W=[],chip_H=[],chip_pos_X=[],chip_pos_Y=[];
//実際配置位置
var set_pos_X=[],set_pos_Y=[];
//移動配置位置
var mov_pos_X=[],mov_pos_Y=[];
//スライスObject容器
var chip=[];

//変数
var globalflag=false,backImage,mainImage,keep_mainImage,timerID=null;
var inType=true;
var moveType="";
var kcount=0
var once=false;
var viewtext;

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

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

//ボタン
var btncontainer;
var myhitBtn;

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

	//STAGE
	stage=new createjs.Stage('mainCanvas');
	//MouseOver設定/必要に応じ設定
	stage.enableMouseOver(20);

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

	stage.addChild(backrect);

	//下画像層、空画像コンテナを作る/寸法設定なくともOK
	backcontainer=new createjs.Container();
	backImage=new createjs.Bitmap();
	backcontainer.addChild(backImage);
	stage.addChild(backcontainer);
	
	//スライス画像層、空コンテナを作る、使いまわし
	container=new createjs.Container();
	stage.addChild(container);

	//TEXT text_useが有効なら作る
	if (text_use) {

		//注意 大きさを設定しないと文字は表示しない
		viewtext=new createjs.Text("---","12px Arial","#FFFFFF");
		viewtext.x=20;
		viewtext.y=18;
		viewtext.lineWidth=canvasWidth-40;
		viewtext.lineHeight=20;
		viewtext.textBaseline="bottom";
		stage.addChild(viewtext);

		//テキスト陰影
		viewtext.shadow = new createjs.Shadow("#000000",1,1,3);

		text_set("START");
	}

	//loadingコンテナをステージにaddChild
	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表示判定

	//BTNcontainer
	//Click-Buttonボタンを作る
	btncontainer=new createjs.Container();
	btncontainer.x=600;
	btncontainer.y=20;

	//ラベル文字生成
	var label="CLICK";
	//x,y,w,h,r,c,label,lc,overc,outc
	//RoundRect center補正ボタン/xyをずらした設定を送る
	//RoundRectは中心であるがテキストがづれる
	myhitBtn=createbtn_center (-30,-10,60,20,5,"#FFFFFF","CLICK","#FF0000","#48D1CC","#FFFFFF");
	myhitBtn.cursor="pointer";
	myhitBtn.x=0;
	myhitBtn.y=0;
	//クリックプロローグ
	myhitBtn.addEventListener("click",restart);
	//addChild
	btncontainer.addChild(myhitBtn);
	//非表示
	myhitBtn.visible=false;
	stage.addChild(btncontainer);

	stage.update();

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

}

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

	text_set("LOADING NOW");
	//Loader
	loader=new createjs.LoadQueue(false);

	//loader EventListener設定、この部分修正
	loader.addEventListener("fileload",fileload);
	loader.addEventListener("complete",complete);

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

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

	//エラー無しの画像をassets容器に保存
	assets.push(eventObject.result);

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

	//現在こちら使用
	text_set("LOADING END");

	//画像数確認、再計算
	image_max=assets.length;

	//loader Listener削除 こちら使用に修正
	loader.removeEventListener("fileload",fileload);
	loader.removeEventListener("complete",complete);

	//loading Listener削除
	createjs.Ticker.addEventListener('tick',loadingShape.tick);
	//loading container非表示
	loadingcontainer.visible=false;
	loading=false;//loading表示判定

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

		//時間調整
		setTimeout(function() {

			//少し変化あり
			slice_draw();

		},2000);

	}

}


//DRAW、分割アニメ
function slice_draw() {

	globalflag=false;//未使用

	text_set("");

	//INの場合画像result取得
	mainImage=assets[0];

	//カウントクリア
	kcount=0;

	//ランダム分割値代入
	split_h=Math.floor(Math.random()*12)+1;
	split_v=Math.floor(Math.random()*8)+1;

	//スライス寸法データを得る1
	slice_set(canvasWidth,canvasHeight,split_h,split_v);
	//分割合計要素数計算
	split_all=split_h*split_v;

	//画像分割貼り付け
	var srcArr=[];//URL容器
	var k=0;
	for (var i=0; i < split_h; i++) {
		for (var j=0; j < split_v; j++) {

			var sliceCanvas=document.createElement("canvas");
			//大きさ重要
			sliceCanvas.setAttribute("width",chip_W[k]);
			sliceCanvas.setAttribute("height",chip_H[k]);
			var context=sliceCanvas.getContext("2d");
			//貼り付け
			context.drawImage(mainImage,chip_pos_X[k],chip_pos_Y[k],chip_W[k],chip_H[k],0,0,chip_W[k],chip_H[k]);
			//srcArr[k]=sliceCanvas.toDataURL("image/png");
			srcArr[k]=sliceCanvas;
			k++;
		}
	}

	//アニメ条件設定
	//配列クリア
	var delay_st=[];
	var delay_pt=[];

	//多目的判定用
	var chgxyflag=Math.floor(Math.random()*5);
	//多目的用2
	var chgflag=Math.floor(Math.random()*3);
	//多目的判定用3 1-2の値
	var chgflag2=Math.floor(Math.random()*2)+1;
	//逆転フラグ
	var chg_v=Math.floor(Math.random()*2);
	if (chg_v < 1) {chg_v=-1;}

	//delay番号
	var delay_no=Math.floor(Math.random()*2);

	//delayed遅延させる/20%
	var delayed=Math.floor(Math.random()*5);

	//配置disposition位置番号
	var disposition_no=Math.floor(Math.random()*3);
	var disposition_X=0;
	var disposition_Y=0;

	//スケール方向番号
	var scale_no=scales[Math.floor(Math.random()*scales.length)];
	//回転データ取得
	var rotate=rotates[Math.floor(Math.random()*rotates.length)];

	//透明度
	var alpha_no=Math.floor(Math.random()*2);
	//透明度強制補正
	if (scale_no > 0) {alpha_no=0;}

	//Even算出
	var even_v=1;
	if (split_v % 2 !=0) {even_v=0;}

	flag3=1;
	var k=0;
	for (var i=0; i < split_h; i++) {
		for (var j=0; j < split_v; j++) {

			//Bitmap配列に保存
			chip[k]=new createjs.Bitmap(srcArr[k]);

			chip[k].width=chip_W[k];
			chip[k].height=chip_H[k];
			//中央補正
			chip[k].regX=chip_W[k]/2;
			chip[k].regY=chip_H[k]/2;
			//戻り位置計算
			set_pos_X[k]=chip_pos_X[k]+chip_W[k]/2;
    			set_pos_Y[k]=chip_pos_Y[k]+chip_H[k]/2;

			//その場所で
			if (disposition_no != 1) {
				disposition_X=set_pos_X[k];
				disposition_Y=set_pos_Y[k];
			}
			//YX内部ランダム位置
			if (disposition_no == 1) {
				disposition_X=Math.floor(Math.random()*canvasWidth);
				disposition_Y=Math.floor(Math.random()*canvasHeight);
			}

			//初期位置など条件の設定
			//位置確定
			chip[k].x=disposition_X;
			chip[k].y=disposition_Y;
			//スケール補正
			chip[k].scaleX=scale_no;
			chip[k].scaleY=scale_no;
			//回転補正
			chip[k].rotation=rotate*120*chg_v;
			//透明度補正
			chip[k].alpha=alpha_no;

			//表示リストaddChild、stage.updateはしないこと
			//コンテナに収容
			container.addChild(chip[k]);

			k++;
			flag3 *=-1;
		}
		if (even_v) {flag3 *=-1;}
	}

	var k=0;
	for (var i=0; i < split_h; i++) {
		for (var j=0; j < split_v; j++) {

			delay_st[k]=(i+j)*delay_speed;

			//delayed遅延
			if (delayed == 1) {
				if (flag3 < 0) {delay_st[k] +=1000;}
			}

			k ++;
			flag3 *=-1;

		}
		if (even_v) {flag3 *=-1;}
	}

	//delay反転
	if (chgxyflag > 2) {
		delay_st.reverse();
	}

	//TWEENの実行
	var k=0;
	for (var i=0; i < split_h; i++) {
		for (var j=0; j < split_v; j++) {

			var tw=createjs.Tween.get(chip[k])
			.wait(delay_st[k])
			.call(indexchg)
			.to({x:set_pos_X[k],y:set_pos_Y[k],scaleX:1,scaleY:1,rotation:0,alpha:1},speed)
			.call(function () {
				//要素ごとのアニメ完了処理
				//全て完了
				if(kcount == split_all-1 ){
					finshAll();
				}
				//0からカウント加算
				kcount ++;
			});

			k++;

		}
	}

	//Firefox
	setTimeout(function() {
		//Ticker設定
		createjs.Ticker.setFPS(30);
		createjs.Ticker.addEventListener('tick',tick);
	},20);

}

//重ね順を一番上にする
function indexchg () {
	container.setChildIndex(this,split_all-1);
	//container.setChildIndex(this,0);
}

//アニメ全て完了
function finshAll () {

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

	//コンテナの中を削除
	container.removeAllChildren();

	//removeAllTweens バージョン4.2.1
	//createjs.Tween.removeAllTweens();
	//個別removeTweens
	for (var i=0; i < split_all; i++) {
		//removeTween
		createjs.Tween.removeTweens(chip[i]);
	}

	kcount=0;
	globalflag=true;

	//画像処理に時間がかかるので、少し遅延させる
	setTimeout(function() {
		//Ticker OFF
		createjs.Ticker.removeEventListener('tick',tick);

		//ボタン表示
		myhitBtn.visible=true;
		stage.update();

	},1000);

}

//再スタート
function restart () {

	//ボタン非表示
	myhitBtn.visible=false;
	//下画像クリア
	backImage.image=new createjs.Bitmap().image;
	stage.update();

	//時間調整
	setTimeout(function() {

		//分割アニメ再スタート
		slice_draw();

	},2000);

}

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

//スライス要素の位置大きさ決定、保存
function slice_set(bw,bh,slh,slv) {
	//スライス
	slice_W=Math.round(bw/slh);//YOKO
	slice_H=Math.round(bh/slv);//TATE
	slice_Wb=bw-slice_W*(slh-1);
	slice_Hb=bh-slice_H*(slv-1);
	var k=0;
	for (var i=0; i < slh; i++) {
		for (var j=0; j < slv; j++) {
			//大きさ保存
			chip_W[k]=slice_W;
			if (i == slh-1) {chip_W[k]=slice_Wb;}
			chip_H[k]=slice_H;
			if (j == slv-1) {chip_H[k]=slice_Hb;}
			//位置保存中央補正前
			chip_pos_X[k]=(slice_W*i);
			chip_pos_Y[k]=(slice_H*j);
			k ++;
		}
	}
}


//TEXT表示
function text_set (t) {
	if (text_use) {
		viewtext.text=t;
		stage.update();
	}
}

//create-bottunベタ塗り/center補正
function createbtn_center (x,y,w,h,r,c,label,lc,overc,outc) {

	//BTNコンテナ
	var btn=new createjs.Container();
	var s=new createjs.Shape();
	s.graphics.s(0).beginFill(outc);
	operaRoundRect(s,x,y,w,h,r);
	btn.addChild(s);
	//myBtn shadow onMouseOverでupdate()すると濃くなる
	//テキスト以外で使用は注意
	btn.shadow=shadow;
	var tx=new createjs.Text(label,"12px Arial",lc);
	tx.maxWidth=w;
	tx.textAlign="center";
	tx.textBaseline="middle";
	tx.shadow=shadow;//テキストは濃くなら無い
	tx.name="btntext";//name挿入
	btn.addChild(tx);
	//文字の食み出し防止mask
	tx.mask=s;

	//rollover
	btn.addEventListener("rollover",function () {
		s.graphics.clear();
		s.graphics.s(0).beginFill(overc);
		operaRoundRect(s,x,y,w,h,r);
		stage.update();
	});
	//rollout
	btn.addEventListener("rollout",function () {
		s.graphics.clear();
		s.graphics.s(0).beginFill(outc);
		operaRoundRect(s,x,y,w,h,r);
		stage.update();
	});
	return btn;
}
//quadraticCurveTo、こちら使用
function operaRoundRect(s,x,y,w,h,r) {
	s.graphics.moveTo(x+r,y)
	.lineTo(x+w-r,y)
	.quadraticCurveTo(x+w,y,x+w,y+r)
	.lineTo(x+w,y+h-r)
	.quadraticCurveTo(x+w,y+h,x+w-r,y+h)
	.lineTo(x+r,y+h)
	.quadraticCurveTo(x,y+h,x,y+h-r)
	.lineTo(x,y+r)
	.quadraticCurveTo(x,y,x+r,y);
}

//簡単な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

createJS036.css、createJS036b.css、CSS名は任意に変更可。(共通)


/*日本語 createJS036.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:#FFFFFF;
}

#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;
}

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


簡単な説明


画像の分割

画像の分割は複数回トリミングをすることですから、ループで処理します。縦横の分割数を指定出来ます。画像は必ず整数値で分割しなければなりません。
ワタシの場合は、図の様な階層構造にして、下画像層(backcontainer)を作っているのが特徴であり、分割した要素はcontainer層の中に入れます。

[説明図]

 

画像分割のcanvas処理とBitmap化


1. トリミング画像貼り付け用の新規 canvas を複数個作り画像を流し込み、Bitmap化(インスタンス)する。
2. インスタンスは分割したため複数個有りますから、ループで処理します。
3. 出現位置順序の制御などはwait()で処理しますが、複数個の処理を行いますので少し工夫をします。
4. 分割された幅、高さの値を整数にしますので、図の様に大きさに違いが出ますが、1-2ピクセルの違いですから判りません。少数値が入りますと隙間が出ますので注意下さい。
5. AS3ではトリミングからTweenまで1つのループで処理で可能ですが、Canvasは処理が遅いのでパターン(表示順序)に微妙な影響を与えますから、作業毎にループで処理しています。
6. 最大分割数(合計)はAS3より小さくします。マシン性能に左右されますから最大100分割数(合計)位です。通常は最大50-60位で使用します。(Canvas処理はFlashPlayerと比較して3分の1位の処理速度だそうです)
7. loading表示は自由です。(デモcreateJS036.jsでは削除しています)
8. トリミングcanvas処理の詳細は同じですから、前ページの記事を参照下さい。


以下、「デモ」の createJS036.js を例に簡単に説明します。但し、簡単に「IN」のみの処理です。


● 画像分割の計算

計算の一例です(書き方は色々あると思います)。大きさ及び位置を計算して、配列容器に保存します。位置は左上を原点とした計算です。(整数化は round が、ほぼ大きさが揃いキレイになると思います)
尚、1x1分割は、分割しない「1枚画像」、2x1分割は「上下に2分割」になります。分割数は「奇数値」のほうが処理の都合でキレイになり易く、多分割の場合は正方形に近いほうがキレイです。


//スライス寸法データを得る
//slice_set(元画像の幅,元画像の高さ,横方向の分割数,縦方向の分割数)
slice_set(canvasWidth,canvasHeight,split_h,split_v);

------------------------------------------------------
//スライス要素の位置大きさ決定、保存
function slice_set(bw,bh,slh,slv) {
	//スライス
	slice_W=Math.round(bw/slh);//YOKO
	slice_H=Math.round(bh/slv);//TATE
	slice_Wb=bw-slice_W*(slh-1);
	slice_Hb=bh-slice_H*(slv-1);
	var k=0;
	for (var i=0; i < slh; i++) {
		for (var j=0; j < slv; j++) {
			//大きさ保存
			chip_W[k]=slice_W;
			if (i == slh-1) {chip_W[k]=slice_Wb;}
			chip_H[k]=slice_H;
			if (j == slv-1) {chip_H[k]=slice_Hb;}
			//位置保存中央補正前
			chip_pos_X[k]=(slice_W*i);
			chip_pos_Y[k]=(slice_H*j);
			k ++;
		}
	}
}

● 画像をdrawImage()で分割 / toDataURL()を使用しない方式

分割する位置、大きさなどを先に計算していますので、drawImage()で簡単に処理出来ます。ここでは、Bitmap()を作る際のURL情報を srcArr配列 に収容します。

この時点では、分割画像情報のみ取得しているだけで、Bitmap()化は次ぎに行います。ループが同じですから次ぎの処理と統合は可能です。


	//画像分割貼り付け
	var srcArr=[];//URL容器
	var k=0;
	for (var i=0; i < split_h; i++) {
		for (var j=0; j < split_v; j++) {

			var sliceCanvas=document.createElement("canvas");
			//大きさ重要
			sliceCanvas.setAttribute("width",chip_W[k]);
			sliceCanvas.setAttribute("height",chip_H[k]);
			var context=sliceCanvas.getContext("2d");
			//貼り付け
			context.drawImage(mainImage,chip_pos_X[k],chip_pos_Y[k],chip_W[k],chip_H[k],0,0,chip_W[k],chip_H[k]);
			//srcArr[k]=sliceCanvas.toDataURL("image/png");
			srcArr[k]=sliceCanvas;

			k++;
		}
	}

● Bitmap()に変換する

srcArr配列のURL情報を元に、分割された画像要素毎のBitmap()を作ります。addChildで、コンテナに収容しますがまだアップデートはしません。(舞台裏が見えるのでTickerは控える)
下の例では、分割された画像要素インスタンスを、regX regY で中央補正して、位置はその中央補正場所にしています。インスタンスは移動しないその場所に有りますので、透明度変化、スケール変化の選択肢しか無い。(透明度変化だけなら中央補正しなくとも良い)

ここでは、画像要素を動かしていませんので(中央補正している移動は一応無視)、画像要素を外側に移動させる場合と少々違います。色々な条件により少々違いが有りますが、これらの変化は原則使用者が設計します。

原則、中央補正をするようにしています。移動させる際に計算が少し楽になります。



Bitmapを作る書式

Bitmapインスタンス=new createjs.Bitmap("画像URL");

上の、Bitmapを作るは、下記形式でも変換可能です。/2013/10/02、追加説明
ページ最終段の「toDataURL()を使用しない方式への修正方法」説明参照のこと。


var sliceCanvas=document.createElement("canvas");がループ内にあれば
toDataURL()を使用しないで、Bitmap変換できる

Bitmapインスタンス=new createjs.Bitmap(sliceCanvas);


	var k=0;
	for (var i=0; i < split_h; i++) {
		for (var j=0; j < split_v; j++) {

			//Bitmap配列に保存
			chip[k]=new createjs.Bitmap(srcArr[k]);
			//大きさ
			chip[k].width=chip_W[k];
			chip[k].height=chip_H[k];
			//中央補正
			chip[k].regX=chip_W[k]/2;
			chip[k].regY=chip_H[k]/2;

			//保存値を中央補正の位置にする
			chip_pos_X[k] +=chip_W[k]/2;
			chip_pos_Y[k] +=chip_H[k]/2;

			//位置確定
			chip[k].x=chip_pos_X[k];
			chip[k].y=chip_pos_Y[k];

			略す、必要であれば関連の処理をする、別ループでの処理も良い

			//コンテナに収容
			container.addChild(chip[k]);

			k++;

		}
	}

● 遅延(delay)操作による表示パターン

上から、中央から、斜めになどの表示順序は「遅延」で操作出来ます。便宜的に「表示パターン」と呼ぶことにします。
遅延はjqueryではdelay()、CreateJSではwait()です。便宜的に「delay値」と言ったら、「wait値」として説明します。


delay値 = 計算式 x 設定速度
------------------------------------------------------
左上から、斜めに右下にのパターン
//delay計算
delay_st[k]=(i+j)*delay_speed;

k値の順に
delay_st[k]=k*delay_speed;

設定速度を乗じるのは値を大きくするためで「AS3」の様な小さな値はまだ無理があります。これらの計算式は使用者自身が考えます、資料などは殆んど有りません。


● 交互遅延

1つおき、つまり交互に大幅に「遅刻」させれば「市松状」に出来ます。対象とするdelay値に一定の値を加算すれば良い。色々な条件により見た目は相違有り。(createJS036b.js)


//delayed遅延させる/20%
var delayed=Math.floor(Math.random()*5);

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

//delayed遅延
if (delayed == 1) {
	if (flag3 < 0) {delay_st[k] +=1000;}
}

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

flag3は交互に1 または -1 が計算されて入る

● 遅延の反転

「遅延」は delay_st[k]配列 に収納していますので、reverse() で順序を反転できます。つまり「表示パターン」を反対にする事が可能です。但し計算式によっては反転しても同じの場合も有ります。(createJS036b.js)

reverse()はループを分離しなければ行えませんので、delay_st[k]配列の処理が終了してから行います。ここではある程度の確率で実行する様にしている。


//多目的判定用
var chgxyflag=Math.floor(Math.random()*5);

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

//delay反転
if (chgxyflag > 2) {
	delay_st.reverse();
}

● ランダムな遅延

delay_st[k]配列値にランダムな値を入れれば、ランダムな表示になります。配列をシャッフルしても良い。


● Tweenの実行

Tweenはスコブル簡単ですが、複数のインスタンスをTweenさせていますし、パターンのためwait()を与えていますので「最終的なTween完了」が判りません。
よって、グローバルな変数 kcount のカウントにより「Tween完了」を判定します。
「重ね順」の変更も行っています、その場所でのフエードの「デモ」では効果は有りませんが(重ね順を変える必要も無い)、移動、拡大などの際は「重ね順」を変えたほうが違和感が無くキレイです。

原則として、Tween以前の前処理とTweenの実行の処理はループを別にします。より時間間隔の正確な「wait()処理」をするためが理由です。


	//TWEENの実行
	var k=0;
	for (var i=0; i < split_h; i++) {
		for (var j=0; j < split_v; j++) {

			var tw=createjs.Tween.get(chip[k])
			.wait(delay_st[k])
			.call(indexchg)
			.to({alpha:1},speed)
			.call(function () {
				//要素ごとのアニメ完了処理
				//全て完了
				if(kcount == split_all-1 ){
					finshAll();
				}
				//0からカウント加算
				kcount ++;
			});

			k++;

		}
	}
---------------------------------------------------------

call(indexchg)は重ね順を変更します

//重ね順を一番上にする
function indexchg () {
	container.setChildIndex(this,split_all-1);
	//container.setChildIndex(this,0);
}

● INとOUTの考え方

画像の分割などの移動には、「IN」「OUT」の考え方があります、外側から移動集結するのは「IN」、外側に分散移動を「OUT」と考えてTweenさせます。他に便宜上の分類を行います。

1.「IN」外側から移動集結、フエードイン、拡大。
2.「OUT」外側に分散移動、フエードアウト、縮小。

複数の画像を順次表示する場合は、画像層コンテナ2層(上画像層、下画像層)使って画像を切り替えます。
但し、Firefoxで問題が発生します。Tween直前下画像層に画像を入れた場合(OUT処理)に一瞬キャンバスの1番上に表示して、その後、指定の階層に収まります(キャンバス処理が遅いのか?、原因不明)。一瞬でも見えては困りますので、次ぎの様にTicker設定を僅か遅延して解決しています。(20-30ミリ秒)


Ticker設定を一瞬遅らせる

//Firefox
setTimeout(function() {
	//Ticker設定
	createjs.Ticker.setFPS(30);
	createjs.Ticker.addEventListener('tick',tick);
},20);

● Tween終了後の処理

この例は、フエードインですから分類では「IN」に成ります。繰り返しの処理をしない場合は何もせずとも結構ですが、原則次ぎの処理を行います。

1.「IN」、下画像層に分割しない画像を入れて、分割画像インスタンスを削除します。
2.「OUT」、Tween事前に下画像層には新しい画像を入れておき、分割画像インスタンスを古い画像にしてTween後、上にある分割画像インスタンスを削除します。
3. Tweenの削除などは自由です。

Tween終了後に直ぐに Ticker を削除すると最後のインスタンスが未処理で終了する場合がありますので、少し時間が経過してから Ticker を削除しています。


//アニメ全て完了
function finshAll () {

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

	略す

	//画像処理に時間がかかるので、少し遅延させる
	setTimeout(function() {
		//Ticker OFF
		createjs.Ticker.removeEventListener('tick',tick);

		//ボタン表示
		myhitBtn.visible=true;
		stage.update();

	},1000);

}

● 複数画像の読み込み処理

複数画像の読み込み処理の場合はローダー、LoadQueue() で読み込み分割した方が便利です。drawImage()処理を行う際は「result値」を取得して使用下さい。(createJS036b.js は、画像manifestリストを設定していますが画像は1枚のみ登録で使用しています)


//各画像読み込み完了
function fileload (eventObject) {
	//エラー無しの画像をassets容器に保存
	assets.push(eventObject.result);
}

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

//貼り付け
context.drawImage(result値,chip_pos_X[k],chip_pos_Y[k],chip_W[k],chip_H[k],0,0,chip_W[k],chip_H[k]);

● その外の注意点など

単に、toDataURL()を使用しないでBitmap処理が偶然出来ただけで、正式なBitmap処理では有りませんので、何らかの加工を行った場合に問題がでる場合があります。

「デモ」での処理自体は、以上の様ですからスコブル簡単ですが、Flashplayerと違い、ブラウザ毎に振る舞いなど違う事が有りますので、その確認などが面倒になります。
分割数、拡大、透明度、回転、ひねり、移動位置、など変化させますと色々な違うエフェクト(感じ)になります。これらは自由ですが大変な作業になりますので、効率的な手法を考案する事が肝要です。(ウソではない、オモイッキリ悩み苦しむ面倒で時間浪費の特権付きだ!)
その上、問題が発生した場合は、現在、資料などは有りませんので自己解決する他に方法は有りません。時間の経過と共に情報は増えてくるとは思います。またCreateJSの「仕様」もクルクル変わっていますので、バージョン違いに注意下さい


● easeljs-0.7への変更

easeljs-0.7への変更してもJSはそのまま正常に作動しますが、
1. ボタンロールオーバーを mouseover mouseout、から rollover rollout、に変更しました。
2. ボタン「クリックアクション」は、EVENT処理をしていませんのでそのままです。


● 階層用コンテナに収容する訳
階層用コンテナつまりレーヤーの代替として利用の場合が多いが、個人的に多用しています。強制するツモリは有りませんのでこれは自由です。


[怪奇! Bitmap食み出し事件の捜査図、再放送]

1. 階層構造(大まかな重ね順)を常に一定にしておける。
2. コンテナに収容のインスタンスなどの削除が簡単になる。
3. デモの様にCSSで角丸処理した場合に、ステージ角丸部分で、中のBitmap画像の「角が食み出す」事があるが、コンテナに収容すると「何故か食み出さないでCSSが有効」と成る。何故なのだ?
4. 階層用コンテナ毎に移動したり出来るので、ブロック毎の管理が楽だ。(但し、階層が深くなり少し重くなる欠点あり)


● jQueryでの画像分割との比較

HTMLでの画像分割も出来ますし、jQueryでのアニメーションも可能ですから同様のものを制作出来ます。現時点で比較してみますと、

1. 簡単に回転出来るのが便利。
2. 透明度を与えた場合、比較的軽い。
3. 重ね順の変更が楽だ。HTMLでは「IE」が不正確のため重ね順の変更はしていない。
4. インスタンスの中心を自由に出来る。
5. マスク処理が簡単で有り。陰影処理も問題が少ない。

以上の利点など有りますが、テキスト周りが貧弱ですから旨く使い分けることが重要かと思います。(または旨く組み合わせる)


toDataURL()を使用しない方式への修正方法

このページ掲載のJSは修正済みです。


画像をdrawImage()で分割している部分です、2箇所書き換えます。
var sliceCanvas=document.....は必ず移動下さい。

修正前


	//画像分割貼り付け
	var srcArr=[];//URL容器
	var sliceCanvas=document.createElement("canvas");
	var k=0;
	for (var i=0; i < split_h; i++) {
		for (var j=0; j < split_v; j++) {

			//大きさ重要
			sliceCanvas.setAttribute("width",chip_W[k]);
			sliceCanvas.setAttribute("height",chip_H[k]);
			var context=sliceCanvas.getContext("2d");
			//貼り付け
			context.drawImage(mainImage,chip_pos_X[k],chip_pos_Y[k],chip_W[k],chip_H[k],0,0,chip_W[k],chip_H[k]);
			srcArr[k]=sliceCanvas.toDataURL("image/png");

			k++;
		}
	}

修正後


	//画像分割貼り付け
	var srcArr=[];//URL容器
	var k=0;
	for (var i=0; i < split_h; i++) {
		for (var j=0; j < split_v; j++) {

			var sliceCanvas=document.createElement("canvas");
			//大きさ重要
			sliceCanvas.setAttribute("width",chip_W[k]);
			sliceCanvas.setAttribute("height",chip_H[k]);
			var context=sliceCanvas.getContext("2d");
			//貼り付け
			context.drawImage(mainImage,chip_pos_X[k],chip_pos_Y[k],chip_W[k],chip_H[k],0,0,chip_W[k],chip_H[k]);
			srcArr[k]=sliceCanvas;

			k++;
		}
	}

以上の修正です。画像分割は、ほぼ同じ形態で処理していますので他のJSも修正可能です。


使用画像

画像などは原則、使用者が目的に応じ用意します。640x300


複数画像を読み込み、分割して表示する色々な例

色々な、画像分割、画像分割アニメに関しては、当方の下記記事を参照下さい。多少複雑になりますが、、


画像分割アニメーション、toDataURL()を使用しない方式 (easeljs-0.7用)です。

【参照】当方の記事: CreateJS 画像分割アニメーション、一括画像読み込み、toDataURL()を使用しない方式 (easeljs-0.7用)


その外の、画像分割アニメーション、toDataURL()を使用しない方式に修正可能です。

【参照】当方の記事: CreateJS-Canvas画像分割アニメ、一括画像読み込み単純階層化、タイマー形式

【参照】当方の記事: CreateJS-Canvas画像分割アニメーションのテスト、タイマー形式




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


皆さん「画像分割」などしなければ良かったと「つくづく」反省するでショウ。以上です。

 


[ この記事のURL ]


 

ブログ記事一覧

年別アーカイブ一覧



[1]