jquery jQuery Cookie Pluginを利用してランダムに画像を表示

2013年4月30日

トップページなどで、画像を複数用意してユーザーがアクセスする度に異なる画像を表示する場合などに応用できる方法。

  • ユーザーが前回アクセスしたときにどの画像を表示したかの記録が必要なのでクッキー(Cookie)を利用する。
  • 異なる順序で毎回表示するため乱数を利用する。
  • 但し、単に乱数を発生させると同じ数が連続する可能性があるので、重複しないようにする。
  • 画像名は「xxx-1.jpg」のように、数字を使い、異なる画像を表示するときにこの数字の部分を変更。
  • 数字を使わない場合は、画像要素を HTML に記述して非表示にしておき、jQuery のラップ集合として操作する。(後述)
  • クッキーを使えない環境の場合は単純に乱数を発生させる。

例えば5枚の画像を表示する場合、以下の画像を用意したとして
pic-1.jpg
pic-2.jpg
pic-3.jpg
pic-4.jpg
pic-5.jpg

下記のような要素の乱数の配列(arrayxとする)を生成した場合、
「2, 4, 1, 3, 0」
それぞれの要素は、arrayx[index] でアクセスできるので(index は添え字)、画像名は以下のように記述できる。
‘pic-‘ + (arrayx[index] + 1) + ‘.jpg’
index = 4 の場合、arrayx[4] は「0」なので pic-1.jpg となる。

そこで、乱数の配列と要素の添え字をクッキーに登録し、画像を表示する度に、添え字(index)を1つ増やし、そのクッキーを更新する。

jQuery Cookie Plugin(プラグイン)の使用

以下のサイトから「jQuery Cookie Plugin v1.3.1」コードをコピー (「jquery.cookie.js」とある部分をクリック)または右側の「Download ZIP」をクリックすると関連ファイルもダウンロードできる。
jQuery Cookie Plugin(github)

重複のない乱数の配列を生成する関数を用意

