jquery カルーセルパネル(スライドパネル)の表示

2014年1月14日

カルーセルパネル(パネルをスライドして1周すると元のパネルに戻る)やスライドパネルを使う際のメモと練習(実用的でないものがほとんど)。

カルーセルパネルの表示(サンプル1)

サンプル1

シンプルなカルーセルパネルを表示する。

  • カルーセル全体を囲む div 要素を配置(id=”slider_wrap”)
  • その内側に「戻る」(slider_prev)と「進む」(slider_next)ボタンを配置
  • パネルを表示する領域の div 要素(id=”slider”)を配置(overflow: hidden に設定)
  • div 要素(id=”slider”)の内側にパネル全体を格納する div 要素(id=”slider_inner”)を配置
  • その内側にパネルを ul li 要素で記述
  • 画像の幅は「150px」、高さは「85px」
  • カルーセルを実現するには最低3つの ul 要素(パネル)が必要

HTML

<div id="slider_wrap">
    <p id="slider_prev"><img src="images/slider-prev.png" alt="prev"></p>
    <p id="slider_next"><img src="images/slider-next.png" alt="next"></p>
    <div id="slider">
        <div id="slider_inner">
            <ul class="panel">
                <li><a href="#"><img src="images/1.jpg" alt=""></a></li>
                <li><a href="#"><img src="images/2.jpg" alt=""></a></li>
                <li><a href="#"><img src="images/3.jpg" alt=""></a></li>
                <li><a href="#"><img src="images/4.jpg" alt=""></a></li>
            </ul>
            ・・・省略・・・
            <ul class="panel">
                <li><a href="#"><img src="images/13.jpg" alt=""></a></li>
                <li><a href="#"><img src="images/14.jpg" alt=""></a></li>
                <li><a href="#"><img src="images/15.jpg" alt=""></a></li>
                <li><a href="#"><img src="images/16.jpg" alt=""></a></li>
            </ul>
        </div><!-- end of #slider_inner --> 
    </div><!-- end of #slider --> 
</div><!-- end of #slider_wrap -->

CSS

パネル全体を格納する div 要素(id=”slider_inner”)の幅を指定する必要があるが、パネルの数を変更できるように、jQuery で計算して指定する。

  • ul 要素などはマージンやパディングをリセットしておくとやりやすい
  • #slider_wrap の幅は、ul.panel の幅にそのパディングを足した値(設定によっては異なる)
  • 図を描いてみるのが一番わかりやすい

CSS

* {  /* 好ましくないが取りあえずマージンとパディングをリセット */
  margin: 0;
  padding: 0;
}
#slider_wrap {
  margin: 20px auto;
  width: 680px;  /* 全体の幅 */
  height: 125px;  /* パネルの高さ + パディング */
  padding: 20px;
  background: #EFEFEF;
  position: relative;  /* 基点とするため相対配置に */
  border: 1px solid #CCC;
}
#slider_prev {
  position: absolute;  /* 絶対配置 */
  top: 65px;
  left: 10px;
  cursor: pointer;
}
#slider_next {
  position: absolute;  /* 絶対配置 */
  top: 65px;
  right: 10px;
  cursor: pointer;
}
#slider {
  width: 100%;
  height: 100%;
  overflow: hidden;  /* はみ出た部分を非表示に */
}
#slider_inner ul.panel {
  width: 640px;
  height: 85px;
  padding: 20px;  /* パネルの幅+パディング = 680px */
  list-style-type: none;
  float: left;
  background: #999;  /* 領域がわかりやすいように色づけ */
}
#slider_inner ul.panel li {
  float: left;
  margin: 0 5px;
  display: inline;  /* li をフロートさせるとIE6 ではずれるのでこの指定で回避 */
}
#slider_inner ul.panel img {
  border: none;
}

jQuery

  • パネル全体を格納する div 要素(id=”slider_inner”)の幅は「表示領域の横幅 X パネル(ul.panel)の数」
  • 最後のパネル(ul.panel:last)を先頭位置に移動(prependTo)
  • div 要素(id=”slider_inner”)を上記で移動した分だけ左方向へずらす
  • クリックイベントを設定
  • 「戻る」と「進む」ボタンはアニメーションの途中でクリックされると計算がずれるので非表示に
  • animate() を使って左側のマージンを変更してスライドさせる
  • コールバックで、初期設定と同様に最後のパネル(ul.panel:last)を先頭位置に移動し、div 要素(id=”slider_inner”)の左側のマージンを元に戻す(★)
  • ボタンを表示する

(注意)CSS の設定によっては「表示領域の横幅」にパディングも含める必要がある。$(‘#slider_wrap’).outerWidth() なども利用できるが、数値で指定した方が確実かもしれない。

但し、その場合パネル全体を格納する div 要素(id=”slider_inner”)の幅の算出にはパディングを含めるがパネルをスライドさせる距離ではパディング分を差し引かなければならなくなる可能性もある。CSS の設定によりこれらの値は変更しなければならない場合もあるので注意する。

jQuery

<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script>
jQuery(function($){
  //表示領域の横幅(CSS の設定によってはパディングも含める必要がある)
  var slider_width = $('#slider_wrap').width();
  var slider_inner$ = $('#slider_inner');
  //パネル全体を格納する div 要素の幅を設定 
  slider_inner$.css('width', slider_width * $('#slider_inner ul.panel').size() + 'px');
  //最後のパネルを先頭位置に移動 
  $('#slider_inner ul.panel:last').prependTo('#slider_inner');
  //移動した分だけ左方向へずらす(★) 
  slider_inner$.css('margin-left', '-' + slider_width + 'px');
  //戻る」と「進む」ボタン
  var prev_next$ = $('#slider_next, #slider_prev');
  
  $('#slider_prev').click(function(){
    prev_next$.hide();
    slider_inner$.stop().animate({
      marginLeft: parseInt(slider_inner$.css('margin-left'), 10) + slider_width + 'px'
    }, 700,
    function(){
      slider_inner$.css('margin-left', '-' + slider_width + 'px');
      $('#slider_inner ul.panel:last').prependTo('#slider_inner');
      prev_next$.show();
    });
  });
  
  $('#slider_next').click(function(){
    prev_next$.hide();
    slider_inner$.stop().animate({
      //「戻る」では加算したが「進む」では減算
      marginLeft: parseInt(slider_inner$.css('margin-left'), 10) - slider_width + 'px'
    }, 700,
    //「戻る」では「prependTo」だが「進む」では「appendTo」
    function(){
      slider_inner$.css('margin-left', '-' + slider_width + 'px');
      $('#slider_inner ul.panel:first').appendTo('#slider_inner');
      prev_next$.show();
    });
  });
});
</script>

自動的にスライドさせる

setInterval を利用して一定間隔(3秒)で自動的にスライドさせる。

カーソルがカルーセルの領域に入ると一時的にスライドを停止させ、ユーザーがクリックできるようにする。
「止める」ボタン(「止める」と「開始」を兼ねる)を追加。

<p id="stop">Stop</p>

CSS

#stop {
  cursor: pointer;
  background: #666;
  color: #FFF;
  border: 1px solid #999;
  width: 50px;
  height: 2em;
  text-align: center;
  line-height: 2em;
}

jQuery に以下を追記。

  • start_carousel():カルーセルを開始。「止める」ボタンの文字を「Stop」に変更。
  • stop_carousel():clearInterval() でカルーセルを中止。「止める」ボタンの文字を「Start」に変更。
  • hover() でその領域にマウスが入ればカルーセルを中断し、マウスアウト時は「止める」ボタンが押されていなければ再開
var timer;
//「止める」ボタンがクリックされたかどうか
var is_stopped = false;
var stop$ = $('#stop');
function start_carousel() {
  timer = setInterval(function(){
    $('#slider_next').click();
  },3000);
  stop$.text('Stop');
  is_stopped = false;
}

function stop_carousel() {
  clearInterval(timer);
  stop$.text('Start');
  is_stopped = true;
}

$('#slider_wrap').hover(function() {
  clearInterval(timer);
},function() {
  //「止める」ボタンがクリックされていない場合のみ再開(マウスアウト)
  if(!is_stopped) {
    start_carousel();
  }    
});

stop$.click(function(){
  if(is_stopped) {
    start_carousel();
  }else{
    stop_carousel();
  }    
});
//自動的に開始
start_carousel();
//念のため(不要?)
$(window).unload(function(){
  window.clearInterval(timer);
});

HTML の構造を変更してみる

サンプル1-2

