roomx.jp

Room No.1

JavaScript

Lightbox風 画像ビューワ【拡大・縮小表示対応版】

2014.12.05

先のLightbox風の画像ビューワを元にして閲覧者のブラウジングサイズに合わせた画像の拡大・縮小表示機能を追加しました。

元々は、当サイトのブログ( Room B )で使用しているWordPressに組み込む為に組んだプログラムですが、HTMLとJavaScriptで構成されているので、WordPressに限らず一般のHTMLページでも動作します。

WordPressにLightbox風の画像ビューワを実装するのに一番簡単な方法は、公開されているWordPressのプラグインを使う事ですが、自分で調べた限りでは、記事(画像)を投稿する際に画像をメディアファイルとしてWordPress経由で画像をアップしていないと、後からプラグインを組み込んでも正しく機能しないモノが殆どでした。これはWordPressの記事に埋め込まれた画像が記事の本文とデータベース(DB)によって関連付けられおり、プラグインはこのDBを参照し、格納先の画像を呼び出してLightbox風の画像表示を行うからだと思います。

WordPressのようなCMS(Content Management System)を使うのであれば、全ての情報をDBで管理するのが当然なのですが、個人的にメディアファイル投稿が面倒なので使わず、画像情報のDB登録も行っていませんでした。この状態でエントリー数が150件を超えた段階で後からプラグインを使ってのLightbox風画像ビューワの実現は困難であり現実的で無いと判断しました。

が・・・、それでもやはりブログ内の画像をクリックする度にページ遷移したり別タブが増えるのはアレなので、何とかメディアファイル投稿をしなくてもLightbox風画像表示が出来ないモノか考えた結果、JavaScriptに必要なパラメータを与える(投げる)事さえ出来れば何とかなりそうだったので記事内の画像リンクの方を全て修正して強引に実現させました。投稿済みの全ての画像をメディアファイルとして再投稿する場合は本文側の修正・編集・調整も必要となりますが、本文内の画像リンク(<a>タグ)のみなら何とかなるかなと・・・。(それでも数千箇所の修正が必要になりましたがw)

ついでに画像リンク情報の記述(書式)も統一化し、疑似ギャラリー表示機能も後から実装可能な様にHTMLを一工夫しました。(※今回は実装していません)

処理の流れ

コードの殆どは以前書いたモノを流用し、処理手順・内容とも殆ど同じです。
大きく異なるのは、本文内の<a>タグからJavaScriptにリンクさせている点と、表示画像を閲覧者のブラウジング環境(サイズ)に合わせて拡大・縮小表示するようにした点です。

フルサイズの実体画像を<img src="ディレクトリ+ファイル名">で呼び出し、CSSで縮小表示しています。
一般的には縮小表示専用のサムネイル画像を用意するところですが、画像レイアウトや画像の入れ替え等が面倒になるのでサムネイル画像を別途用意していません。ただし、この方法は元の画像データが大きい場合、ページの読み込みに時間が掛かり表示が遅くなる(閲覧側のPC性能・通信環境に依存)ので、予め画像データの軽量化を図るなどしてデータサイズに留意する必要があります。

画像格納先ディレクトリは1つのエントリー(記事)につき1つのディレクトリとする必要は有りませんが、上位ディレクトリは共通でないと本文にリンクを記述するのが大変になり、JavaScriptでの処理が困難になります。

・動作確認 → Lightbox風 画像ビューワ【拡大・縮小表示対応版】 : like_lightbox_200.html

・サンプルダウンロード → like_lightbox_2.zip [417KB]

 


<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Lightbox風 画像ビューワ【拡大・縮小表示対応版】</title>
<link rel="stylesheet" type="text/css" media="all" href="like_lightbox_200.css">
</head>

<body>
<h3>Lightbox風 画像ビューワ【拡大・縮小表示対応版】サンプル</h3>
<div id="content">
<p>下の3つの画像は元サイズがwidth="800"ピクセルです。<br>
クリックするとブラウザのサイズに合わせて拡大・縮小表示されます。</p>
<p>
<a class="sample2" onclick="return Simg('sample2','01.jpg');">
<img src="img/sample2/01.jpg" width="800" height="639" alt="DANBOARD + Mac" class="resize200">
</a>
<a class="sample2" onclick="return Simg('sample2','02.jpg');">
<img src="img/sample2/02.jpg" width="800" height="639" alt="DANBOARD + Win" class="resize200">
</a>
<a class="sample2" onclick="return Simg('sample2','03.jpg');">
<img src="img/sample2/03.jpg" width="800" height="639" alt="DANBOARD in Mac" class="resize200">
</a>
</p>
<p>この画像は元のサイズが width="1024"です。クリックすると原寸大で表示</p>
<p>
<a class="sample2" onclick="return Simg('sample2','120213-1.jpg');" style="display:block; width:530px;">
<img src="img/sample2/120213-1.jpg" width="1024" height="683" alt="DANBOARD with Snow-man" class="resize500">
</a>
</p>
</div>
 
