POPSブログ

CreateJS アコーディオン、大型画像HOVER(rollover)形式

297

  Category:  javascript2014/05/20 pops 

簡単な画像を使用した ホリゾンタル アコーディオン です。CreateJSでは MouseHover などの処理に少々クセがありますので、その辺をクリアできれば jQuery AS3 のアコーディオンと原理は同じですから製作は簡単です。
easeljs-0.7.1 でのテストです。

 

CreateJS アコーディオン、大型画像HOVER(rollover)形式 テスト

簡単な画像を使用したアコーディオンですが、一応リンクを組めば指定ページにジャンプできますので、アコーディオンMENUと言う所でしょうか。画像エフェクトなどの多様性はありますが「htmlコンテンツ」の表示には不向きです。

あくまでも、画像専用のアコーディオンとなります。


 

DEMO


CreateJS アコーディオン大型画像HOVER形式のデモ、(createJS081.js)

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



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


 

HTML JS CSS


使用するライブラリ

easeljs preloadjs tweenjs

配布元 : CreateJS createjs.com


ライブラリの読み込み

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


<script type="text/javascript" src="js/easeljs-0.7.1.min.js"></script>
<script type="text/javascript" src="js/preloadjs-0.4.1.min.js"></script>
<script type="text/javascript" src="js/tweenjs-0.5.1.min.js"></script>

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


HTML (HTML5)



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

JS

createJS081.js、JS名は任意に変更可。注意、easeljs-0.7.1用です。


//日本語
//createJS081.js
//アコーディオン

//------------------------------------------------------
//canvasの大きさ
var canvasWidth=800;
var canvasHeight=300;

//アコーディオン画像の大きさ
var accordionWidth=640;
var accordionHeight=300;

//初期指定OPEN番号を有効にする
var selectUes=false;//true
//初期指定OPEN番号 0-
var select_no=0;
//TWEEN速度 200-800
var speed=500;
//リンクを有効にする
var linkUse=false;//false true

//TEXT
var text_use=true;//true false

//画像manifestリスト
var manifest=[
{src:"/main/images/flight01.jpg",id:"PHOTO1"},
{src:"/main/images/flight02.jpg",id:"PHOTO2"},
{src:"/main/images/flight03.jpg",id:"PHOTO3"},
{src:"/main/images/flight04.jpg",id:"PHOTO4"},
{src:"/main/images/flight05.jpg",id:"PHOTO5"},
{src:"/main/images/flight06.jpg",id:"PHOTO6"}
]

//案内文、リンクデータは画像数にあわせて編集
//案内文タイトルなど
var info_text=["Blog","Index","Service","Links","Download","Map"];
//リンクデータ、URLなど
var link_url=["blog.html","index.html","service.html","links.html","download.html","map.html"];

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

//ステージ
var stage;
//コンテナ
var accordioncontainer;
var loadingcontainer;
var progresscontainer;
var textcontainer;

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

//ローダー変数
var loader;
//LoadingShape
var loadingShape;

//loading変数
var loading=false;
//ProgressBar
var progressbar;
var progtext;
var bar_v=0;

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

//Accordion変数
myAccordion=[];
//標準X位置保存
accordionStPointX=[];
accordionOpenPointX=[];
accordionClosePointX=[];

//陰影
var shadow=new createjs.Shadow("#000000",0,0,4);

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