以下の関数は重複のない乱数の配列を返す。(詳細はこちら

function generate_randomx(count) {
  var generated = new Array();
  var generatedCount = generated.length;
  for(var i = 0 ; i < count; i++){
    var candidate = Math.floor(Math.random() * count);
    //今まで出力された数字と同じ場合は再度乱数を発生
    for(var j = 0; j < generatedCount; j++) {
      if(candidate == generated&#91;j&#93;){
        candidate = Math.floor(Math.random() * count);
        j= -1;
      }
    }
    generated&#91;i&#93; = candidate;  
    generatedCount++;
  }
  return generated;  
}
&#91;/code&#93;

<h3>概要</h3>
<ul>
<li>画像の数分の重複のないランダムな数値の配列を作成</li>
<li>作成した配列を(文字列として)クッキーに登録</li>
<li>現在の配列の添え字をクッキーに登録する</li>
<li>画像を表示する際に、クッキーから配列と添え字を取得し、添え字の値を1ずつ増やして更新する</li>
</ul>

以下の例は、重複のないランダムな数値の配列を作成し、それをクッキーに登録して、それらの数値を順番に取り出す関数。クッキーの期限はセッション(ブラウザを閉じるまで)とするので「expires」は指定しない。
<ul class="nodisc">
<li>total_count:重複のないランダムな数値の総数</li>
<li>array_cookie:配列を登録するクッキーの名前(重複しない適当な文字列)</li>
<li>index_cookie:配列の要素を指定するための配列の添え字を登録するクッキーの名前(重複しない適当な文字列)</li>
</ul>
function get_random_number(total_count, array_cookie, index_cookie) { //重複のないランダムな数値の配列を生成(先に用意した関数を利用) var arrayx = generate_randomx(total_count); var countx = 0; //配列の添え字を格納 var number = 0; //返す値の数値を格納 //上記配列を文字列に変換して(クッキーに登録されていない場合は)クッキーに登録(.toString()は省略可能) if(!$.cookie(array_cookie)) { $.cookie(array_cookie, arrayx.toString(), { path: '/' } ); } //上記配列の添え字として使用する数を(クッキーに登録されていない場合は)クッキーに登録 if(!$.cookie(index_cookie)){ $.cookie(index_cookie, 0, { path: '/' } ); } //クッキー「array_cookie」の文字列を配列(整数をランダムに格納した配列)へ変換(クッキーが無効な場合は「null」にしておく arrayx = $.cookie(array_cookie) ? $.cookie(array_cookie).split(',') : null; if(arrayx){ //クッキー「index_cookie」(添え字)の値を数値(countx)に変換 countx = parseInt($.cookie(index_cookie), 10); //返す値の数値を取得(返す値の範囲は0 から total_count-1 なので必要であれば使用時に1を足す) number = parseInt(arrayx[countx], 10); //添え字の値(countx)を1増加 countx = (countx + 1) % total_count; //クッキー「index_cookie」の値を更新して登録 $.cookie(index_cookie, countx, { path: '/' } ); }else{ ////クッキーが無効な場合(重複のないランダムな数値は保存されないので、単純に乱数を発生) number = Math.floor(Math.random() * total_count); } return number; }

使用例
以下の画像を用意し、div 要素内に p 要素と img 要素を次のように記述した場合
pic-1.jpg
pic-2.jpg
pic-3.jpg
pic-4.jpg
pic-5.jpg

<div id="section_test">
    <p>
        <img id="mainPhoto" src="images/pic-1.jpg.jpg" height="200" width="300" alt="photo" />
    </p>
</div><!-- end of .section_test -->

以下を記述すると、その画像をクリックする度に、ランダムに画像が切り替わる。
(画像要素の src 属性を get_random_number() を使って変更)

$('#section_test p img').css('cursor', 'pointer').click( function() {
    $(this).attr('src', 'images/pic-' +(get_random_number(5, 'array_x', 'index_x') + 1) + '.jpg');
  });

画像名に数字を使わない場合

前述の例では、画像名を「xxx-1.jpg」のように、数字を使い、この数字の部分を変更したが、以下は画像名に数字を使わない場合の方法。

  • 表示する画像(img)要素を HTML に記述し、CSS で非表示にしておく。
  • 画像(img)要素のラップ集合を発生させたランダムな値で操作する。
  • また、以下の例では最初に表示する画像を指定できるようにする。

HTML

<!-- 写真を表示する部分 -->
<p class="top_photo">
<img id="mainPhoto" src="images/sky.jpg" height="200" width="300" alt="空の写真" />
</p>

<!-- ランダムに表示する画像(非表示にしておく) -->
<div id="photo_list">
<img id="mainPhoto" src="images/bridge.jpg" height="200" width="300" alt="橋の写真" />
<img id="mainPhoto" src="images/building.jpg" height="200" width="300" alt="ビルの写真" />
<img id="mainPhoto" src="images/river.jpg" height="200" width="300" alt="川の写真" />
<img id="mainPhoto" src="images/sunset.jpg" height="200" width="300" alt="夕焼けの写真" />
<img id="mainPhoto" src="images/sky.jpg" height="200" width="300" alt="空の写真" />
</div>

CSS

div#photo_list {
  display: none;
}

jQuery

/*!
* jQuery Cookie Plugin v1.3.1
*/
(function (factory) {
  //jQuery Cookie Plugin(省略)
}));