<div id="imglay">
<div onClick="return Limg()"><img id="img_view" src="" style="border: 15px solid #FFFFFF;"></div>
<div id="img_close">
<a href="javascript:void(0)" onClick="return Limg()">
<img src="img/close.png" alt="CLOSE" title="CLOSE"></a>
</div> 
</div>
 
<script type="text/javascript">
function Simg(d,n){
	document.getElementById('imglay').style.display='block';
	var img_dir = 'img/' + d + '/';
	var img_num = n;
	var img_file = img_dir + img_num;
	document.getElementById('img_view').src = img_file;   //表示画像
 
/*------------------------------------------画像サイズ・表示サイズ制御*/
 
	if(document.all){
		Ws = document.documentElement.clientWidth;   //表示領域取得 (IE8:標準モード)
		Hs = document.documentElement.clientHeight;
		//Ws = document.body.clientWidth;            //表示領域取得 (IE6.7:互換モード)
		//Hs = document.body.clientHeight;
	}else{
		Ws = window.innerWidth;  //表示領域取得
		Hs = window.innerHeight;
	}
 
	img_F = new Image();
	img_F.src = img_file;
	img_W = img_F.width;
	img_H = img_F.height;
	mg_prop = img_W / img_H; //画像縦横比率
 
	if( img_W <= 800 ){
		if(Ws*0.8 >= img_W && Hs*0.8 >= img_H){  //Ws=80% Hs=80%基準
			imgTru();
		}else if(Ws*0.8 < img_W || Hs*0.8 < img_H){
			img_resW = Math.ceil(Ws * 0.8);                       //image Wサイズ優先
			img_resH = Math.ceil(img_H * (img_resW / img_W));     //画像:Hサイズ比率適用
			if(img_resH >= Hs * 0.8){
				img_resH = Math.ceil(Hs * 0.8);                      //image Hサイズ優先
				img_resW = Math.ceil(img_W * (img_resH / img_H));    //画像:Wサイズ比率適用
				imgRes();
			}else{
				imgRes();
			}
		}
	}else{
		imgTru();
	}
}
 
function imgRes(){
	document.getElementById('img_view').style.width = img_resW +'px';
	document.getElementById('img_view').style.height = img_resH +'px';
}
function imgTru(){
	document.getElementById('img_view').style.width = img_W +'px';
	document.getElementById('img_view').style.height = img_H +'px';
}

function Limg(){
	document.getElementById('imglay').style.display='none';
}

//-->
</script>
</body>
</html>

ほぼ上記のコードのまま、実際にこのサイトのブログ( Room B )に実装しています。
WordPressに組み込む場合は記事内の画像リンク箇所を修正し、テンプレートファイルに(自分は footer.php に記述)【div id="imglay"】で囲まれた部分とJavaScriptのコード全てを追記します。

ただし、画像リンクの書式が決まっているので後付けの場合は全エントリーの修正が必要になり、記事数が多ければ多いほど大変な作業になるのでプラグインの様に簡単・お手軽に機能拡張というワケには行きませんが、こういう方法も有るよ、という参考にでもなればと思います。

 

解説・注意点