//ステージ周りセット
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);

	//accordion画像層
	accordioncontainer=new createjs.Container();
	stage.addChild(accordioncontainer);

	//loading3コンテナをステージにaddChild
	loadingcontainer=new createjs.Container();
	stage.addChild(loadingcontainer);
	//ShapeのLOADINGを作る
	loadingShape=loadingIndicator3();
	loadingShape.x=canvasWidth/2;
	loadingShape.y=canvasHeight/2;
	//tickを設定
	loadingShape.tick=function (){
		loadingShape.rotation +=5;

	}
	//loading addEventListenerを設定
	createjs.Ticker.addEventListener('tick',loadingShape.tick);
	//コンテナに貼り付け
	loadingcontainer.addChild(loadingShape);
	loading=true;//loading表示判定未使用

	//ProgressBar
	progresscontainer=new createjs.Container();
	progressbar=new createjs.Shape();
	progtext=new createjs.Text("0","12px Arial","#FFFFFF");
	progtext.x=0;
	progtext.y=15;
	progtext.maxWidth=80;
	progtext.textAlign="center";
	progtext.shadow=shadow;//shadow
	//alpha
	progressbar.alpha=0.5;

	//bar_v判定tickを設定 butt round/Stroke
	//90度是正-Math.PI/2
	progressbar.tick=function (){
		if(bar_v > 0) {
			progressbar.graphics.clear();
			progressbar.graphics.setStrokeStyle(8,"butt").beginStroke("#FF69B4");
			progressbar.graphics.arc(0,0,40,-Math.PI/2,Math.PI*2*bar_v-Math.PI/2);
			progtext.text=Math.floor(bar_v*100);
		}
	}
	//Ticker.Listener設定
	createjs.Ticker.addEventListener('tick',progressbar.tick);
	//addChild
	progresscontainer.x=canvasWidth/2;
	progresscontainer.y=canvasHeight/2;
	progresscontainer.addChild(progressbar,progtext);
	stage.addChild(progresscontainer);

	textcontainer=new createjs.Container();
	//注意 大きさを設定しないと文字は表示しない
	viewtext=new createjs.Text("---","12px Arial","#FFFFFF");
	viewtext.x=20;
	viewtext.y=18;
	viewtext.lineWidth=canvasWidth-40;
	viewtext.lineHeight=20;
	viewtext.textBaseline="bottom";
	textcontainer.addChild(viewtext);
	stage.addChild(textcontainer);
	//テキスト陰影
	viewtext.shadow=shadow;
	text_set("LOADING NOW");

	//Main-Ticker設定
	createjs.Ticker.setFPS(30);
	//createjs.Ticker.timingMode=createjs.Ticker.RAF;
	createjs.Ticker.addEventListener('tick',tick);

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

}

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

	//Loader
	loader=new createjs.LoadQueue(false);
	//全体、progressがあれば先に設定
	loader.addEventListener("progress",progress);

	//loader EventListener設定、この部分修正
	loader.addEventListener("fileload",fileload);
	loader.addEventListener("complete",complete);
	//必要ならエラーListenerを書く

	//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表示判定

	//画像があれば
	if (image_max) {

		setTimeout(function() {

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

			//現在こちら使用
			text_set("");
			//Mainに行く
			main();

		},2000);
	}

}

//progressBar
function progress(event) {

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

//MAIN
function main() {

	text_set("Accordion");

	//アコーディオン配置間隔
	var move_w=Math.floor(canvasWidth/image_max);//ST
	var move_w2=Math.floor((canvasWidth-accordionWidth)/(image_max-1));//OPEN
	var move_w3=Math.floor((canvasWidth-accordionWidth)/(image_max-1));//CLOSE

	for (var i=0; i < image_max; i++) {

		//初期間隔決定保存
		accordionStPointX[i]=move_w*i;
		//OPEN CLOSE位置
		accordionOpenPointX[i]=move_w2*i;
		accordionClosePointX[i]=move_w3*(i-1)+accordionWidth;
		if(i == 0) {accordionClosePointX[i]=0;}
	}

	//アコーディオンHoverMenu clickタイプ
	for (var i=0; i < image_max; i++) {

		//番号受け渡し
		var no=i;

		var img=assets[no];

		//アコーディオン要素
		myAccordion[i]=createAccordion(img,accordionWidth,accordionHeight,no);
		//初期間隔
		myAccordion[i].x=accordionStPointX[i];
		//判別用のproperty:idを書き込む、未使用
		myAccordion[i].id=i;

		//リンク有効なら
		if(linkUse) {
			//pointer
			myAccordion[i].cursor="pointer";
			//クリックアクション
			myAccordion[i].on("click",handleclick,null,false,i);
		}

		//addChild
		accordioncontainer.addChild(myAccordion[i]);

	}

	//select番号補正
	if(select_no > image_max-1) {select_no=0;}

	//初期指定OPEN番号
	if(selectUes) {
		accordion_open(select_no);
	}

	//stage-rollout/stage-u-out初期指定OPEN番号
	stage.addEventListener("rollout",function (e) {
		if(selectUes) {
			//accordion_open(select_no);
		}
	});

}

//アコーディオン要素作成
function createAccordion(img,w,h,no) {

	//ラップコンテナ
	ac=new createjs.Container();
	//画像
	back=new createjs.Bitmap(img);
	ac.addChild(back);

	//active判定用
	var no=no;

	//ラップコンテナrollover
	ac.addEventListener("rollover",function (e) {
		//
		accordion_open(no);
	});
	//ラップコンテナrollout
	ac.addEventListener("rollout",function (e) {
		//
		accordion_close(no);
	});
	return ac;
}

//Click
function handleclick (event,no) {

	var hit_no=no;

	text_set(" No."+hit_no);

	//リンク有効ならば処理
	if(linkUse) {

		//登録リンクデータ
		var url="/main/html/" + link_url[hit_no];

		//例ウィンドウに出力
		location.href=url;
	}

}

//OPEN、removeAllTweensで対応
function accordion_open(no){

	//案内文の表示
	//text_set("Accordion-No: "+(no+1));
	text_set(info_text[no]);

	//removeAllTweens
	createjs.Tween.removeAllTweens();

	for (var i=0; i < image_max; i++) {
		var tw=createjs.Tween.get(myAccordion[i]);

		if(no >= i) {tw.to({x:accordionOpenPointX[i]},speed);}
		if(no < i) {tw.to({x:accordionClosePointX[i]},speed);}
	}

}
//CLOSE
function accordion_close(no){

	text_set("");

	//removeAllTweens
	createjs.Tween.removeAllTweens();

	//標準に戻す
	for (var i=0; i < image_max; i++) {
		//myAccordion[i].x=accordionStPointX[i];//標準

		var tw=createjs.Tween.get(myAccordion[i]);
		tw.to({x:accordionStPointX[i]},200);

	}

}

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

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

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

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

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

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

//START
init();

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


CSS

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


/*日本語 createJS081.css*/

#demo-wrap {
position:relative;
width:auto;
height:100%;
text-align:center;
}