このサンプルの場合1つのパネルに4つのサムネイルを表示しているが、サムネイルを1つ追加する場合を考えてみる。

最初に表示されるパネルに新しく追加したサムネイルを表示したい場合、全ての li 要素をずらす必要があるので更新が面倒になる可能性がある(数が多ければ多いほど)。

そこで、サムネイルは1つの ul 要素(id=”list”)の中に li 要素と記述して、jQuery でその構造を4つずつ(n 個ずつ)の li 要素を含む ul 要素に変更するようにして、その後でカルーセルパネル(スライドパネル)の表示の記述を行えば、前述のサンプルと同じ結果になり更新も簡単になる(と思う)。

HTML

<div id="slider_wrap">
    <div id="slider">
        <div id="slider_inner">
        <ul id="list">
           <li><a href="#"><img src="images/1.jpg" alt=""></a></li>
           <li><a href="#"><img src="images/2.jpg" alt=""></a></li>
           <li><a href="#"><img src="images/3.jpg" alt=""></a></li>
           <li><a href="#"><img src="images/4.jpg" alt=""></a></li>
                 ・・・省略・・・
           <li><a href="#"><img src="images/9.jpg" alt=""></a></li>
           <li><a href="#"><img src="images/10.jpg" alt=""></a></li>
           <li><a href="#"><img src="images/11.jpg" alt=""></a></li>
           <li><a href="#"><img src="images/12.jpg" alt=""></a></li>
        </ul>
        </div><!--end of #slider_inner-->
    </div><!--end of #slider-->
</div><!--end of #slider_wrap-->

サムネイルの数(list_length)がパネルに表示する数(n)で割り切れれば簡単だが、そうでない場合を考慮しないとならない。

サムネイルの数(list_length)をパネルに表示する数(n)で割った余りが、最後のパネルに表示されるサムネイルの数なので、最後のパネルの余白の数は「n – list_length % n」になり、その分は <li></li> として表示するようにする。

パネルの数を算出「Math.ceil(list_length / n)」して、パネルごとに ul 要素(ul class=”panel”)を生成しそれに li 要素を移していく。

jQuery

jQuery(function($){
  
  function reform_li(n) {
    var list$ = $('ul#list li');
    var list_length = list$.length;
    //余白の数
    var offset_li = n - list_length % n;
    if(list_length % n === 0) { offset_li = 0;}
    var is_offset = true;
    if(offset_li === 0) {is_offset = false; }
    //パネル(行)の数
    var list_row_count = Math.ceil(list_length / n);
    var ul_panel;
    var current_list_length;
    for(var i = 0; i < list_row_count; i ++) {
      ul_panel = $('<ul class="panel"></ul>').prependTo('#slider_inner');
      current_list_length = $('ul#list li').length + offset_li;    
      for(var j = current_list_length - 1; j >= current_list_length - n; j--){
        if(is_offset) {
          ul_panel.prepend($('<li></li>'));
          offset_li --;
          if(offset_li === 0)  {is_offset = false; }
        }else{
          ul_panel.prepend($('ul#list li').eq(j));
        }    
      }
    }
    $('ul#list').remove();
  }
});

パネルの数を表す画像を表示(サンプル2)

サンプル2

パネルの数を表す画像(slider-icon.png, slider-icon-selected.png)を用意
それらを表示する領域の div 要素(id=”icon”)を追加

<div id="slider_wrap">
    <p id="slider_prev"><img src="images/slider-prev.png" alt="prev"></p>
    <p id="slider_next"><img src="images/slider-next.png" alt="next"></p>
    <div id="slider">
        <div id="slider_inner">
            <ul class="panel">
                <li><a href="#"><img src="images/1.jpg" alt=""></a></li>
                <li><a href="#"><img src="images/2.jpg" alt=""></a></li>
                <li><a href="#"><img src="images/3.jpg" alt=""></a></li>
                <li><a href="#"><img src="images/4.jpg" alt=""></a></li>
            </ul>
            ・・・省略・・・
            <ul class="panel">
                <li><a href="#"><img src="images/13.jpg" alt=""></a></li>
                <li><a href="#"><img src="images/14.jpg" alt=""></a></li>
                <li><a href="#"><img src="images/15.jpg" alt=""></a></li>
                <li><a href="#"><img src="images/16.jpg" alt=""></a></li>
            </ul>
        </div><!-- end of #slider_inner --> 
    </div><!-- end of #slider -->
    <!-- 以下を追加--> 
    <div id="icon"><a href="#"><img src="images/slider-icon.png" height="14" width="14" alt= ""></a></div>
</div><!-- end of #slider_wrap -->

CSS

パネルの数を表す画像の領域とその中のリンク要素の CSS を以下のように設定

#icon {
  padding-top: 10px;
  width: 30px;
  margin: 0 auto;
}

#icon a {
  padding: 8px;
  
}

jQuery

  • パネルの数を表す画像は HTML に1つだけ記述してあるのでパネルの数分追加
  • 現在表示されているパネルを表す画像を「slider-icon-selected.png」に設定
  • パネルの数を表す画像のクリックイベントを設定
  • クリックイベントの中で遅延時間を調整できるようにするため、「進む」「戻る」ボタンをクリックした際の処理を関数にしておく
  • また、位置がずれないようにするためアニメーション中はパネルの数を表す画像をクリックしても何もしないようにする。
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script>
jQuery(function($){
  //パネル(ul.panel)の数を「panel_count」に格納  
  var panel_count = $('#slider_inner ul.panel').length;
  //パネルの数を表す画像の領域の幅の初期値を「icon_width」に格納
  var icon_width = $('#icon').width();
  //パネルの数を表す画像は HTML に1つだけ記述してあるのでパネルの数分生成
  if(panel_count > 1) {
    for(var i = 0; i < panel_count -1 ; i++) {
      $('#icon a:first').clone().appendTo('#icon');
    }
    //「panel_count」を使ってパネルの数を表す画像の領域の幅を設定
    $('#icon').css('width', icon_width * panel_count);    
  }
  //パネルの数を表す画像のラップ集合を「icon_imgs」に格納
  var icon_imgs = $('#icon img');
  //パネルの数を表す画像のリンクのラップ集合を「icon_links」に格納
  var icon_links = $('#icon a');
  //現在表示されているパネルのインデックスを「current_panel」に格納し、初期値「0」を設定
  var current_panel = 0;
  //現在表示されているパネルを表す画像を「slider-icon-selected.png」に設定
  $(icon_imgs.get(current_panel)).attr('src', "images/slider-icon-selected.png");
  
  //現在表示されているパネルを表す画像のクリックイベント
  icon_links.click(function(){
    //画像をスライドさせるアニメーション中の場合は何もしない(位置がずれるため)
    if(is_animate) return false;
    var this$ = $(this);
    //クリックされたリンクのインデックスを「icon_index」に格納
    var icon_index = icon_links.index(this$);
    //「icon_imgs」の全ての要素を調査して、現在表示されているパネルのインデックスを取得して「current_icon_index」に格納
    var current_icon_index;
    icon_imgs.each(function(n) {
            if($(this).attr('src') == "images/slider-icon-selected.png") {
        current_icon_index = n;
      }
        });
    //クリックされたリンクのインデックス「icon_index」と現在表示されているパネルのインデックス「current_icon_index」を比較
    if(icon_index < current_icon_index){
      //「icon_index」が小さければ、setInterval を使って click_prev() を「current_icon_index – icon_index」回実行
      var count = 0;
      var timer = window.setInterval(function(){ 
        if(count < current_icon_index - icon_index) {
          click_prev(400);
          count++;
        }else{
          clearInterval(timer);
        }
        //setInterval の遅延時間は click_prev() のアニメーションの時間(400)より大きく設定
       }, 500);    
    }else{
      var count = 0;
      var timer = window.setInterval(function(){ 
        if(count < icon_index -current_icon_index ) {
          click_next(400);
          count++;
        }else{
          clearInterval(timer);
        }    
       }, 500);      
    }  
    return false;    
  });
  
  var slider_width = $('#slider_wrap').width();
  var slider_inner$ = $('#slider_inner');
  slider_inner$.css('width', slider_width * $('#slider_inner ul.panel').size() + 'px');
  $('#slider_inner ul.panel:last').prependTo('#slider_inner');
  slider_inner$.css('margin-left', '-' + slider_width + 'px');
  var prev_next$ = $('#slider_next, #slider_prev');
  
  var is_animate = false;
  //「戻る」ボタンをクリックした際の処理を関数にする
  //パネルを表す画像のクリックイベントの中で遅延時間を調整できるようにする
  function click_prev(speed) {
    is_animate = true;
    prev_next$.hide();
    slider_inner$.stop().animate({
      marginLeft: parseInt(slider_inner$.css('margin-left'), 10) + slider_width + 'px'
    }, speed,
    function(){
      slider_inner$.css('margin-left', '-' + slider_width + 'px');
      $('#slider_inner ul.panel:last').prependTo('#slider_inner');
      prev_next$.show();
      //現在表示されているパネルのインデックスを更新
      if(current_panel > 0 ) {
        current_panel --;
      }else{
        current_panel = panel_count -1;
      }
      icon_imgs.attr('src', "images/slider-icon.png");
      //現在表示されているパネルに対応する画像を変更
      $(icon_imgs.get(current_panel)).attr('src', "images/slider-icon-selected.png");
      is_animate = false;
    });
  }
  
  //「進む」ボタンをクリックした際の処理を関数にする
  //パネルを表す画像のクリックイベントの中で遅延時間を調整できるようにする
  function click_next(speed) {
    is_animate = true;
    prev_next$.hide();
    slider_inner$.stop().animate({
      marginLeft: parseInt(slider_inner$.css('margin-left'), 10) - slider_width + 'px'
    }, speed,
    function(){
      slider_inner$.css('margin-left', '-' + slider_width + 'px');
      $('#slider_inner ul.panel:first').appendTo('#slider_inner');
      prev_next$.show();
      //現在表示されているパネルのインデックスを更新
      current_panel = (current_panel + 1) % panel_count;
      icon_imgs.attr('src', "images/slider-icon.png");
      //現在表示されているパネルに対応する画像を変更
      $(icon_imgs.get(current_panel)).attr('src', "images/slider-icon-selected.png");
      is_animate = false;
    });
  }
  
  $('#slider_prev').click(function(){
    click_prev(700);
  });
  
  $('#slider_next').click(function(){
    click_next(700);
  });

});
</script>