コードのポイントなど・・・(´・ω・`)

画像の拡大・縮小表示部分のスタイルシートについてはコチラのページを参照して下さい。
※今回はスタイルシートは別ファイルにしています。

<a class="sample2" onclick="return Simg('sample2','01.jpg');">
<img src="img/sample2/01.jpg" width="800" height="639" alt="DANBOARD + Mac" class="resize200">
</a>

本文に埋め込んだ画像リンク部分です。

普通(?)アンカーポイントを示す<a>タグを使う場合、href属性を記述するのですが<img>タグで実体ファイルを呼び出しているのでhref属性は必要無く、JavaScriptへのリンクのみとなっています。 JavaScriptに投げるパラメーターはディレクトリ名と画像ファイル名のみとしていますが、ブラウザが対応している画像形式であればどんな画像でも問題ないハズです。

※一部のサイトでは<a>タグにはhref属性が無いとW3CのHTMLバリデーション・チェックに引っ掛かるとか、SEO的に不利とか書かれていましたが、実際はそんな決まり事は無いので安心してして下さい。

<a>タグの class="sample2" は画像の格納先ディレクトリ名をそのままクラス名にしています。
これは将来的にギャラリー風画像表示を実現する際に【getElementsByClassName】を使えば処理が簡単になると考えたからで、同一階層に同一ディレクトリ名が存在する事はシステム上有り得ないので直感的にも判りやすくてベターかなと・・・。

<a class="sample2" onclick="return Simg('sample2','120213-1.jpg');" style="display:block; width:530px;">

基本的に<a>タグはinline要素なのですが、1行に大きく画像を1枚表示する場合は display:block; としてブロックレベル要素として範囲指定をしないと1行分すべてがクリック可能な範囲となってしまいます。

実際は、ブログやサイトのレイアウトによって表示画像サイズとブロックレベルの範囲を変更する事になると思うので適宜変更して下さい。

 

var img_file = img_dir + img_num;
document.getElementById('img_view').src = img_file;   //表示画像

パラメーターを元に画像ファイルを特定しています。
変数: img_file は後の画像拡大・縮小表示でも必要となるので今回はディレクトリとファイル名の情報を一つの変数にまとめました。

 

	if(document.all){
		Ws = document.documentElement.clientWidth;   //表示領域取得 (IE8:標準モード)
		Hs = document.documentElement.clientHeight;
		//Ws = document.body.clientWidth;            //表示領域取得 (IE6.7:互換モード)
		//Hs = document.body.clientHeight;
	}else{
		Ws = window.innerWidth;  //表示領域取得
		Hs = window.innerHeight;
	}

ユーザーのブラウジングサイズを取得します。

例によってIE8がぁ・・・ヽ(´o`;
なのでこの様な事になっています。場合によってはスクロールバーも含んだ領域を取得する必要があると思いますが、その場合には検索して適宜書き換えて下さい。(※IE6・7については、既にサポートの必要が無いかも?ですが一応・・・)

 

	img_F = new Image();
	img_F.src = img_file;
	img_W = img_F.width;
	img_H = img_F.height;
	mg_prop = img_W / img_H; //画像縦横比率

対象画像のW・Hサイズの取得、画像の縦横比を取得しています。
確実に取得できるように new を使い、先の変数:img_file をソースとして指定しています。

今回、画像の縦横比率は必要ありませんが、備忘録代わりに・・・。

 

	if( img_W <= 800 ){
		if(Ws*0.8 >= img_W && Hs*0.8 >= img_H){  //Ws=80% Hs=80%基準
			imgTru();
		}else if(Ws*0.8 < img_W || Hs*0.8 < img_H){
			img_resW = Math.ceil(Ws * 0.8);                       //image Wサイズ優先
			img_resH = Math.ceil(img_H * (img_resW / img_W));     //画像:Hサイズ比率適用
			if(img_resH >= Hs * 0.8){
				img_resH = Math.ceil(Hs * 0.8);                      //image Hサイズ優先
				img_resW = Math.ceil(img_W * (img_resH / img_H));    //画像:Wサイズ比率適用
				imgRes();
			}else{
				imgRes();
			}
		}
	}else{
		imgTru();
	}

ブラウジングサイズに合わせて対象画像を拡大縮小する処理です。
ターゲット画像ファイルのW・Hを取得し、ブラウザの表示領域に合わせてスタイル指定で拡大・縮小を行っています。

一番先頭の条件判定は、自分が横:800ピクセルの画像を基本サイズとしている為で、横:800ピクセル以上の画像はそのまま表示するようにしています。
その際はブラウザの表示領域次第で画像全体が表示されませんが意図的に実サイズで表示する必要が有る画像もブログに含まれているのでこの様な処理にしています。

表示可能領域の縦横各80%を基準として、このサイズより大きな画像は縮小し、表示可能領域の80%より小さな画像はそのまま表示しています。
80%という数字もサイトによって最適な数値は変わって来ると思いますのでデザインやレイアウトに合わせて変更して下さい。

縮小表示判定は最初に横(W)方向のサイズについて行い、同じ縮小比率を縦(H)方向に適用しています。(自分は ceil で画像ピクセルを整数化しています)

横長画面で横長画像のみの表示を行うだけであればこの処理だけで済むのですが、横長画面で縦長画像を表示する場合も考えられ、画像のサイズによっては縮小しても縦方向の表示領域をオーバーする事も有り得ます。(例えば正方形の画像等)
なので横方向の縮小比率を縦方向に適用した後、縦方向の表示領域をオーバーしていないか再度チェックしています。
このチェックで縦サイズの表示領域をオーバーしている場合は、縦方向の縮小を優先してその縮小比率を横方向に適用しています。

最初は横長ブラウジングか?縦長ブラウジングか?横長画像か?縦長画像か?・・・などと細かく条件分岐させていましたがダラダラと長いコードになってしまったので、最終的には単純にブラウザの表示領域をオーバーしているか否かのみで判定を行う処理にしました。

実際にWordPressに記事を投稿する際は、色々なサイズの画像が混在すると思いますが先のコードで最低限の見栄えは整えられると思います。

最初からメディアファイル投稿をしておけばこんな苦労はしなくて良いのでしょうが・・・後悔先に立たずです(´・ω・`)

▲BACK TO TOP