2014/01/07
Fancyboxのようにサムネイルから飛び出してくるようなjQueryを組んでみる
ライトボックス系のjQueryプラグインであるFancyboxでは、
サムネイルをクリックすると、そこから画像が飛び出してくるような効果をつけることができ、
個人的に好きなので、よく使っています。
この効果を、自分でも組むことができるようになりたかったので、
実際にjQueryを使って組んでみました。
今回はせっかくなので、
画像を読み込んでいる間に、サムネイル上にローディングアニメーションを表示する効果も一緒に組んでみました。
↓こちらがそのDEMOです。
手順
今回は、aタグでリンクの指定された画像をターゲットとして、
リンク先の画像をモーダルウィンドウで表示することを想定しました。
ターゲットとなるHTMLの例です。
1 2 3 4 5 6 7 8 9 10 | <ul> <li><a href="images/image01.jpg"><img src="images/thumb_image01.jpg" alt="image"></a></li> <li><a href="images/image02.jpg"><img src="images/thumb_image02.jpg" alt="image"></a></li> <li><a href="images/image03.jpg"><img src="images/thumb_image03.jpg" alt="image"></a></li> <li><a href="images/image04.jpg"><img src="images/thumb_image04.jpg" alt="image"></a></li> <li><a href="images/image05.jpg"><img src="images/thumb_image05.jpg" alt="image"></a></li> <li><a href="images/image06.jpg"><img src="images/thumb_image06.jpg" alt="image"></a></li> <li><a href="images/image07.jpg"><img src="images/thumb_image07.jpg" alt="image"></a></li> <li><a href="images/image08.jpg"><img src="images/thumb_image08.jpg" alt="image"></a></li> </ul> |
JavaScript
はじめに初期設定をします。
後々調整が必要な情報はココでまとめて設定しておくと調整が楽ですし、
プラグイン化することになったときにも、スムーズにoptionの設定ができます。
1 2 3 4 5 6 7 8 | //options(調整やプラグイン化がしやすいように、変数をまとめておく) var loadingImgUrl = ""; //ローディング画像のURL var loadingImgWidth = 64; //ローディング画像の大きさ var loadingImgFrame = 4; //ローディングアニメーションのフレーム数 var loadingImgFrameSpeed = 1000; //ローディングアニメーションの全フレームが表示される時間(ミリ秒) var loadingImgBgColor = "white"; //ローディング画像の背景色 var imagePadding = 20; //モーダルウィンドウの周りの余白サイズ(px) var fadeSpeed = 750; //モーダルウィンドウを表示するときのアニメーションのスピード(ミリ秒) |
ローディング画像の表示
今回はGIFアニメーションではなく、
下のような画像を用意し、
CSSのbackground-positionで背景画像の表示位置をずらすことで、
アニメーションすることにしました。
手順としては、
- サムネイル画像の大きさとウィンドウ上の位置を取得する
- サムネイル画像上(aタグの末尾)にローディング画像の背景と、ローディング画像を配置
- リンク先の画像が読み込まれるまでアニメーションを表示し、読み込まれたらローディング画像を削除する
という流れです。
まず、クリックされたタイミングで、クリックされたサムネイル画像の大きさとウィンドウ上の位置を取得します。
1 2 3 4 5 6 7 | tgElm.on("click", function(){ /*-- loadingアニメーションに必要な情報取得 --*/ var clickElm = $(this); //クリックされた要素を取得 var imgWidth = clickElm.find("img").width(); //クリックされたサムネイルの画像の幅を取得 var imgHeight = clickElm.find("img").height(); //クリックされたサムネイルの画像の高さを取得 var imgPosX = clickElm.find("img").offset().left; //クリックされたサムネイルの画面内でのY座標を取得 var imgPosY = clickElm.find("img").offset().top; //クリックされたサムネイルの画面内でのX座標を取得 |
そしてその情報をもとに、ローディング画像を設置します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | /*-- loadingアニメーションを表示 --*/ //ローディング画像をサムネイル上に表示するためのCSS設定 if(clickElm.css("position") != "absolute" || clickElm.css("position") != "fixed"){ clickElm.css("position", "relative"); } clickElm.css("display", "inline-block"); clickElm.append('<span class="loadingAnmBg"></span>'); //サムネイル上にローディング画像の背景枠を設置 $(".loadingAnmBg").css({ //ローディング画像背景のCSS設定 "position" : "absolute", "top" : "0", "left" : "0", "width" : imgWidth + "px", "height" : imgHeight + "px", "background-color" : loadingImgBgColor, "opacity" : "0.5" }); clickElm.find(".loadingAnmBg").append('<span class="loadingAnm"></span>');//背景枠内にローディング画像を設置 clickElm.find(".loadingAnm").css({ //ローディング画像のCSS設定 "position" : "absolute", "top" : "50%", "left" : "50%", "width" : loadingImgWidth + "px", "height" : loadingImgWidth + "px", "margin-top" : -loadingImgWidth / 2 + "px", "margin-left" : -loadingImgWidth / 2 + "px", "background-image" : "url(" + loadingImgUrl + ")", "background-repeat" : "no-repeat", "background-position" : "0 0" }); |
さらに、setIntervalを使って、アニメーションを実行します。
1 2 3 4 5 6 7 | /*-- ローディングアニメーションを実行 --*/ clickElm.cnt = 0; //クリックした要素のプロパティとしてカウンターを設置(それぞれのサムネイルで独立させるため) clickElm.timerFn = setInterval(function(){ //同様にタイマーの関数を設置 if(clickElm.cnt >= loadingImgFrame) clickElm.cnt = 0; //ローディングアニメーションのフレーム数に達したら、カウンターをリセット clickElm.find(".loadingAnm").css("background-position", -loadingImgWidth * clickElm.cnt + "px 0"); //背景画像の位置をずらしてアニメーションさせる clickElm.cnt++; },loadingImgFrameSpeed / loadingImgFrame); //タイマーの速度を指定 |
最後に、リンク先の画像が読み込み終わったら、アニメーションを 停止し、削除します。
1 2 3 4 5 6 7 8 9 | $("<img>") //リンク先の画像を読み込み .appendTo("body") .attr("src", clickElm.attr("href")) .load(function(){ /*-- 画像を読み込んだら、ローディングアニメーションを終了 --*/ clearInterval(clickElm.timerFn); $(".loadingAnmBg").remove(); }); |
モーダルウィンドウの表示
いよいよ、 サムネイルから画像が飛び出すようなモーダルウィンドウを表示します。
手順としては
- 必要な情報を取得し、画面いっぱいに画像を拡大したときの大きさを計算
- リンク先の画像を読み込んでbodyの末尾に設置し、CSSでサムネイルと重なるように配置する
- モーダルウィンドウの背景をフェイドインさせながら、画像を画面いっぱいに拡大するアニメーションを表示
という流れになります。
まず準備として、ウィンドウサイズを取得し、画像を拡大したときの大きさを計算します。
リンク先の画像の大きさの取得は、画像が読み込み終わったタイミングになるよう、loadイベントの後で行います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | /*-- モーダルウィンドウの表示に必要な情報取得 --*/ var windowWidth = $(window).width(); //ウィンドウの幅を取得 var windowHeight = $(window).height(); //ウィンドウの高さを取得 /*-- モーダルウィンドウの表示に用いる変数を初期化 --*/ var loadImgWidth = 0; //モーダルウィンドウに表示する画像の元の幅 var loadImgHeight = 0; //モーダルウィンドウに表示する画像の元の高さ var viewWidth = 0; //モーダルウィンドウに表示するときの画像の幅 var viewHeight = 0; //モーダルウィンドウに表示するときの画像の高さ var viewRate = "1"; //モーダルウィンドウに表示する画像の縦横比 /*-- モーダルウィンドウの表示 --*/ $("<img>") //画像の読み込み .load(function(){ loadImgWidth = $(this).width(); //モーダルウィンドウに表示する画像の元の幅を取得 loadImgHeight = $(this).height(); //モーダルウィンドウに表示する画像の元の高さを取得 viewRate = loadImgHeight / loadImgWidth; //モーダルウィンドウに表示する画像の縦横比を算出 /*画面内に画像が収まるように、大きさを調整 */ viewWidth = windowWidth - (imagePadding * 2); viewHeight = viewWidth * viewRate; if(viewHeight > windowHeight - (imagePadding * 2)){ viewHeight = windowHeight - (imagePadding * 2); viewWidth = viewHeight / viewRate; } |
ウィンドウの大きさから最初に設定した余白の大きさを引いた値を最大値として、
幅、高さの順に画像を計算しています。
次に、body末尾に設置し、CSSを調整します。
サムネイル画像の情報はすでにローディング画像の設置のときに取得しているので、
それをつかってCSSを調整します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | /*-- モーダルウィンドウの表示 --*/ $("<img>") //画像の読み込み .appendTo("body") .attr("src", clickElm.attr("href")) .css("display", "none") .load(function(){ $(this).css({ //読み込んだ画像を、サムネイル上に合わせる "display" : "block", "width" : imgWidth + "px", "height" : imgHeight + "px", "position" : "absolute", "top" : imgPosY + "px", "left" : imgPosX + "px", "z-index" : "999" }) |
そして、モーダルウィンドウの背景をフェイドインさせながら、画像を画面いっぱいに拡大するアニメーションを表示します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | $(this).animate({ //画面いっぱいに拡大するアニメーションを表示 "width" : viewWidth + "px", "height" : viewHeight + "px", "top" : (windowHeight - viewHeight)/2 + "px", "left" : (windowWidth - viewWidth)/2 + "px" },fadeSpeed); $(this).before('<div class="bgViewer"></div>'); //モーダルウィンドウの背景を設置 $(".bgViewer").css({ //モーダルウィンドウの背景のCSSを設定 "position" : "fixed", "top" : "0", "left" : "0", "width" : "100%", "height" : "100%", "background-color" : "#000", "opacity" : "0", "z-index" : "990" }) .animate({ //フェイドインしながら背景を表示 "opacity" : "0.5" },fadeSpeed) .click(function(){ //背景をクリックしたら、モーダルウィンドウを閉じる $(".bgViewer, .bgViewer+img").fadeOut(500, function(){ $(this).remove(); }); }); |
背景設定のときに、背景をクリックしたときにモーダルウィンドウを閉じる設定も一緒に行っています。
これで一連の動きができました。
実際のコード全体はこちらです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | $(function(){ /*-- 初期設定 --*/ var tgElm = $("ul li a"); //対象となる要素の指定 $("html, body").css({ //モーダルウィンドウで背景が画面いっぱいに表示されるための準備 "width" : "100%", "height" : "100%" }); //options(プラグイン化しやすいように、変数をまとめておく) var loadingImgUrl = ""; //ローディング画像のURL var loadingImgWidth = 64; //ローディング画像の大きさ var loadingImgFrame = 4; //ローディングアニメーションのフレーム数 var loadingImgFrameSpeed = 1000; //ローディングアニメーションの全フレームが表示される時間(ミリ秒) var loadingImgBgColor = "white"; //ローディング画像の背景色 var imagePadding = 20; //モーダルウィンドウの周りの余白サイズ(px) var fadeSpeed = 750; //モーダルウィンドウを表示するときのアニメーションのスピード(ミリ秒) //ローディング画像のURLの指定がなかったときに既定画像のURLを指定 if(loadingImgUrl == ""){ if(loadingImgBgColor == "white"){ //背景色でwhiteを指定したときは、黒いローディング画像を指定 loadingImgUrl = "images/loading_black.png"; }else{ loadingImgUrl = "images/loading_white.png"; } } /* サムネイルをクリックで動作を開始 */ tgElm.on("click", function(){ /*-- loadingアニメーションに必要な情報取得 --*/ var clickElm = $(this); //クリックされた要素を取得 var imgWidth = clickElm.find("img").width(); //クリックされたサムネイルの画像の幅を取得 var imgHeight = clickElm.find("img").height(); //クリックされたサムネイルの画像の高さを取得 var imgPosX = clickElm.find("img").offset().left; //クリックされたサムネイルの画面内でのY座標を取得 var imgPosY = clickElm.find("img").offset().top; //クリックされたサムネイルの画面内でのX座標を取得 /*-- loadingアニメーションを表示 --*/ //ローディング画像をサムネイル上に表示するためのCSS設定 if(clickElm.css("position") != "absolute" || clickElm.css("position") != "fixed"){ clickElm.css("position", "relative"); } clickElm.css("display", "inline-block"); clickElm.append('<span class="loadingAnmBg"></span>'); //サムネイル上にローディング画像の背景枠を設置 $(".loadingAnmBg").css({ //ローディング画像背景のCSS設定 "position" : "absolute", "top" : "0", "left" : "0", "width" : imgWidth + "px", "height" : imgHeight + "px", "background-color" : loadingImgBgColor, "opacity" : "0.5" }); clickElm.find(".loadingAnmBg").append('<span class="loadingAnm"></span>');//背景枠内にローディング画像を設置 clickElm.find(".loadingAnm").css({ //ローディング画像のCSS設定 "position" : "absolute", "top" : "50%", "left" : "50%", "width" : loadingImgWidth + "px", "height" : loadingImgWidth + "px", "margin-top" : -loadingImgWidth / 2 + "px", "margin-left" : -loadingImgWidth / 2 + "px", "background-image" : "url(" + loadingImgUrl + ")", "background-repeat" : "no-repeat", "background-position" : "0 0" }); /*-- ローディングアニメーションを実行 --*/ clickElm.cnt = 0; //クリックした要素のプロパティとしてカウンターを設置(それぞれのサムネイルで独立させるため) clickElm.timerFn = setInterval(function(){ //同様にタイマーの関数を設置 if(clickElm.cnt >= loadingImgFrame) clickElm.cnt = 0; //ローディングアニメーションのフレーム数に達したら、カウンターをリセット clickElm.find(".loadingAnm").css("background-position", -loadingImgWidth * clickElm.cnt + "px 0"); //背景画像の位置をずらしてアニメーションさせる clickElm.cnt++; },loadingImgFrameSpeed / loadingImgFrame); //タイマーの速度を指定 /*-- モーダルウィンドウの表示に必要な情報取得 --*/ var windowWidth = $(window).width(); //ウィンドウの幅を取得 var windowHeight = $(window).height(); //ウィンドウの高さを取得 /*-- モーダルウィンドウの表示に用いる変数を初期化 --*/ var loadImgWidth = 0; //モーダルウィンドウに表示する画像の元の幅 var loadImgHeight = 0; //モーダルウィンドウに表示する画像の元の高さ var viewWidth = 0; //モーダルウィンドウに表示するときの画像の幅 var viewHeight = 0; //モーダルウィンドウに表示するときの画像の高さ var viewRate = "1"; //モーダルウィンドウに表示する画像の縦横比 /*-- モーダルウィンドウの表示 --*/ $("<img>") //画像の読み込み .appendTo("body") .attr("src", clickElm.attr("href")) .css("display", "none") .load(function(){ loadImgWidth = $(this).width(); //モーダルウィンドウに表示する画像の元の幅を取得 loadImgHeight = $(this).height(); //モーダルウィンドウに表示する画像の元の高さを取得 viewRate = loadImgHeight / loadImgWidth; //モーダルウィンドウに表示する画像の縦横比を算出 /*画面内に画像が収まるように、大きさを調整 */ viewWidth = windowWidth - (imagePadding * 2); viewHeight = viewWidth * viewRate; if(viewHeight > windowHeight - (imagePadding * 2)){ viewHeight = windowHeight - (imagePadding * 2); viewWidth = viewHeight / viewRate; } $(this).css({ //読み込んだ画像を、サムネイル上に合わせる "display" : "block", "width" : imgWidth + "px", "height" : imgHeight + "px", "position" : "absolute", "top" : imgPosY + "px", "left" : imgPosX + "px", "z-index" : "999" }) .animate({ //画面いっぱいに拡大するアニメーションを表示 "width" : viewWidth + "px", "height" : viewHeight + "px", "top" : (windowHeight - viewHeight)/2 + "px", "left" : (windowWidth - viewWidth)/2 + "px" },fadeSpeed); $(this).before('<div class="bgViewer"></div>'); //モーダルウィンドウの背景を設置 $(".bgViewer").css({ //モーダルウィンドウの背景のCSSを設定 "position" : "fixed", "top" : "0", "left" : "0", "width" : "100%", "height" : "100%", "background-color" : "#000", "opacity" : "0", "z-index" : "990" }) .animate({ //フェイドインしながら背景を表示 "opacity" : "0.5" },fadeSpeed) .click(function(){ //背景をクリックしたら、モーダルウィンドウを閉じる $(".bgViewer, .bgViewer+img").fadeOut(500, function(){ $(this).remove(); }); }); /*-- モーダルウィンドウを表示したら、ローディングアニメーションを終了 --*/ clearInterval(clickElm.timerFn); $(".loadingAnmBg").remove(); }); return false; }); }); |
Author Profile
NINOMIYA
Webデザイナー兼コーダー出身のフロントエンド開発者です。 UXデザインやチーム開発の効率化など、勉強中です。
SHARE