少し変更してみる

前述のサンプルでは、パネルの数を表す画像をクリックした場合、少し動きがぎこちないので以下のように変更してみる。

サンプル2-1

  • パネルを動かすアニメーションの関数「slide_panel(direction, repeat, speed)」を作成
  • direction:「prev」方向か「next」方向(テキスト)
  • repeat:繰り返す回数(1以上の整数)
  • speed:アニメーションの時間(ミリ秒)
  • 再帰的にこの関数を呼び出し、その際に「repeat」の値を1ずつ減じていく
  • 前述のサンプルでは、一番最初から一番最後に移動する場合など一定方向にしか動かなかったが、近いほうを判定してそちらへ動かす(返ってわかりずらい?)
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script>
jQuery(function($){
  //パネル(ul.panel)の数を「panel_count」に格納  
  var panel_count = $('#slider_inner ul.panel').length;
  //パネルの数を表す画像の領域の幅の初期値を「icon_width」に格納
  var icon_width = $('#icon').width();
  //パネルの数を表す画像は HTML に1つだけ記述してあるのでパネルの数分生成
  if(panel_count > 1) {
    for(var i = 0; i < panel_count -1 ; i++) {
      $('#icon a:first').clone().appendTo('#icon');
    }
    //「panel_count」を使ってパネルの数を表す画像の領域の幅を設定
    $('#icon').css('width', icon_width * panel_count);    
  }
  //パネルの数を表す画像のラップ集合を「icon_imgs」に格納
  var icon_imgs = $('#icon img');
  //パネルの数を表す画像のリンクのラップ集合を「icon_links」に格納
  var icon_links = $('#icon a');
  //現在表示されているパネルのインデックスを「current_panel」に格納し、初期値「0」を設定
  var current_panel = 0;
  //現在表示されているパネルを表す画像を「slider-icon-selected.png」に設定
  $(icon_imgs.get(current_panel)).attr('src', "images/slider-icon-selected.png");
  
  var slider_width = $('#slider_wrap').width();
  var slider_inner$ = $('#slider_inner');
  slider_inner$.css('width', slider_width * $('#slider_inner ul.panel').size() + 'px');
  $('#slider_inner ul.panel:last').prependTo('#slider_inner');
  slider_inner$.css('margin-left', '-' + slider_width + 'px');
  var prev_next$ = $('#slider_next, #slider_prev');
    
  //現在表示されているパネルに対応する画像を変更とボタンを表示する処理
  function setup() {
    //パネルに対応する画像を全て同じ画像にする(リセット)
    icon_imgs.attr('src', "images/slider-icon.png");
    //現在表示されているパネルに対応する画像だけを変更
    $(icon_imgs.get(current_panel)).attr('src', "images/slider-icon-selected.png");    
  }
  
  var default_speed = 700;
  //アニメーション中かどうかのフラグ
  var is_animate = false;
  var count = 0;
  function slide_panel(direction, repeat, speed) {    
    is_animate = true;
    if(speed) { var speed = speed; }else{ var speed = default_speed; }
    if(direction == "prev") {
      var margin_left =  parseInt(slider_inner$.css('margin-left'), 10) + slider_width + 'px';
    }else{
      var margin_left =  parseInt(slider_inner$.css('margin-left'), 10) - slider_width + 'px';
    }    
    prev_next$.hide();
    //パネルをスライドさせる
    slider_inner$.stop().animate({
      marginLeft: margin_left
    }, speed,
    function(){
      slider_inner$.css('margin-left', '-' + slider_width + 'px');
      if(direction == "prev") {
        //最後のパネル(ul.panel:last)を先頭位置に移動(prependTo)
        $('#slider_inner ul.panel:last').prependTo('#slider_inner');
        //現在表示されているパネルのインデックスを更新
        current_panel = (panel_count + current_panel -1) % panel_count;
      }else{
        //先頭のパネル(ul.panel:first)を最後に移動(appendTo)
        $('#slider_inner ul.panel:first').appendTo('#slider_inner');
        //インデックスを更新
        current_panel = (current_panel + 1) % panel_count;
      }
      setup();
      prev_next$.show();
      
      if(repeat == 1) {
        is_animate = false;
        count = 0;
      }else if(repeat == count) {
        is_animate = false;
        count = 0;
      }
      //繰り返し(再帰)
      if(repeat > 1) {
        slide_panel(direction, repeat -1, speed);
        count ++;
      }
    });  
  }
  
  $('#slider_prev').click(function(){
    slide_panel('prev', 1, 500); 
  });
  
  $('#slider_next').click(function(){
    slide_panel('next', 1, 500) 
  });
  
  //現在表示されているパネルを表す画像のクリックイベント
  icon_links.click(function(){
    //画像をスライドさせるアニメーション中の場合は何もしない(位置がずれるため)
    if(is_animate) return false;
    var this$ = $(this);
    //クリックされたリンクのインデックスを「icon_index」に格納
    var icon_index = icon_links.index(this$);
    //「icon_imgs」の全ての要素を調査して、現在表示されているパネルのインデックスを取得して「current_icon_index」に格納
    var current_icon_index;
    icon_imgs.each(function(n) {
            if($(this).attr('src') == "images/slider-icon-selected.png") {
        current_icon_index = n;
      }
        });
    //インデックスの差分(絶対値)を取得
    var delta = Math.abs(icon_index - current_icon_index);
    //逆方向への移動距離を算出するための値
    var alpha = panel_count - delta;  
    //クリックされたリンクのインデックス「icon_index」と現在表示されているパネルのインデックス「current_icon_index」を比較
    if(icon_index < current_icon_index){      
      //差分が写真の数の半分より大きい場合(どちら側へ移動するかを決めるため)
      if(delta > panel_count / 2) {
        slide_panel('next', alpha, 800);        
      }else{
        slide_panel('prev', delta, 800);        
      }      
    }else{
      if(delta > panel_count / 2) {
        slide_panel('prev', alpha, 800);
      }else{
        slide_panel('next', delta, 800);
      }
    }  
    return false;    
  });

});
</script>

スライドショーを追加

カルーセルパネルのサムネイル画像をクリックすると、それに対応するメインの画像を表示するようにする。

サンプル2-2

  • カルーセルパネルのサムネイル画像のフォルダ:images/thumbnails/
  • メインの画像(680 x 383)のフォルダ:images/photos/
  • 画像名は同じものにする

メインの画像を表示する領域(id=”main_photo”)を追加。

HTML

<div id="main_photo">
    <img src="images/photos/P1000812.jpg" alt="">
</div>

