写真ギャラリーのソース解説④ ~Javascriptによる画像の順次読み込み~

先日公開した写真ギャラリーのソースコードを解説していきます。

第4回目はJavascriptによる画像の順次読み込みの解説です。
予めサムネイル画像には軽い画像 (紹介している例では、”Now Loading….” と書かれた画像) を読み込ませておき、先頭から順番に本来のサムネイルへと切り替えていきます。
順番で表示させないと回線が遅い場合、全体の画像がちょっとずつ読み込まれてなかなか一枚の画像が表示されずにストレスになるかもしれません。

機能などの紹介は紹介の記事を見て下さい。



ソースコード

恒例のソースコードから見ていきましょう。

// サムネイルを読み込んで、一枚読み込んだら次の画像を再帰で読み込む
var _loadImagesInitialize = function(){
	var _imageNum     = 0;
	var _loadingFlag  = 0;   // 0:読み込み中でない、1:読み込み中
	var _thumbName       ;
	var _loadImage       ;
	var _createdThumb = 0;
	return function __loading(){
		_loadImage           = document.getElementById("thumb_list").children[_imageNum].firstChild.firstChild;
		if(_loadImage && !_loadingFlag){
			_loadingFlag = 1;   // 読み込み中フラグを立てる
			_thumbName   = (gallery_list[_imageNum].path.split("./"))[1];
			_thumbName   = _thumbName.split("/").join("_");
			_thumbName   = _thumbName.split(".").join("-" + thumbWidth + "x" + thumbHeight + ".");
			_loadImage.src  = "./cache/" + _thumbName;
			_loadImage.onload  = function(){
				_imageNum++;
				__loading();
			}
			_loadImage.onerror = function(){
				_loadImage.src  = "./create_thumbnail.php?url=" + gallery_list[_imageNum].path + "&width=" + thumbWidth + "&height=" + thumbHeight;
				_createdThumb++;
				_imageNum++;
				_loadImage.onload = function(){
					__loading();
				};
			};
			_loadingFlag = 0;   // 読み込み終了
			document.getElementById("created_thumb").innerHTML = "Created thumbneil to cache : " + _createdThumb;
		}
	};
};
var _loadImages = _loadImagesInitialize();

解説

今回の肝は、クロージャと再帰処理です。
クロージャを使って再帰処理させることでグローバル変数を汚さずにどこまで読み込んでいるのかを保持しておくことができます。

初期化

はじめに、クロージャ内で使用する変数の初期化を行います。
そして、初期化した変数を持ったクロージャ化した関数を定義します。

// サムネイルを読み込んで、一枚読み込んだら次の画像を再帰で読み込む
var _loadImagesInitialize = function(){
	var _imageNum     = 0;
	var _loadingFlag  = 0;   // 0:読み込み中でない、1:読み込み中
	var _thumbName       ;
	var _loadImage       ;
	var _createdThumb = 0;
	return function __loading(){   // 再帰させないなら無名関数でOK ( return function(){ )
		// _loadImagesInitialize関数はクロージャ化された__loading関数を返す関数です
		// 読み込み処理
	};
};
// _loadImagesに初期化された__loading関数を代入して関数として使用します
var _loadImages = _loadImagesInitialize();

まずは、以下の変数を初期化します。
 ・_imageNUM … 読み込むサムネイル画像のID番号
 ・_loadingFlag … 画像を読み込んでいる最中かどうかのフラグ
 ・_thumbName … キャッシュに保存されているであろうファイル名
 ・_loadImage … サムネイル画像を読み込むIMG要素への参照
 ・_createdThumb … 新規で生成したサムネイル画像数

_imageNUMと_loadingFlagは初期化が必須です。
_thumbNameと_loadImageは再帰で読み出す度に変数が宣言されるのが気持ち悪いので、先に宣言だけしておきます。(Javascriptの挙動的には大した違いはなく、処理速度も殆ど同じです)
_createdThumbに関しては新規でサムネイル画像を作成した数を数える為だけです。

続いて、return命令で定義した関数を返します。
再帰させない処理とするなら無名関数function()と省略することができます。

もちろん関数を定義してから返り値に渡してもOKです。(無名関数は不可です)
その場合は以下のように書きます。こっちの方が分かりやすいかもしれませんね。

// 関数定義とreturnをまとめた場合
return function __loading(){
	// 読み込み処理
	};
};

// 関数定義とreturnを分けた場合
function __loading(){
	// 読み込み処理
}
return __loading;

ここでこの__loading関数がクロージャになります。
クロージャはクロージャの外で定義された変数を操作することができ、また、その関数の内部で値を保持したまま利用することができます。

今回の場合だと_imageNUMをクロージャの外で宣言と同時に0で初期化していますが、クロージャである__loading関数内で__loading関数が呼び出される度にインクリメント (値を+1する) されていきます。
クロージャ・・・分かりにくいですよね。
ご自身で使ってみると段々と理解できると思います。

最後に初期化した変数をクロージャ内に持つ関数を_loadImagesに代入して終了です。
ここで、”var _loadImages = _loadImagesInitialize;” と関数の “()” を忘れないように注意して下さい。忘れると初期化する関数が代入されてしまいます(笑)

画像の読み込みを処理する関数

では画像を順次読み込んでいく関数を解説します。
難しい処理はないので簡単にいきます。

function __loading(){
	_loadImage           = document.getElementById("thumb_list").children[_imageNum].firstChild.firstChild;
	if(_loadImage && !_loadingFlag){
		_loadingFlag = 1;   // 読み込み中フラグを立てる
		_thumbName   = (gallery_list[_imageNum].path.split("./"))[1];
		_thumbName   = _thumbName.split("/").join("_");
		_thumbName   = _thumbName.split(".").join("-" + thumbWidth + "x" + thumbHeight + ".");
		_loadImage.src  = "./cache/" + _thumbName;
		_loadImage.onload  = function(){
			_imageNum++;
			__loading();
		}
		_loadImage.onerror = function(){
			_loadImage.src  = "./create_thumbnail.php?url=" + gallery_list[_imageNum].path + "&width=" + thumbWidth + "&height=" + thumbHeight;
			_createdThumb++;
			_imageNum++;
			_loadImage.onload = function(){
				__loading();
			};
		};
		_loadingFlag = 0;   // 読み込み終了
		document.getElementById("created_thumb").innerHTML = "Created thumbneil to cache : " + _createdThumb;
	}
}

まずは、_loadImage変数にIMG要素の参照を代入します。
ここはHTMLの構造によって適宜変更して下さい。

次にIF文でIMG要素が存在することと読み込み中でないことを確認します。
確認が済んだら、読み込み中のフラグを立てて、キャッシュに保存されているであろうファイル名を_thumbNameに代入して準備は完了です。

そして、画像にサムネイル画像のパスを指定して読み込みをさせていきます。
読み込みが成功したらサムネイルのID番号をインクリメントして再帰させます。

もし、読み込みに失敗したらキャッシュに画像がない (まだサムネイル画像が生成されていない) 場合は、サムネイルを作成するPHPでサムネイルを作成します。
今回は成功するはずなので読み込み完了したら再帰させます。

表示領域の全ての要素に対してサムネイル画像が読み込めたらフラグを0に戻して終了です。

まとめ

以上、画像の順次読み込みの解説でした。

説明不足等あると思うので、ご質問等あればコメントやお問合せ下さい。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)