jQuery(function($){
  //乱数の配列を生成して返す。
  //count:生成する乱数の数
  //num: 1番目の数値を指定(必ずその数値を1番目にもってくる)。値の範囲は0~count-1 (オプション)
  function generate_randomx(count, num) {
    var generated = new Array();
    var generatedCount = generated.length;
    //num: 1番目の数値の指定がある場合
    if(num || num === 0 ) {
      for(var i = 0 ; i < count; i++){
        //1番目の数値(generated&#91;0&#93;)を num の値にする
        if(i === 0) {
          var candidate = num;
          generated&#91;i&#93; = candidate;  
          generatedCount++;
          continue;
        }
        candidate = Math.floor(Math.random() * count);
        //今まで出力された数字と同じ場合は再度乱数を発生
        for(j = 0; j < generatedCount; j++) {
          if(candidate == generated&#91;j&#93;){
            candidate = Math.floor(Math.random() * count);
            j= -1;
          }
        }
        generated&#91;i&#93; = candidate;  
        generatedCount++;
      }
    }else{
      for(i = 0 ; i < count; i++){
        candidate = Math.floor(Math.random() * count);
        //今まで出力された数字と同じ場合は再度乱数を発生
        for(j = 0; j < generatedCount; j++) {
          if(candidate == generated&#91;j&#93;){
            candidate = Math.floor(Math.random() * count);
            j= -1;
          }
        }
        generated&#91;i&#93; = candidate;  
        generatedCount++;
      }
    }
    return generated;  
  }
  //重複のないランダムな数値の配列を作成し、それをクッキーに登録して、それらの数値を順番に取り出す関数
  function get_random_number(total_count, array_cookie_name, index_cookie_name, my_options) {
    //total_count:重複のないランダムな数値の総数
    var array_cookie = array_cookie_name;    //array_cookie:乱数の配列を登録するクッキーの名前(文字列)
    var index_cookie = index_cookie_name;    //index_cookie:配列を操作するための配列の添え字を登録するクッキーの名前(文字列)vvvv
    var settings = $.extend({
      first : null,    //1番目の数値を指定。generate_randomx(count, num) 参照。(オプション)
      expires : null,    //クッキーの期限。(オプション)
      path : '/'  //クッキーのパス。(オプション)
    }, my_options || {});
    
    var countx = 0;    
    var number = 0;      
    var arrayx = generate_randomx(total_count, settings.first);//重複のないランダムな数値の配列を生成(要素は 0 から total_count-1 までの整数)
    if(!$.cookie(array_cookie)) {//上記配列を文字列に変換して(クッキーに登録されていない場合は)クッキーに登録(.toString()は省略可能)
      $.cookie(array_cookie, arrayx.toString(), { expires: settings.expires, path: settings.path } );      
    }
    if(!$.cookie(index_cookie)){//上記配列の添え字として使用する数を初期化して(クッキーに登録されていない場合は)クッキーに登録
      $.cookie(index_cookie, 0, { expires: settings.expires, path: settings.path } );    //クッキー「index_cookie」の値を更新して登録
    }
    //クッキーが無効でなければクッキーから値を取得
    arrayx = $.cookie(array_cookie) ? $.cookie(array_cookie).split(',') : null;    //クッキー「array_cookie」の文字列を配列(整数をランダムに格納した配列)へ変換
    if(arrayx) {
      countx = parseInt($.cookie(index_cookie), 10);    //クッキー「index_cookie」の値を数値(countx)に変換
      number = parseInt(arrayx&#91;countx&#93;, 10);  //返す値の数値を取得
      countx = (countx + 1) % total_count;    //添え字の値(countx)を1増加
      $.cookie(index_cookie, countx, { expires: settings.expires, path: settings.path } );    //クッキー「index_cookie」の値を更新して登録
    }else {  //クッキーが無効な場合(重複のないランダムな数値は保存されないので、単純に乱数を発生)    
      number = Math.floor(Math.random() * total_count);  
    }    
    return number;
  }
  //画像要素のラップ集合
  var photos$ = $('#photo_list img');
  //5番目の写真を必ず最初に表示するように指定
  var rand_photo = get_random_number(photos$.length, 'array_x', 'index_x', {first: 4});
  //画像要素のラップ集合(photos$)の「rand_photo」番目の要素の「src」と「alt」の属性を取得して、表示されている画像の属性に入れ替える。
  $('p.top_photo img').attr({src: $(photos$.get(rand_photo)).attr('src'), alt:$(photos$.get(rand_photo)).attr('alt')});
});
&#91;/code&#93;

<h4>クッキー(Cookie)の確認</h4>
一番簡単で、詳細な情報を確認するには、 Firefox の Firebug を使用して、「Cookie」のタブを表示すると、下記のように「名前」、「内容」、「有効期限」など全てのクッキーの情報を確認できる。

<a  class="mpg" href="http://www.webdesignleaves.com/wp/wp-content/uploads/2013/04/cookie_firebug.gif"><img src="http://www.webdesignleaves.com/wp/wp-content/uploads/2013/04/cookie_firebug.gif" alt="Firebug での クッキーの表示" width="600" height="179" class="aligncenter size-full wp-image-130" /></a>

(メモ)
「www あり」と「www なし」を統一していない場合、ドメインを指定しないと、「www あり」と「www なし」で別々の同じ名前のクッキーが生成されている。

jQuery Cookie Pluginを利用した場合、クッキーを読み込むには設定してクッキー名を使って以下のように記述するだけ。
$.cookie('クッキー名'); // => 値が得られる alert($.cookie('クッキー名')); // => 値がアラートで表示される

全てのクッキーを読み込むには、パラメータなしで以下のように記述すると、全てのクッキーの値がオブジェクトで取得できる。

$.cookie(); // => { "クッキー名": "値", "...remaining": "cookies" }

ローカル環境で全てのクッキー名と値をアラートで表示させるには、以下のように記述。

function showCookies(cookie) {
     var values = '';
     for (var name in cookie){
       values += name + "=" + cookie[name] + "\n";
     }
     alert(values);
}
showCookies($.cookie());

有効期限を設定したクッキーの場合の注意点

クッキーに有効期限を設定した場合、写真の枚数などを変更する際は、クッキーの名前を変更する。

そうしないと写真の枚数が減ると、実際の写真の数より大きいインデックスが残っているため画像が表示されず、また、写真の枚数が増えると、増えた分の写真は表示されない。