#image-box {
/*position:absolute;*/
position:relative;
top:0;left:0;
width:800px;
height:300px;
padding:0;
margin:0 auto;
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;
}

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


 

簡単な説明


[説明図]

 

CreateJSのマウスイベント関係が変更なってからは、少々ごまかし的な手法を取らないと旨く行かない。
このアコーディオンでは基本的な位置を先に計算しておいて、そこに移動する形態である。各々の重なりのためにイベントが途切れるので、一旦Tweenを削除して、その位置から新たな位置に移動処理をする仕組みにした。
又、Stageに補助的なイベントを設定して、動きを補完するのも1つの方法かも知れない。(後で説明)


1. HOVERでアコーディオン要素を開く。(rollover rollout)
2. HOVEROUTでアコーディオン要素を閉じる。一応全てを中間位置に戻す。
(指定要素を開くのも可能です)
3. 初期時に指定要素を開く設定が可能です。
4. 画像をクリックすれば指定ページにジャンプ可能。
5. TEXTなどを挿入できるように、コンテナ収容の形にしました、変更など可能です。
6. 設定はJS上部を参照ください。


画像用、アコーディオン

主に、MENU用途に用いられる事を前提に作っています。デモではページへのジャンプ設定は行っていませんが、設定可能ですので、リンク先のURLなどを記載ください。
テキストなどを配置して、少々加工したものは、次回に掲示します。


アコーディオン部の大きさと要素(画像)の大きさ

アコーディオン部の大きさはページの大きさなどに合わせますので、枚数に応じて適正な幅の画像を用意します。
図の様に配置されますので、それらを考慮した画像幅にしてください。画像幅が同じで枚数が増えれば重なり部分が狭くなる。この辺は臨機応変に対応する。


アコーディオン指定要素を開く原理

アコーディオン各要素のOPEN時とCLOSE時の、それぞれの「X位置」を予め計算しておきます。
HOVER要素と、HOVER要素の番号より小さい要素はOPEN処理、番号の大きい要素はCLOSE処理すれば、指定要素が表示されると言う理屈です。

但し、最初の要素(0番)は、OPEN時とCLOSE時ともに同じで、X値はで 0 ある。


マウスの左右移動時画像の重なりが原因でイベントが途切れたりする。イベント処理の簡略化のため、一旦、Tweenを削除しています。このほうが処理が楽になるようです。



//OPEN、removeAllTweensで対応
function accordion_open(no){

	//案内文の表示
	//text_set("Accordion-No: "+(no+1));
	text_set(info_text[no]);

	//removeAllTweens
	createjs.Tween.removeAllTweens();

	for (var i=0; i < image_max; i++) {
		var tw=createjs.Tween.get(myAccordion[i]);

		if(no >= i) {tw.to({x:accordionOpenPointX[i]},speed);}
		if(no < i) {tw.to({x:accordionClosePointX[i]},speed);}
	}

}

初期時に指定要素を開く

初期時に指定要素を開くには、アコーディオン要素の番号を指定します。通常1番目の要素で、0、を指定します。
初期時に中間位置にしたい場合は、指定要素を開く設定をしないでください。初期時は中間位置合わせでレイアウトしています。


指定番号要素を開く


accordion_open(番号);


//初期指定OPEN番号
if(selectUes) {
	accordion_open(select_no);
}

---------------------------------------------------------------
初期時に中間位置にしたい場合は

//初期指定OPEN番号を無効にすれば良い
var selectUes=false;

OUT時に初期指定要素をOPENさせる

中間位置にしないで、指定要素を開く場合は次のstageのOUT設定を有効にしてください。アクションはあるが現在はコメントアウトして何もしていない。


//stage-rollout/stage-u-out初期指定OPEN番号
stage.addEventListener("rollout",function (e) {
	if(selectUes) {
		//accordion_open(select_no);
	}
});

