POPSブログ

jQueryのattr()で画像表示とフェード

191

  Category:  jquery2013/01/04 pops 

jQueryで、画像をimg要素に読み込むにattr()を使用します。フェード、クロスフェードなどの画像処理を行ってみます。

 

jQueryのattr()で画像表示とフェード

jQueryで、画像をimg要素に読み込むにattr()を使用します。但しただ表示、フェード表示するだけなら簡単ですが、、クロスフェードなどの処理を行おうとすると考慮しなければならない事が多々あります。
最大の問題は、画像が処理以前にキャッシュされていなければなりませんし、フェード処理すると色々と不可解なことが起こるものです。


1. JavaScriptの、nwe Image()機能を使用して事前に画像を読み込む。
2. 画像読み込みがわかるようにLoading画像を使用する。
3. フェード、クロスフェードなど行う場合の問題点を考慮する。(特にIEに多く問題が発生するので注意)
4. ボタンなどがある場合は、フェードの影響を受けないよう考慮する。
5. 全ての人が、高価且つ最新のマシンでアクセスしている訳ではない。(良すぎる環境では判らないことがある、画像フェードは特に負荷がかかるので問題が出易い事を考慮する)


画像読み込みクロスフェード表示 サンプル


Example

フェード中はボタンを押しても無効です。画像をロード出来ない場合「Loading画像」を「クリック」すれば解除されます。


  • INDEX1
  • INDEX2
  • INDEX3


 

サンプルのHTML JS CSS


HTML


<ul id="tab-menu">
	<li text="/main/images/toyota_car10.jpg">INDEX1</li>
	<li text="/main/images/toyota_car11.jpg">INDEX2</li>
	<li text="/main/images/toyota_car12.jpg">INDEX3</li>
</ul>
<div id="image-box-base">
	<div id="image-box"><img /></div>
	<div id="top-box"><img /></div>
	<div id="loading"></div>
</div>

text属性は当方が勝手に作った属性です。jquery attr() で読み込みできます。

画像URLは上記サンプルの例です。使用者の画像収納先に合わせてください。


JS

imgload03.js 必要な設定はJS上部参照。


//imgload03.js
//日本語

(function($){

	$(function () {

		//設定
		var select_no=0;//最初に開くメニューの位置
		var speed=800;//フェード速度
		box_W=640;//画像BOX幅
		box_H=300;//画像BOX高さ

		var no=0;
		var keep_no=select_no;
		var img_url="";
		var load_url="";
		fade_flag=false;

		//オブジェクト
		var tabmenu=$("#tab-menu");
		var boxbase=$("#image-box-base");
		var imagebox=$("#image-box");
		var topbox=$("#top-box");
		var loading=$("#loading");

		//欄外移動
		topbox.css({'left':box_W});
		//loadingを一旦けす
		loading.css({'display':'none'});
		//指定場所のOPEN
		tabmenu.find("li").eq(select_no).addClass("active");
		img_url=tabmenu.find("li").eq(select_no).attr('text');
		//指定画像を表示
		imagebox.children("img").attr({'src':img_url});

		//メニューclick-action
		tabmenu.find("li").click(function() {

			if(fade_flag) {return false}
			no=tabmenu.find("li").index(this);
			if(no == keep_no) {return false}

			tabmenu.find("li").removeClass("active");
			$(this).addClass("active");

			//画像URL取得、画像の読み込み
			load_url=$(this).attr('text');
			imgload ();
			return false;

		});

		//loading-click-action
		loading.click(function() {
			//
			loading.css({'display':'none'});
			//menuを前に戻す
			tabmenu.find("li").removeClass("active");
			tabmenu.find("li").eq(keep_no).addClass("active");

			fade_flag=false;
			return false;
		});

		//画像Preloader
		function imgload () {

			loading.css({'display':'block'});
			//imgPreloaderを作成
			var imgPreloader=new Image();
			//イベントハンドラ
			imgPreloader.onload=function() {

				loading.css({'display':'none'});
				//画像表示に進む
				show_image();

			}
			//重要、最後に書く
			imgPreloader.src=load_url;
		}

		//画像表示処理
		function show_image() {

			//欄外移動
			topbox.css({'left':box_W});

			//画像挿入
			topbox.css({'opacity':0}).children("img").attr({'src':load_url});

			//原点に戻す
			topbox.css({'left':0});

			//flag
			fade_flag=true;
			//CROSSFADE
			topbox.animate({'opacity':1},speed,function(){

				img_url=load_url;
				//下画像に新しいURL画像を入れる
				imagebox.children("img").attr({'src':img_url});
				//上画像欄外移動
				topbox.css({'left':box_W});
				//
				fade_flag=false;
				keep_no=no;

			});

		}

	});

})(jQuery);