#main_photo 及びその中の img 要素はスライドショーで使いやすいように設定。

「overflow: hidden」はメインの画像をスライドで表示する場合に必要。

CSS

#main_photo {
  position: relative;
  margin: 0 auto;
  width: 680px;
  height: 383px;
  border: 3px solid #CCC;
  overflow: hidden;
}

#main_photo img {
  position: absolute;
}

クロスフェードで表示

  • クリックされたリンクの中の画像要素を取得
  • src 属性を取得して「thumbnails」を「photos」に置換
  • 必要であれば alt など他の属性も取得
  • 上記で取得した情報を元に img 要素を生成し、before() を使ってメイン画像(#main_photo img)の前に img 要素を挿入
  • メイン画像(#main_photo img)は「position: absolute」を指定しているので、2つの画像は重なった状態になっているので、元のメインの画像を fadeOut() で非表示にする
  • 元の画像は不要なのでコールバックの中で remove() を使って削除
$('.panel li a').click(function() {
    var img$ = $(this).find('img');
    var src = img$.attr('src').replace(/thumbnails/, 'photos');
    var alt = img$.attr('alt');
    $('#main_photo img').before('<img src="' + src + '" alt="' + alt + '">');
    $('#main_photo img:last').fadeOut(400, function() {
      $(this).remove();
    });
    return false;
  });

スライドさせて表示

クロスフェードではなく、メインの画像をスライドさせて表示する例。

サンプル2-3

基本的にはクロスフェードと同じ。fadeOut() の代わりに animate() でスライドさせる。

$('.panel li a').click(function() {
    var img$ = $(this).find('img');
    var src = img$.attr('src').replace(/thumbnails/, 'photos');
    var alt = img$.attr('alt');
    $('#main_photo img').before('<img src="' + src + '" alt="' + alt + '">');
    $('#main_photo img:last').stop().animate({
      marginLeft: '-680px'
    }, 600, function(){
      $(this).remove();
    });
    return false;
  });

サンプル2-3では、元の画像がスライドして、その下に新しい画像が表示されるが、以下は新しい画像がスライドして上に表示される例。

サンプル2-4

  • 画像要素を生成して、位置(left)を指定してメイン画像を表示する領域(#main_photo)の外側に設定
  • insertAfter() を使ってメイン画像(#main_photo img)の直後に追加して animate() でスライド
  • 元の画像(この場合は’#main_photo img:first’)を削除
$('.panel li a').click(function() {
    var img$ = $(this).find('img');
    var src = img$.attr('src').replace(/thumbnails/, 'photos');
    var alt = img$.attr('alt');    
    var new_img$ = $('<img src="' + src + '" alt="' + alt + '">').css('left', '680px');
    new_img$.insertAfter('#main_photo img').animate({
      left: 0 
    }, 600, function() {
      $('#main_photo img:first').remove()
    });
    return false;
  });

画像1枚分スライドさせる(サンプル3)

パネルをスライドさせるのではなく、画像1枚分スライドさせる場合。

  • 自動的にスライドを開始。
  • 「停止」ボタンをクリックするとスライドを停止。
  • また、マウスオーバーした場合もスライドを停止して、「戻る」「進む」ボタンを表示

サンプル3

  • 画像のリストの ul 要素に「id=”photo_list”」を設定
  • カルーセルを実現するにはこの場合、最低6つの画像が必要

HTML

<div id="slider_wrap">
    <p id="slider_prev"><img src="images/slider-prev.png" height="30" width="20" alt="previous"></p>
    <p id="slider_next"><img src="images/slider-next.png" height="30" width="20" alt="next"></p>
    <div id="slider">
        <div id="slider_inner">
            <ul id="photo_list">
                <li><a href="#"><img src="images/1.jpg" alt=""></a></li>
                <li><a href="#"><img src="images/2.jpg" alt=""></a></li>
                <li><a href="#"><img src="images/3.jpg" alt=""></a></li>
                <li><a href="#"><img src="images/4.jpg" alt=""></a></li>
                ・・・省略・・・
                <li><a href="#"><img src="images/10.jpg" alt=""></a></li>
                <li><a href="#"><img src="images/11.jpg" alt=""></a></li>
                <li><a href="#"><img src="images/12.jpg" alt=""></a></li>
            </ul>
        </div><!-- end of #slider_inner --> 
    </div><!-- end of #slider --> 
</div><!-- end of #slider_wrap --> 
<p id="stop">Stop</p>

CSS

  • ul 要素は1つなので id を指定(#photo_list)し、関連する要素の指定も変更
  • ul 要素の幅の指定を削除
  • 前のサンプルのままでは、位置などがうまく調整できないのでそれぞれの要素の幅やマージン、パディング、位置などを変更

CSS

#slider_wrap {
  margin: 20px auto;
  width: 700px;  /* 変更 */
  height: 125px;
  padding: 20px;
  background: #EFEFEF;
  position: relative;
  border: 1px solid #CCC;
}
#slider_prev {
  position: absolute;
  top: 65px;
  left: -10px;  /* 変更 */
  cursor: pointer;
}
#slider_next {
  position: absolute;
  top: 65px;
  right: -10px;  /* 変更 */
  cursor: pointer;
}
#slider {
  width: 100%;
  height: 100%;
  overflow: hidden;
}
#photo_list {
  /*width: 640px;  幅は指定しない*/
  height: 85px;
  padding: 20px 10px;  /* 変更 */
  list-style-type: none;
  float: left;
  background: #999;
}
#photo_list li {
  float: left;
  margin: 0 10px;  /* 変更 */
  display: inline;
}

#photo_list img {
  border: none;
}
#stop {
  cursor: pointer;
  background: #666;
  color: #FFF;
  border: 1px solid #999;
  width: 50px;
  height: 2em;
  text-align: center;
  line-height: 2em;
  margin-left: 40px;
}