---------------------------------------------------------------
有効にする

stage.addEventListener("rollout",function (e) {
	if(selectUes) {
		accordion_open(select_no);
	}
});

画像要素をコンテナでラップ

簡略にするならばコンテナでラップしなくとも中の「Bitmap画像」のみで構成できるが、テキストなどを挿入したり、エフェクトなどを変化させることもあるので、あえてコンテナでラップしています。


rollover rollout アクション

一番簡単な rollover rollout アクションを「アコーディオン要素」に直接設定している(EventListenerの削除が困難な形)。このような構成では後で EventListener を削除するなどないと思う。
EventListener設定前に、「active判定用」の変数 no を宣言して EventListener で使用できる様にしているのが「ミソ」である。


//アコーディオン要素作成
function createAccordion(img,w,h,no) {

	//ラップコンテナ
	ac=new createjs.Container();
	//画像
	back=new createjs.Bitmap(img);
	ac.addChild(back);

	//active判定用
	var no=no;

	//ラップコンテナrollover
	ac.addEventListener("rollover",function (e) {
		//
		accordion_open(no);
	});
	//ラップコンテナrollout
	ac.addEventListener("rollout",function (e) {
		//
		accordion_close(no);
	});
	return ac;
}

番号を渡しているので、rollover した要素が何番であるか、調べる手間隙がいらないだけ簡単になる。


案内文、タイトルの表示

Text表示が有効であれば、画面左上に文字を表示します。


//案内文
var info_text=["案内文","案内文",.........];

ページへのジャンプ設定

下記配列にデータをいれて、ジャンプ設定を有効にします。カーソルが変更になり、「クリック」でジャンプします。


//リンクを有効にする
var linkUse=true;//false true

---------------------------------------------------------------
正確なURLを記載して、実行を確認ください

//リンクデータ
var link_url=["リンク先URL","リンク先URL",...........];

urlの記載部分を合わせてください。


//Click
function handleclick (event,no) {

	var hit_no=no;

	text_set(" No."+hit_no);

	//リンク有効ならば処理
	if(linkUse) {

		//登録リンクデータ
		var url="/main/html/" + link_url[hit_no];

		//例ウィンドウに出力
		location.href=url;
	}

}

デモではジャンプ設定をしていません。


画像の読み込み失敗による不具合

画像の読み込み失敗がある場合は、画像とリンクが合わなくなります。(現在ではほとんど無いと思いますが....)
エラー処理をして代替画像を用意するなどの処置が必要になりますが、このJSはエラー処理に対処していません。
次回はエラー処理をしたものを掲載します。


Canvasエレメントで画像同様のものを即座に作れますのでそれを代用すれば、読み込みエラーでも問題は解消します。ここまで処理するかは個人の判断になります。


● 簡単なエラー処理、代替画像挿入

画像読み込みエラー処理関数を追加、あとで削除をお忘れれなく。
エラー時、画像と同じ大きさの白い画像同等のCanvasエレメントを作り、配列assetsに入れていますので、リンクデータなどが合致します。
下の例では白ベタ画像ですが、グラデーション処理などすればモット綺麗になります。



//ローダーListenerにerror関数を追加する
loader.addEventListener("error",loaderror);

//エラー処理
function loaderror(event) {
	//エラーの場合代替画像を作りassets容器に格納
	var img=createColorCanvas (accordionWidth,accordionHeight,"#FFFFFF");
	assets.push(img);
}

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

//色付きcanvasを作る
function createColorCanvas (w,h,c) {
	var canvas=document.createElement("canvas");
	canvas.width=w;
	canvas.height=h;
	var ctx=canvas.getContext("2d");
	ctx.fillStyle=c;
	ctx.fillRect(0,0,w,h);
	return canvas;
}

随意の場所でListener削除


//追加error関数を削除
loader.removeEventListener("error",loaderror);

コンテンツの表示

原則、画像アコーディオン表示専用であり、「htmlコンテンツ」のアコーディオン表示はできません。ステージである「Canvasエレメント」の上層に「htmlコンテンツ」を重ねることは可能ですが、アコーディオンで組み合わせると違和感があります。(アコーディオンが開いてからその上に「htmlコンテンツ」を重ねて表示は可能、「Canvas」に直接描画する訳ではないので大きな違いがある)


「htmlコンテンツ」のアコーディオン表示は「Canvas」を使用しない、JavaScriptまたはjQueryなどのアコーディオンを使用してください。そのほうが自由度、応用性があります。


使用画像

原則、画像は使用者が用意します。640x300 使用画像はデモページにあります。



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

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


以上です。

 


[ この記事のURL ]


 

ブログ記事一覧

年別アーカイブ一覧



[1]