JS名、クラス名など修正したい場合は、html js css 共に該当部分を修正ください。自由な名前で設定できます。


CSS

imgload03.css


/* imgload03.css 日本語 */

/* tab-menu  */
ul#tab-menu {
display:inline-block;
list-style:none;
width:100%;
height:20px;
margin:0;
padding:0;
}
#tab-menu li {
display:inline;
list-style:none;
width:60px;
height:20px;
line-height:20px;
font-size:11px;
font-weight:bold;
text-align:center;
margin-right:2px;
border-top-left-radius:5px;
border-top-right-radius:5px;
-moz-border-radius-topleft:5px;
-moz-border-radius-topright:5px;
-webkit-border-radius-top-left:5px;
-webkit-border-radius-top-right:5px;
background-color:#888888;
float:left;
cursor:pointer;/*default*/
}
#tab-menu li.active {
background-color:#EEEEEE;
}
#tab-menu li:hover {
color:#FFFFFF;
background-color:#FF1493;
}

/* image-box-base */
#image-box-base {
position:relative;
top:0;left:0;
display:block;
width:640px;
height:300px;
padding:0;
margin:0;
background-color:#000000;
overflow:hidden;
}

/* image-box */
#image-box {
position:absolute;
top:0;left:0;
display:block;
width:640px;
height:300px;
padding:0;
margin:0;
background-color:#000000;
}
#image-box img {
width:100%;
height:100%;
}

#top-box {
position:absolute;
top:0;left:0;
display:block;
width:640px;
height:300px;
padding:0;
margin:0;
}
#top-box img {
width:100%;
height:100%;
}

/* loading */
#image-box-base #loading {
display:block;
position:absolute;
top:0;left:0;
width:100%;height:100%;
background:url("/main/images/loading.gif") no-repeat center center;
background-color:transparent;
}

注意、loadingは一般的によく使用されています、他のJSと競合する場合は、ID名を変えるなどの処置をして下さい。


サンプルの基本構造


説明図