jQuery

  1. #slider_inner の幅は「 li 要素の幅(マージンを含む) X その個数」と ul 要素のパディングの合計
  2. 最後の画像(#photo_list li:last)を ul 要素の先頭位置に移動(prependTo)
  3. div 要素(id=”slider_inner”)を上記で移動した分だけ左方向へずらす
  4. クリックイベントを設定
  5. 前のサンプルとの違いはスライドさせる量を「パネルの幅」ではなく「画像1まい分」
  6. 自動的にスタートするように設定
  7. 「戻る」と「進む」ボタンは自動的にカルーセルが動いているときは非表示にして、マウスオーバーした時とカルーセルを停止したときに表示

jQuery

<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script>
jQuery(function($){
  
  var photo_list$ = $('#photo_list');
  var li$ = $('#photo_list li');
  var li_count = li$.length;
  var li_width = li$.width() + parseInt(li$.css('margin-left'), 10) + parseInt(li$.css('margin-right'), 10);
  var ul_padding = parseInt(photo_list$.css('padding-left') , 10) + parseInt(photo_list$.css('padding-right') , 10);
  var slider_inner$ = $('#slider_inner');
  //#slider_inner の幅は「 li 要素の幅(マージンを含む) X その個数」と ul 要素のパディングの合計
  slider_inner$.css('width', (li_width * li_count + ul_padding) + 'px');
  //最後の画像(#photo_list li:last)を ul 要素の先頭位置に移動(prependTo)
  $('#photo_list li:last').prependTo(photo_list$);
  //slider_inner を上記で移動した分だけ左方向へずらす
  slider_inner$.css('margin-left', '-' + li_width + 'px');  
  
  $('#slider_prev').click(function(){
    slider_inner$.stop().animate({
      marginLeft: parseInt(slider_inner$.css('margin-left'), 10) + li_width + 'px'
    }, 500,
    function(){
      slider_inner$.css('margin-left', '-' + li_width + 'px');
      $('#photo_list li:last').prependTo(photo_list$);
    });
  });
  
  $('#slider_next').click(function(){
    slider_inner$.stop().animate({
      marginLeft: parseInt(slider_inner$.css('margin-left'), 10) - li_width + 'px'
    }, 500,
    function(){
      slider_inner$.css('margin-left', '-' + li_width + 'px');
      $('#photo_list li:first').appendTo(photo_list$);
    });
  });
  
  var timer;
  var is_stopped = false;
  var stop$ = $('#stop');
  var next_prev$ = $('#slider_next, #slider_prev');
  function start_carousel() {
    timer = setInterval(function(){
      $('#slider_next').click();
    },1500);
    stop$.text('Stop');
    is_stopped = false;
  }
  
  function stop_carousel() {
    clearInterval(timer);
    stop$.text('Start');
    is_stopped = true;
  }
  
  $('#slider_wrap').hover(function() {
    clearInterval(timer);
    next_prev$.show();
  },function() {
    if(!is_stopped) {
      start_carousel();
      next_prev$.hide();  
    }      
  });
  
  stop$.click(function(){
    if(is_stopped) {
      start_carousel();
      next_prev$.hide();
    }else{
      stop_carousel();
      next_prev$.show();
    }    
  });
  //「戻る」と「進む」ボタンは非表示に
  next_prev$.hide();
  //自動的にスタートするように設定
  start_carousel();  
  //念のため(不要?)
  $(window).unload(function(){
    window.clearInterval(timer);
  });
});
</script>

パネルの構造を保持する場合(サンプル3-2)

前述(サンプル3)の場合、1つの ul 要素の中に全てのサムネイル画像を配置したが、何らかの理由で「サンプル1」のようなパネルの構造を使う場合。

サンプル3-2

HTML と CSS はサンプル1とほぼ同じ。

  • パネルをサムネイルの幅だけ動かす関数を作成
  • 現在表示されているパネルの左端のサムネイルのインデックスを「cell_position」に格納
  • サムネイルの幅分移動させた回数を利用した値を「pos」に格納
  • 「cell_position」と「pos」の値により、パネルを移動するかを判定

例えば、「進む(Next)」の方向へ1つ移動した場合は「cell_position」は 1、「pos」は 1。
この時「戻る(Prev)」の方向へ1つ移動すると「cell_position」は 0、「pos」は 0 になるが、この場合はパネルの移動を行わない。「pos」の値が「-4 」または「4 」の場合のみ、パネルの移動を行う。

jQuery

<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script>
jQuery(function($){
  
  //表示領域の横幅 
  var slider_width = $('#slider_wrap').width() ;
  var slider_inner$ = $('#slider_inner');
  var panel$ = $('#slider_inner ul.panel');
  var panel_size = panel$.size();
  //パネル全体を格納する div 要素の幅を設定 
  slider_inner$.css('width', slider_width * panel_size + 'px');
  //最後のパネルを先頭位置に移動 
  $('#slider_inner ul.panel:last').prependTo('#slider_inner');
  //移動した分だけ左方向へずらす 
  slider_inner$.css('margin-left', '-' + slider_width + 'px');
  //戻る」と「進む」ボタン
  var prev_next$ = $('#slider_next, #slider_prev');
  //サムネイルの横幅  
  var cell$ = $('ul.panel li');
  var cell_width = cell$.width() + parseInt(cell$.css('margin-left'), 10) * 2;  
  //パネル1枚に表示されているサムネイルの数
  var cell_per_panel = $('ul.panel:first li').length;
  
  //パネルの左端のサムネイルのインデックス
  var cell_position = 0;
  //表示されているパネルの移動量(パネルを移動させるかを判定するために使用)
  var pos = 0;
  //パネルをサムネイルの幅だけ動かす関数
  function move_cell(direction) {
    prev_next$.hide();
    if(direction == 'prev') {
      //パネルをサムネイルの幅だけ動かす
      slider_inner$.stop().animate({
        marginLeft: parseInt(slider_inner$.css('margin-left'), 10) + cell_width + 'px'
      }, 700,
      function(){
        cell_position = (cell_position - 1 + cell_per_panel) % cell_per_panel;
        pos --;
        console.log('cell: ' + cell_position + ' pos: ' + pos);
        if(cell_position == 0 && pos == -4 ) {
          //パネルの位置を調整する
          reset_panel_position(direction);
        }
        prev_next$.show();
      });
    }else{
      slider_inner$.stop().animate({
        marginLeft: parseInt(slider_inner$.css('margin-left'), 10) - cell_width + 'px'
      }, 700,
      function(){
        cell_position = (cell_position + 1) % cell_per_panel;
        pos ++;
        console.log('cell: ' + cell_position + ' pos: ' + pos);
        if(cell_position == 0 && pos == 4 ) {
          reset_panel_position(direction);
        }
        prev_next$.show();
      });
    }    
  }
  
  //パネルの位置を調整する関数
  function reset_panel_position(direction) {
    if(direction == 'prev'){
      //左マージンをリセット
      slider_inner$.css('margin-left', '-' + slider_width + 'px');
      //最後のパネルを先頭へ移動
      $('#slider_inner ul.panel:last').prependTo('#slider_inner');
    }else{
      //左マージンをリセット
      slider_inner$.css('margin-left', '-' + slider_width + 'px');
      //先頭のパネルを最後へ移動
      $('#slider_inner ul.panel:first').appendTo('#slider_inner');
    }
    //pos をリセット
    pos = 0;
  }
  
  $('#slider_prev').click(function(){
    move_cell('prev') ;
  });
  
  $('#slider_next').click(function(){
    move_cell('next') ;
  });
  
  var timer;
  var is_stopped = false;
  var next_prev$ = $('#slider_next, #slider_prev');
  function start_carousel() {
    timer = setInterval(function(){
      $('#slider_next').click();
    },1500);
    $('#stop').text('Stop');
    is_stopped = false;
    prev_next$.hide();
  }
  
  function stop_carousel() {
    clearInterval(timer);
    $('#stop').text('Start');
    is_stopped = true;
    prev_next$.show();
  }
  
  $('#slider_wrap').hover(function() {
    clearInterval(timer);
    next_prev$.show();
  },function() {
    if(!is_stopped) {
      start_carousel();
      next_prev$.hide();  
    }      
  });
  
  $('#stop').click(function(){
    if(is_stopped) {
      start_carousel();
    }else{
      stop_carousel();      
    }    
  });
  prev_next$.hide();
  start_carousel();
  
  $(window).unload(function(){
    window.clearInterval(timer);
  });
});
</script>

パネルをスライドする操作を追加(サンプル3-3)

前述(サンプル3-2)に、パネルをスライドする操作を追加してみる。

サンプル3-3

  • 「停止ボタン」をクリックすると、パネルをスライドさせるリンクを表示。
  • パネルをスライドする関数「slide_panel()」を追加。
  • 表示されているサムネイルの位置がパネルの先頭でない場合は、パネルの先頭に移動。
  • 表示されているサムネイルの位置がパネルの先頭の場合は、パネルをスライド。

HTML では以下を追加。

<div id="control">
    <p id="panel_prev">&lt;&lt;</p>
    <p id="stop">Stop</p>
    <p id="panel_next">&gt;&gt;</p></div>
</div>

CSS では以下を追加。

#control {
  width: 100%;
  position: relative;
}

#panel_prev, #panel_next {
  cursor: pointer;
  background: #CCC;
  color: #666;
  border: 1px solid #999;
  width: 50px;
  height: 2em;
  text-align: center;
  line-height: 2em;
}

#panel_prev {
  position: absolute;
  left: 30px;
  top: 0;
  
}

#panel_next {
  position: absolute;
  right: 30px;
  top: 0;
}

jQuery

<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script>
jQuery(function($){
  
  //表示領域の横幅 
  var slider_width = $('#slider_wrap').width() ;
  var slider_inner$ = $('#slider_inner');
  var panel$ = $('#slider_inner ul.panel');
  var panel_size = panel$.size();
  //パネル全体を格納する div 要素の幅を設定 
  slider_inner$.css('width', slider_width * panel_size + 'px');
  //最後のパネルを先頭位置に移動 
  $('#slider_inner ul.panel:last').prependTo('#slider_inner');
  //移動した分だけ左方向へずらす 
  slider_inner$.css('margin-left', '-' + slider_width + 'px');
  //戻る」と「進む」ボタン
  var prev_next$ = $('#slider_next, #slider_prev');
  //サムネイルの横幅  
  var cell$ = $('ul.panel li');
  var cell_width = cell$.width() + parseInt(cell$.css('margin-left'), 10) * 2;  
  //パネル1枚に表示されているサムネイルの数
  var cell_per_panel = $('ul.panel:first li').length;
  
  var panel_prev_next$ = $('#panel_prev, #panel_next');
  
  function hide_control() {
    prev_next$.hide();
    panel_prev_next$.hide();
  }
  
  function show_control() {
    prev_next$.show();
    panel_prev_next$.show();
  }
    
  var cell_position = 0;
  var pos = 0;
  function move_cell(direction) {
    prev_next$.hide();
    if(direction == 'prev') {
      slider_inner$.stop().animate({
        marginLeft: parseInt(slider_inner$.css('margin-left'), 10) + cell_width + 'px'
      }, 700,
      function(){
        cell_position = (cell_position - 1 + cell_per_panel) % cell_per_panel;
        pos --;
        console.log('pos : ' + pos);
        if(cell_position == 0 && pos == -4 ) {
          reset_panel_position(direction);
        }
        prev_next$.show();
      });
    }else{
      slider_inner$.stop().animate({
        marginLeft: parseInt(slider_inner$.css('margin-left'), 10) - cell_width + 'px'
      }, 700,
      function(){
        cell_position = (cell_position + 1) % cell_per_panel;
        pos ++;
        console.log('pos : ' + pos);
        if(cell_position == 0 && pos == 4 ) {
          reset_panel_position(direction);
        }
        prev_next$.show();
      });
    }    
  }
  
  //パネルの位置を調整する関数
  function reset_panel_position(direction) {
    if(direction == 'prev'){
      //左マージンをリセット
      slider_inner$.css('margin-left', '-' + slider_width + 'px');
      //最後のパネルを先頭へ移動
      $('#slider_inner ul.panel:last').prependTo('#slider_inner');
    }else{
      //左マージンをリセット
      slider_inner$.css('margin-left', '-' + slider_width + 'px');
      //先頭のパネルを最後へ移動
      $('#slider_inner ul.panel:first').appendTo('#slider_inner');
    }
    //pos をリセット
    pos = 0;
    console.log('**Reset_Panel** pos: ' + pos);
  }
  
  //パネルをスライドさせる関数
  function slide_panel(direction) {
    hide_control()
    if(direction == 'prev') {    
      if(cell_position != 0) {
        slider_inner$.stop().animate({
          marginLeft: parseInt(slider_inner$.css('margin-left'), 10) + cell_width * cell_position + 'px'
        }, 600,
        function(){
          cell_position = 0;
          //pos の値が 0 以下の場合はパネルの位置を移動
          if(pos <= 0) {
            reset_panel_position(direction);
          }
          //pos の値が 0 より大きい場合はパネルの位置はそのままで、pos のみリセット
          pos = 0;
          show_control();
        });
      }else{
        slider_inner$.stop().animate({
          marginLeft: parseInt(slider_inner$.css('margin-left'), 10) + slider_width + 'px'
        }, 700,
        function(){
          reset_panel_position(direction);
          show_control();
        });
      }      
    }else{
      if(cell_position != 0) {
        slider_inner$.stop().animate({
          marginLeft: parseInt(slider_inner$.css('margin-left'), 10) - cell_width * (cell_per_panel - cell_position) + 'px'
        }, 600,
        function(){
          cell_position = 0;
          //pos の値が 0 以上の場合はパネルの位置を移動
          if(pos >= 0) {
            reset_panel_position(direction);
          }
          //pos の値が 0 未満の場合はパネルの位置はそのままで、pos のみリセット
          pos = 0;
          show_control();
        });  
      }else{
        slider_inner$.stop().animate({
          marginLeft: parseInt(slider_inner$.css('margin-left'), 10) - slider_width + 'px'
        }, 700,
        function(){
          reset_panel_position(direction);
          show_control();
        });
      }    
    }
  }
  
  $('#slider_prev').click(function(){
    move_cell('prev') ;
  });
  
  $('#slider_next').click(function(){
    move_cell('next') ;
  });
  
  $('#panel_prev').click(function(){ 
    slide_panel('prev');    
  });
  
  $('#panel_next').click(function(){
    slide_panel('next');   
  });
  
  var timer;
  var is_stopped = false;
  var next_prev$ = $('#slider_next, #slider_prev');
  function start_carousel() {
    timer = setInterval(function(){
      $('#slider_next').click();
    },1500);
    $('#stop').text('Stop');
    is_stopped = false;
    hide_control()
  }
  
  function stop_carousel() {
    clearInterval(timer);
    $('#stop').text('Start');
    is_stopped = true;
    show_control()
  }
  
  $('#slider_wrap').hover(function() {
    clearInterval(timer);
    next_prev$.show();
  },function() {
    if(!is_stopped) {
      start_carousel();
      next_prev$.hide();  
    }      
  });
  
  $('#stop').click(function(){
    if(is_stopped) {
      start_carousel();
    }else{
      stop_carousel();      
    }    
  });
  hide_control()
  start_carousel();
  
  $(window).unload(function(){
    window.clearInterval(timer);
  });
});
</script>

大きな画像をスライド(サンプル4)

「サンプル3」の画像1枚分スライドさせるもので大きな画像を表示してみる。

サンプル4

  • 画像の枚数は最低3枚必要。
  • HTML はほぼ同じ(画像へのパスを大きな画像へのものに変更するだけ)

CSS

CSS も大きな画像を表示するためにそれぞれの要素の高さと幅や位置を変更するだけ。

CSS

#slider_wrap {
  margin: 20px auto;
  width: 720px; /*変更*/
  height: 423px; /*変更*/
  padding: 20px;
  background: #EFEFEF;
  position: relative;
  border: 1px solid #CCC;
}
#slider_prev {
  position: absolute;
  top: 205px; /*変更*/
  left: 10px;
  cursor: pointer;
}
#slider_next {
  position: absolute;
  top: 205px; /*変更*/
  right: 10px;
  cursor: pointer;
}
#slider {
  width: 100%;
  height: 100%;
  overflow: hidden;
}
#photo_list {
  height: 383px; /*変更*/
  padding: 20px;
  list-style-type: none;
  float: left;
  background: #999;
}
#photo_list li {
  float: left;
  margin-right: 20px; /*変更*/
  display: inline;
}
#photo_list img {
  border: none;
}
#stop {
  cursor: pointer;
  background: #666;
  color: #FFF;
  border: 1px solid #999;
  width: 50px;
  height: 2em;
  text-align: center;
  line-height: 2em;
  margin-left: 40px;
}

jQuery

jQuery も前のサンプルとほぼ同じ。

jQuery

<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script>
jQuery(function($){
  
  var photo_list$ = $('#photo_list');
  var li$ = $('#photo_list li');
  var li_count = li$.length;
  var li_width = li$.width() + parseInt(li$.css('margin-left'), 10) + parseInt(li$.css('margin-right'), 10);
  var ul_padding = parseInt(photo_list$.css('padding-left') , 10) + parseInt(photo_list$.css('padding-right') , 10);
  var slider_inner$ = $('#slider_inner');
  slider_inner$.css('width', (li_width * li_count + ul_padding) + 'px');
  $('#photo_list li:last').prependTo(photo_list$);
  slider_inner$.css('margin-left', '-' + li_width + 'px');  
  
  $('#slider_prev').click(function(){
    slider_inner$.stop().animate({
      marginLeft: parseInt(slider_inner$.css('margin-left'), 10) + li_width + 'px'
    }, 800,
    function(){
      slider_inner$.css('margin-left', '-' + li_width + 'px');
      $('#photo_list li:last').prependTo(photo_list$);
    });
  });
  
  $('#slider_next').click(function(){
    slider_inner$.stop().animate({
      marginLeft: parseInt(slider_inner$.css('margin-left'), 10) - li_width + 'px'
    }, 800,
    function(){
      slider_inner$.css('margin-left', '-' + li_width + 'px');
      $('#photo_list li:first').appendTo(photo_list$);
    });
  });
  
  var timer;
  var is_stopped = false;
  var next_prev$ = $('#slider_next, #slider_prev');
  function start_carousel() {
    timer = setInterval(function(){
      $('#slider_next').click();
    },2500);
    $('#stop').text('Stop');
    is_stopped = false;
  }
  
  function stop_carousel() {
    clearInterval(timer);
    $('#stop').text('Start');
    is_stopped = true;
  }
  
  $('#slider_wrap').hover(function() {
    clearInterval(timer);
    next_prev$.show();
  },function() {
    if(!is_stopped) {
      start_carousel();
      next_prev$.hide();  
    }      
  });
  
  $('#stop').click(function(){
    if(is_stopped) {
      start_carousel();
      next_prev$.hide();
    }else{
      stop_carousel();
      next_prev$.show();
    }    
  });
  next_prev$.hide();
  start_carousel();
  
  //念のため(不要?)
  $(window).unload(function(){
    window.clearInterval(timer);
  });
});
</script>

カルーセルではなくスライドさせる(サンプル5)

前述のカルーセルの場合、最低でもパネルの数は3つ必要で2つ以下の場合はうまく機能しない。
カルーセルではなく(1周すると元のパネルに戻るのではなく)、単に「前へ」または「次へ」の方向にスライドさせるようにする。