図のように、クロスフェード表示用の作業層(#top-box)でフェードを行います。其の時、下の層(#image-box)には前の画像があり、上の作業層の画像がフェードインする事によりクロスフェードを実現しています。
この構造の場合は色々な画像エフェクト(slideなど)に好都合になりますので応用に便利です。


1. 基本的に画像を new Image() 形式でロードしています。
2. 画像を attr() する場合に、一旦、作業層を右に移動して画像を挿入します。(アニメーション前に行う作業の量、またマシン環境によっては事前の作業が見える事がありますので隠しています)
3. 一番上には、Loading画像を配置します。メッセージなどのテキスト層などの配置も可能です。
4. Slide-In、Slide-Outなどのエフェクトも作業層をを旨く利用すれば可能です。
5. 原則、エフェクト(フェードを含む)は画像を収容しているBOX構造に対して行われます。(画像のみフェードさせた方が負荷の点では効率は良いのですが、色々とBOXをアニメーションした方が便利です)
6. 画像URLが間違っていたり、画像を読み込めない場合は、Loading画像を「クリック」すれば元にもどります。


#top-box階層

フェードなどを行う専用作業階層であり、画像挿入のときは原則、右に移動して行います。画像挿入タイミングのズレが防げます。挿入したら原点もしくはアニメスタート初期位置に移動させます。(透明度0で、画像を挿入したら一瞬画像を表示した。透明度0で、display:noneを実行したら一瞬画像を表示した。などのチン現象が起こることがある)
エフェクトなどが終了すれば、右に移動させて「非表示」状態にする。IEのアルファフィルタでの問題が起きても直ぐ「非表示」になるから判らない利点がある。


#image-box階層

エフェクトは行わない。画像を表示するだけの階層であり、画像切り替えは attr()で行う。エフェクトによる影響は受けない。原則、上に作業階層の画像があるとき、画像を交換する。
上に作業階層の画像が無く、タイミングのズレが有るときは、下の説明のように setTimeout() を使用すると起きない。
(通常、タイミングのズレはおきないが、アニメの負荷が大きく、画像処理終了前にJSが次のスクリプトを実行するのが原因と思われる)


●opacityアニメーションの設計

以下、色々と作り、経験を踏まえた上の説明である。他でこのような事を書く人はいない。
JSの処理速度は速くなっているが、画像の処理速度は変わらないこの辺に問題がある。
古いマシン環境でなく、通常のマシン環境または高価なマシンの場合は処理速度が速いので問題は起きない。

ページのCSSの量、他に動作しているJSがあるか、FLASHが動作しているか、などの条件でも違いが出てきますので、多少は悪い条件下でテストも必要になります。


1. 透明度のみ変化させる場合


//アニメ
topbox.animate({'opacity':1},speed,function(){
	//アニメ後の処理
});

2. 透明度及び大きさなどを変化させる場合
アニメ直前にCSSで初期値を設定してやれば色々な変化が可能である。アニメのopacity処理の順序によっては、アニメ後の処理が乱れる場合があるので調整する。マシン環境が良い場合は問題は出ない。


//アニメ前のスタートする位置などCSSで設定
topbox.css({'left':X位置値,'top':Y位置値,'width':幅値,'height':高さ値,'opacity':初期透明度値});

//アニメ
topbox.animate({'left':0,'top':0,'width':box_W,'height':box_H,'opacity':1},speed,function(){
	//アニメ後の処理
});

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

状況によっては順序を違わせることも有る
topbox.animate({'opacity':1,'left':0,'top':0,'width':box_W,'height':box_H}..........

3. 画像と画像BOXを同時並行アニメ処理する場合
opacity処理は本来画像が対象であるから、opacity処理の効率が良くなる


//アニメ前のスタートする位置などCSSで設定
topbox.children("img").css({'opacity':初期透明度値});
topbox.css({'left':X位置値,'top':Y位置値,'width':幅値,'height':高さ値});

//アニメ
topbox.animate({'left':0,'top':0,'width':box_W,'height':box_H},speed);
topbox.children("img").animate({'opacity':1},speed,function(){
	//アニメ後の処理
});

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

状況によっては順序を違わせることも有る
//アニメ
topbox.children("img").animate({'opacity':1});
topbox.animate({'left':0,'top':0,'width':box_W,'height':box_H},speed,function(){
	//アニメ後の処理
});

通常面倒なのでこの形式は使わない。エフェクトの種類により必要な場合に使うことがある。


●アニメーション後の setTimeout() について


通常マシン環境、マシン環境が良い場合は、下記については考慮しなくとも良い。アニメ処理の後にスムーツに行かない時は有効な手段と思う。


opacity処理(フェードなどの透明化)の後に、画像を挿入したり、display:none などを実行した場合に多少画面に不具合が出る事があります。画像処理(opacity処理)が遅れ、スクリプトの実行と噛み合わない?
普通には起こりませんが、主に、Firefoxでマシン環境の良くない時 (Firefoxは動作が重いので通常はマシン性能の良い方が使用する、マシン環境が悪くFirefoxを使用している人は居ないと思いますが、、、)、有るいはIE78などスクリプト実行の遅い環境の時。

アニメーション後の setTimeout()で不具合を防ぐことが出来るようです。またアニメーション後では無くともタイミングのずれがある場合、setTimeout()が有効になるようです。面倒ですが!。


setTimeout()使用しない場合、通常はいらない。


//CROSSFADE
topbox.animate({'opacity':1},speed,function(){
	アニメ完了後の処理
});

setTimeout()使用の場合、問題がある時有効です。(TIMER値は200-600位、マシン環境が悪い場合は長い時間)


//CROSSFADE
topbox.animate({'opacity':1},speed,function(){
	//Firefox対策
	setTimeout(function(){
		アニメ完了後の処理
	},500);
});

私見ではありますが、フェードは一番負荷が掛りますから、画像処理(opacity処理)が遅れ、完全に終了する前に次ぎのスクリプトを実行してしまうのが原因と予測します。


その外


ボタンなどがある場合は、フェードの影響を受けないよう考慮する

一般的にIEでの問題です。ボタン画像の種類などにもよりますが影響を受ける場合は、

1. フェードする階層外において影響を受けないようにする。
2. フェードする前に「非表示」にして、使用する時点で「表示」する。
3. ボタンを fadeIn()すると黒くなるなどの現象がある場合は、ボタンをラップしてラップ層をfadeIn()する。


其の外の #top-box 階層の利用

下のように、#top-box 階層にその都度、何らかを append() すれば、またエフェクトの幅が広がる。
当方では、画像分割の際に、ここに分割した構造を append() して構成している。アイデア次第である。


<div id="image-box-base">
	<div id="image-box"><img /></div>
	<div id="top-box"> ここにあとで構造をJSで作って入れる </div>
	<div id="loading"></div>
</div>

Loading画像など

使用画像は原則、使用者がご用意ください。Loading画像は好きなものが使用可能です。

loading.gif 31x31 :


画像先読み、javascriptの new Image() に関しては、下記の記事を参考ください。

【参考】当方の記事: jQuery非同期、Image()で画像読み込み表示


以上です。

 


[ この記事のURL ]


タグ:jquery , photo , memo

 

ブログ記事一覧

年別アーカイブ一覧



[1]