サンプル5

HTML と CSS は「サンプル1」と同じ。

jQuery では現在どのパネル(#slider_inner ul.panel)が表示されているかにより、「前へ」または「次へ」のボタンを表示するかどうかを判定して表示。

  • 1番目のパネルが表示されている場合は「前へ」のボタンを非表示に
  • 最後のパネルが表示されている場合は「次へ」のボタンを非表示に
  • それぞれのクリックイベントで現在のパネルのインデックスを更新
  • カルーセルではないので、最後のパネルを先頭位置に移動したりの処理は不要

jQuery

<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script>
jQuery(function($){
  
  //パネルの総数
  var panel_count = $('#slider_inner ul.panel').length;
  var slider_width = $('#slider_wrap').width();
  //パネル全体を格納する div 要素の幅を「表示領域の横幅 X パネルの数」に設定
  var slider_inner$ = $('#slider_inner');
  slider_inner$.css('width', slider_width * panel_count + 'px');

  //現在表示されているパネルのインデックス(初期化)
  var current_panel = 0;
  
  var prev$ = $('#slider_prev');
  var next$ = $('#slider_next');
  var prev_next$ = $('#slider_prev, #slider_next');
  
  //パネルのインデックスにより「戻る」と「進む」を表示するかどうかを判定
  function show_button() {
    if(current_panel <= 0 ) {
      prev$.css('visibility', 'hidden');
    }else{
      prev$.css('visibility', 'visible');
    }
    if(current_panel >= panel_count-1) {
      next$.css('visibility', 'hidden');
    }else{
      next$.css('visibility', 'visible');
    }  
  }
  show_button();
  
  prev$.click(function(){
    prev_next$.hide();
    var margin_left = parseInt(slider_inner$.css('margin-left'), 10) + slider_width;
    slider_inner$.stop().animate({
      marginLeft: margin_left + 'px'
    }, 700,
    function(){
      prev_next$.show();
      if(current_panel > 0 ) {
        current_panel--;
      }else{
        current_panel = panel_count -1;
      }
      show_button();
    });
  });
  
  next$.click(function(){
    prev_next$.hide();
    var margin_left = parseInt(slider_inner$.css('margin-left'), 10) - slider_width;
    slider_inner$.stop().animate({
      marginLeft: margin_left + 'px'
    }, 700,
    function(){
      prev_next$.show();
      current_panel = (current_panel + 1) % panel_count;
      show_button();
    });    
  });
});
</script>

表示されているパネルがわかるようにする(サンプル5-2)

サンプル5-2

サンプル5のように位置により「前へ」または「次へ」のボタンの表示を変更するのではなく、以下のようにする。

  • 最初のパネルが表示されていて「前へ」をクリックしたら最後のパネルへ移動
  • 最後のパネルが表示されていて「次へ」をクリックしたら最初のパネルへ移動

このため、どのパネルが表示されているかがわかりやすいように、それを表す画像を追加。

HTML と CSS はサンプル2と同じ。

jQuery では重複する記述が増えるので、パネルをスライドさせる処理を「animate_panel()」、「パネルの数を表す画像のリンク」の背景画像を設定する処理を「icon_setup()」という関数にしておく。

また、「パネルの数を表す画像のリンク」をクリックした場合の処理は、現在表示されているパネルとクリックされた「パネルの数を表す画像のリンク」の位置関係からスライドさせる量を調整。

jQuery

<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script>
jQuery(function($){
    
//パネルの総数
  var panel_count = $('#slider_inner ul.panel').length;
  var slider_width = $('#slider_wrap').width();
  //パネル全体を格納する div 要素の幅を「表示領域の横幅 X パネルの数」に設定
  $('#slider_inner').css('width', slider_width * panel_count + 'px');

  //現在表示されているパネルのインデックス(初期化)
  var current_panel = 0;
  
  var icon_width = $('#icon').width();
  //どのパネルが表示されているかを示す画像要素を生成
  if(panel_count > 1) {
    for(var i = 0; i < panel_count -1 ; i++) {
      $('#icon a:first').clone().appendTo('#icon');
    }
    $('#icon').css('width', icon_width * panel_count);    
  }
  var icon_imgs = $('#icon img');
  var icon_links = $('#icon a');
  //現在表示されているパネルに対応する画像を変更(異なる色にする)
  $(icon_imgs.get(current_panel)).attr('src', "images/slider-icon-selected.png");
  
  var prev_next$ = $('#slider_prev, #slider_next');
  var slider_inner$ = $('#slider_inner');
  var default_speed = 700;
  //パネルをスライドさせるアニメーション
  function animate_panel(margin_left, speed) {
    if(speed) { var speed = speed; }else{ var speed = default_speed; }
    prev_next$.hide();
    slider_inner$.stop().animate({
      marginLeft: margin_left + 'px'
    }, speed,
    function(){
      prev_next$.show();
    });
  }
  //現在表示されているパネルに対応する画像を変更する処理
  function icon_setup() {
    icon_imgs.attr('src', "images/slider-icon.png");
    $(icon_imgs.get(current_panel)).attr('src', "images/slider-icon-selected.png");
  }
  
  icon_links.click(function(){
    var this$ = $(this);
    //クリックされた画像のインデックスを取得
    var icon_index = icon_links.index(this$);
    //現在のパネルを示す画像のインデックスを取得
    var current_icon_index;
    icon_imgs.each(function(n) {
            if($(this).attr('src') == "images/slider-icon-selected.png") {
        current_icon_index = n;
      }
        });    
    current_panel = icon_index;
    icon_setup();    
    //インデックスの差分を取得
    var delta = Math.abs(icon_index - current_icon_index);
    //それぞれのインデックスを比較して処理を実行
    if(icon_index < current_icon_index){
      var margin_left = parseInt($('#slider_inner').css('margin-left'), 10) + slider_width * delta;
      animate_panel(margin_left);
    }else{      
      var margin_left = parseInt($('#slider_inner').css('margin-left'), 10) - slider_width * delta;
      animate_panel(margin_left);
    }  
    return false;    
  });
  
  $('#slider_prev').click(function(){
    if(current_panel > 0) {
      current_panel --;
      icon_setup();
      var margin_left = parseInt($('#slider_inner').css('margin-left'), 10) + slider_width;
      animate_panel(margin_left);
    }else{
      current_panel = panel_count -1;
      icon_setup();
      var margin_left = parseInt($('#slider_inner').css('margin-left'), 10) - (slider_width * (panel_count -1));
      animate_panel(margin_left);
    }
  });
  
  $('#slider_next').click(function(){    
    if(current_panel < panel_count - 1) {      
      var margin_left = parseInt($('#slider_inner').css('margin-left'), 10) - slider_width;
      animate_panel(margin_left);
    }else{
      var margin_left = parseInt($('#slider_inner').css('margin-left'), 10) + (slider_width * (panel_count -1));
      animate_panel(margin_left);
    }
    current_panel = (current_panel + 1) % panel_count;  
    icon_setup();
  });
});
</script>

画像1枚分スライドさせる(サンプル6)

サンプル6

HTML と CSS はサンプル3と同じ。。

jQuery ではサンプル5と同じように画像の位置により「前へ」または「次へ」のボタンを表示するかどうかを判定して表示。(サンプル5の場合はパネルの位置で判定)

また、「先頭」と「最後」というボタンを作成し、その位置へスライドするようにする。

<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script>
jQuery(function($){
    
  var photo_list$ = $('#photo_list');
  var li$ = $('#photo_list li');
  var li_count = li$.length;
  var li_width = li$.width() + parseInt(li$.css('margin-left'), 10) + parseInt(li$.css('margin-right'), 10);
  var ul_padding = parseInt(photo_list$.css('padding-left') , 10) + parseInt(photo_list$.css('padding-right') , 10);
  var slider_inner$ = $('#slider_inner');
  slider_inner$.css('width', (li_width * li_count + ul_padding) + 'px');
  
  //現在一番左に表示されている画像のインデックス(初期化)
  var current_image = 0;
  
  //画像のインデックスにより「戻る」と「進む」を表示するかどうかを判定
  var prev$ = $('#slider_prev');
  var next$ = $('#slider_next');
  function show_button() {
    if(current_image <= 0 ) {
      prev$.css('visibility', 'hidden');
    }else{
      prev$.css('visibility', 'visible');
    }
    if(current_image == li_count-4) {
      next$.css('visibility', 'hidden');
    }else{
      next$.css('visibility', 'visible');
    }  
  }
  show_button();
  
  var prev_next$ = $('#slider_prev, #slider_next');
  var default_speed = 500;
  //パネルをスライドさせるアニメーション
  function animate_panel(margin_left, speed) {
    if(speed) { var speed = speed; }else{ var speed = default_speed; }
    prev_next$.hide();
    slider_inner$.stop().animate({
      marginLeft: margin_left + 'px'
    }, speed,
    function(){
      prev_next$.show();
    });
  }
  //現在表示されているパネルに対応する画像を変更する処理
  function icon_setup() {
    icon_imgs.attr('src', "images/slider-icon.png");
    $(icon_imgs.get(current_panel)).attr('src', "images/slider-icon-selected.png");
  }
    
  $('#slider_prev').click(function(){
    if(current_image > 0 ) {      
      animate_panel(parseInt(slider_inner$.css('margin-left'), 10) + li_width);
      current_image --;
      show_button();  
    }else{      
      show_button();      
    }    
  });
  
  $('#slider_next').click(function(){    
    if(current_image < li_count -4) {
      animate_panel(parseInt(slider_inner$.css('margin-left'), 10) - li_width);
      current_image ++;
      show_button();
    }else{
      show_button();
    }    
  });
  
  $('#last').click(function(){    
    animate_panel(li_width * (li_count - 4) * -1);
    current_image = li_count -4;
    show_button();  
  });
  
  $('#top').click(function(){
    animate_panel(0);
    current_image = 0;
    show_button();
  });
});
</script>

大きな画像をスライド(サンプル7)

サンプル7

サンプル4と同じように大きな画像をスライドさせる。

HTML と CSS はサンプル4とほぼ同じ(「先頭」と「最後」というボタンを追加)。

jQuery はサンプル6とほぼ同じ。但し、パネルではなく画像1枚をスライドさせるので、現在表示されている画像のインデックス(current_image)での比較が多少異なる。

<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script>
jQuery(function($){
    
  var photo_list$ = $('#photo_list');
  var li$ = $('#photo_list li');
  var li_count = li$.length;
  var li_width = li$.width() + parseInt(li$.css('margin-left'), 10) + parseInt(li$.css('margin-right'), 10);
  var ul_padding = parseInt(photo_list$.css('padding-left') , 10) + parseInt(photo_list$.css('padding-right') , 10);
  var slider_inner$ = $('#slider_inner');
  slider_inner$.css('width', (li_width * li_count + ul_padding) + 'px');
  
  //現在表示されている画像のインデックス(初期化)
  var current_image = 0;
  
  //画像のインデックスにより「戻る」と「進む」を表示するかどうかを判定
  var prev$ = $('#slider_prev');
  var next$ = $('#slider_next');
  function show_button() {
    if(current_image <= 0 ) {
      prev$.css('visibility', 'hidden');
    }else{
      prev$.css('visibility', 'visible');
    }
    if(current_image == li_count-1) {
      next$.css('visibility', 'hidden');
    }else{
      next$.css('visibility', 'visible');
    }  
  }
  show_button();
  
  var prev_next$ = $('#slider_prev, #slider_next');
  var default_speed = 500;
  //パネルをスライドさせるアニメーション
  function animate_panel(margin_left, speed) {
    if(speed) { var speed = speed; }else{ var speed = default_speed; }
    prev_next$.hide();
    slider_inner$.stop().animate({
      marginLeft: margin_left + 'px'
    }, speed,
    function(){
      prev_next$.show();
    });
  }
    
  $('#slider_prev').click(function(){
    if(current_image > 0 ) {
      animate_panel(parseInt(slider_inner$.css('margin-left'), 10) + li_width);
      current_image --;
      show_button();  
    }else{      
      show_button();      
    }    
  });
  
  $('#slider_next').click(function(){    
    if(current_image < li_count -1) {
      animate_panel(parseInt(slider_inner$.css('margin-left'), 10) - li_width);
      current_image ++;
      show_button();
    }else{
      show_button();
    }    
  });
  
  $('#last').click(function(){
    animate_panel(li_width * (li_count - 1) * -1, 1200);
    current_image = li_count -1;
    show_button();
  });
  
  $('#top').click(function(){
    animate_panel(0, 1200);
    current_image = 0;
    show_button();
  });

});
</script>

表示されている画像がわかるようにする(サンプル8)

サンプル8

今までの方法を組み合わせたもの。

HTML と CSS はサンプル7とほぼ同じ(どの画像が表示されているかを示す画像を追加)。

jQuery

<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script>
jQuery(function($){
    
  var photo_list$ = $('#photo_list');
  var li$ = $('#photo_list li');
  var li_count = li$.length;
  var li_width = li$.width() + parseInt(li$.css('margin-left'), 10) + parseInt(li$.css('margin-right'), 10);
  var ul_padding = parseInt(photo_list$.css('padding-left') , 10) + parseInt(photo_list$.css('padding-right') , 10);
  var slider_inner$ = $('#slider_inner');
  slider_inner$.css('width', (li_width * li_count + ul_padding) + 'px');
  
  //画像のインデックスにより「戻る」と「進む」を表示するかどうかを判定
  var prev$ = $('#slider_prev');
  var next$ = $('#slider_next');
  function show_button() {
    if(current_image <= 0 ) {
      prev$.css('visibility', 'hidden');
    }else{
      prev$.css('visibility', 'visible');
    }
    if(current_image == li_count-1) {
      next$.css('visibility', 'hidden');
    }else{
      next$.css('visibility', 'visible');
    }  
  }
  
  //現在表示されている画像のインデックス(初期化)
  var current_image = 0;
  
  var icon_width = $('#icon').width();
  
  if(li_count > 1) {
    for(var i = 0; i < li_count -1 ; i++) {
      $('#icon a:first').clone().appendTo('#icon');
    }
    $('#icon').css('width', icon_width * li_count);    
  }
  var icon_imgs = $('#icon img');
  var icon_links = $('#icon a');
  $(icon_imgs.get(current_image)).attr('src', "images/slider-icon-selected.png");
  
  var prev_next$ = $('#slider_prev, #slider_next');
  var default_speed = 500;
  
  //コールバックで繰り返し使用する関数(パネルをスライドさせるアニメーション)
  function animate_panel(margin_left, speed) {
    if(speed) { var speed = speed; }else{ var speed = default_speed; }
    prev_next$.hide();
    slider_inner$.stop().animate({
      marginLeft: margin_left + 'px'
    }, speed,
    function(){
      prev_next$.show();
    });
  }
  //現在表示されているパネルに対応する画像を変更とボタンを表示する処理
  function setup() {
    icon_imgs.attr('src', "images/slider-icon.png");
    $(icon_imgs.get(current_image)).attr('src', "images/slider-icon-selected.png");
    show_button();
  }
  
  icon_links.click(function(){
    var this$ = $(this);
    //クリックされた画像のインデックスを取得
    var icon_index = icon_links.index(this$);
    //現在のパネルを示す画像のインデックスを取得
    var current_icon_index;
    icon_imgs.each(function(n) {
            if($(this).attr('src') == "images/slider-icon-selected.png") {
        current_icon_index = n;
      }
        });
    //インデックスの差分を取得
    var delta = Math.abs(icon_index - current_icon_index);
    //それぞれのインデックスを比較して処理を実行
    if(icon_index < current_icon_index){
      animate_panel(parseInt($('#slider_inner').css('margin-left'), 10) + li_width * delta, 700);
      current_image -= delta;
      setup();
    }else{  
      animate_panel(parseInt($('#slider_inner').css('margin-left'), 10) - li_width * delta, 700);
      current_image += delta;
      setup();
    }  
    return false;    
  });
    
  $('#slider_prev').click(function(){
    if(current_image > 0 ) {
      animate_panel(parseInt(slider_inner$.css('margin-left'), 10) + li_width, 500);
      current_image --;
      setup();
    }else{      
      show_button();      
    }    
  });
  
  $('#slider_next').click(function(){    
    if(current_image < li_count -1) {
      animate_panel(parseInt(slider_inner$.css('margin-left'), 10) - li_width, 500);
      current_image ++;
      setup();  
    }else{
      show_button();
    }    
  });
  
  $('#last').click(function(){
    animate_panel(li_width * (li_count - 1) * -1, 2000);
    current_image = li_count -1;
    setup();
  });
  
  $('#top').click(function(){
    animate_panel(0, 2000);
    current_image = 0;
    setup();
  });
  
  //初期状態のボタンの表示
  show_button();
});
</script>