堀北真希うさぎ
主な作品
堀北真希ちゃんのボシュロム社TVコマーシャル出演にちなんで描いた、コンタクトレンズをつけている堀北真希うさぎのイラストと仮想CM動画

ページ案内

Ajaxを利用したサムネール処理。

最近ウェブログなどで見掛ける、縮小された画像を選択するとそのページの背景が暗くなって中央に元の画像が表示される機能を解説します。

Ajaxを利用したサムネール処理・目次。

Ajaxを利用したサムネール処理のサンプル。

Ajaxを用いたヴァージョン。

Ajaxに対応している環境で縮小されている画像を選択すると、背景が暗くなって、リンク先の本文とリンク先にある元の画像が表示されるようになります。

Ajaxを用いていないヴァージョン。

Ajaxに対応している環境の方向けに、比較用に用意したサンプルです。

こちらは、縮小されている画像を選択しても、全く同じリンク先へ遷移するだけです。

Ajaxを利用したサムネール処理の実際のコード。

Ajaxを利用したサムネール処理のサンプルに於ける前提条件。

今回のサンプルの前提条件として、以下のようになっている事に留意してください。

  1. 先ず、画像を選択すると、縮小していない画像がと簡単な説明を記したHTML文書がXHTMLの形で用意されております。

    今回、Ajaxを用いて、画像を選択すると、画面が暗くなって中央にそのHTML文書のメイン部分だけを抜き取って表示するようにします。

  2. リンク先のHTML文書は、Ajaxで加工し易いようにXHTMLとしましたが、AjaxでXML文書として処理が出来るよう、全く同じ内容でファイル名の末尾に .xml が追加されたXML文書版(つまり、.html.xml と言う二重拡張子になっているもの)を別途用意しております。

    今回こうした理由は、Ajaxの場合のみXML文書として配信すると言う設定にしようとすると、サーヴァの設定の話しまでする必要が出てくるためです。

    実際にHTML文書をAjaxで読み込み、加工して出力させたいのであれば、AjaxでのHTTP通信ではURLの末尾に何らかのクエリを与えておいて、それをサーヴァが認識したらXML文書(MIMEタイプ・text/xml)として配信すると言うやり方がベターかと思われます。

    • サーヴァがAjaxでのHTTP通信に依るアクセスかどうかを判別する事は出来ないようですので、AjaxでのアクセスではリクエストするURLに何らかの目印(通常のアクセスでは使われないクエリなど)を付けてやる必要があります。
    • 勿論、処理対象となるHTML文書は少なくとも整形式となっているXHTML文書にしておく必要があります。在来のHTMLでは空要素が入るとDOMとして取り出す事が出来ません。

    そのような方法が使えない場合は、今回のように別途同じ内容のXHTML文書を用意してそれにアクセスさせるしか無いでしょう。

  3. また、HTML文書には、id="TOP"属性を与えた<h1>要素で始まり、id="TO_TOP"属性を与えた<ul>要素で本文部分が終わると言うテンプレートを使っております。

    そこで、この二つの要素の間の部分のみを抽出して表示させる事とします。

    但し、<body>要素直下の要素でクラス名に noAjax を含んでいる要素は抽出しないものとします。

  4. このHTML文書には、Ajaxを起動するための onclock属性をリンクしている<a>内には記述せず、スクリプトに対応している場合に限りHTML文書読み込み直後にDOM操作でonclick属性を附加するようにします。

    勿論、対象となる<a>要素は限定されます。具体的には、クラス名に aj_thumbnail を含んだ<ul>要素の子孫要素のみとします。

Ajaxを利用したサムネール処理のサンプルに於ける実際のコード。

実際にサンプルに用いた、ThumbNail.jsのコードは以下のようになっております。

尚、このコードは HTTPRequest.js と併用する必要があります。

/*
    Ajax(アジャックス)サンプルコード(2) - 画像。
    ※インターネットエクスプローラはウィンドウズ版の5.0以降を対象とします。
    ※『サンプルコード(0) - HTTPリクエストを行うコード』が必要です。
*/

/********************************************************************************
    元のHTML文書に本処理を起動するための仕掛けをする処理。
********************************************************************************/
var s_onload=window.onload;
window.onload=thumbnail_prepare;
window_width=600;    //    ウィンドウの幅。

function thumbnail_prepare() {
    if (s_onload) s_onload();

    var e=document.getElementsByTagName('ul');
    var i=e.length;

    while (--i>=0) {
        var c=' '+(e[i].getAttribute('class') || e[i].getAttribute('className') || '')+' ';
        if (c.indexOf('aj_thumbnail')<0) continue;
        var e1=e[i].getElementsByTagName('a');
        var j=e1.length;
        while (--j>=0) {
            e1[j].onclick=getHTML;
            }
        }
}

/********************************************************************************
    XHTML文書をHTTP通信で取得するための処理。
********************************************************************************/
var h=null;
function getHTML() {
    var f=this.getAttribute('href');

    //    HTTP通信のセッティングを行う。
    h=httpReq();
    //    HTTP通信をサポートしていないか、通信に失敗した場合、何もなかったように戻る。
    if (!h) {
        return(true);
        }

    //    通信状況が変わったとき(通信中⇒通信完了など)に実行すべき処理を指定する。
    h.onreadystatechange=getHTML2;
    //    実際にHTTP通信で文書を取得する処理。
    //    ※今回は、本来配信するHTMLと同じもので、ファイル名末尾に「.xml」をつけたものを
    //     XML文書として配信するようにしております。
    h.open('GET',f+'.xml',true);
    h.send(null);
    return(false);
}

/********************************************************************************
    通信状況が変化したときに呼び出される函数。
    ※実際には、HTTP通信が正常終了した場合のみ処理を行う。
********************************************************************************/
function getHTML2() {
    //    通信完了でなければ何もなかったように戻る。
    if (h.readyState!=4) return(true);

    //    正常に処理されなければ、エラーとして通信を途絶させて戻る。
    if (h.status!=200) {
        alert('HTTPエラー '+h.status+' が発生しました!');
        h.abort();
        return(false);
        }

    //    HTML文書をXMLとして取り込む。
    var txt=h.responseXML;
    h.abort();    //この段階で通信を終了する。
    proccessHTML2display(txt);    //HTML加工処理に移る。
    }

/********************************************************************************
    取得したXHTML文書を加工して表示させる処理。
********************************************************************************/
var canvas='';
var bgscreen='';
function proccessHTML2display(txt) {
    /**********************************************************
         取得したXHTML文書の表示用ノードの確保。
    **********************************************************/
    //    加工したHTMLを表示させるための<div>要素(bgscreenノード)を作成する。
    //    実際の内容を入れる子ノード(canvasノード)を生成する。
    var b=(document.getElementsByTagName('body'))[0];
    if (!bgscreen) {
        bgscreen=document.createElement('div');
        b.appendChild(bgscreen);
        }

    if (canvas) {
        b.removeChild(canvas);
        }
    canvas=document.createElement('div');
    b.appendChild(canvas);

    /**********************************************************
         取得したXHTML文書の加工。
    **********************************************************/
    /*
        IDとして「TOP」を与えられた要素の次の要素から、
         IDとして「TO_TOP」を与えられた要素の直前までを取得。
         但し、クラス名に「noAjax」が含まれている要素は除外する。
    */
    var t2=(txt.getElementsByTagName('body'))[0];
    if (!t2) {
        alert('HTMLが壊れております!');
        return(true);
        }
    e=t2.childNodes;

    //    IDとして「TOP」を与えられた要素までスキャンするi=-1;
    while (++i<e.length) {
        if (e[i].nodeType!=1) continue;
        var j=e[i].getAttribute('id') || '';
        if (j=='TOP') break;
        }

    //    IDとして「TO_TOP」を与えられた要素の手前までcanvasノードに追加する。
    //    但し、クラス名に「noAjax」が含まれている要素は追加しない。
    while (++i<e.length) {
        if (e[i].nodeType!=1) continue;
        var j=e[i].getAttribute('id') || '';
        if (j=='TO_TOP') break;
        j=' '+(e[i].getAttribute('class') || e[i].getAttribute('className') || '')+' ';
        if (j.indexOf(' noAjax ')>-1) continue;
        appendOthersNode(canvas, e[i]);
        }

    //    末尾に<hr>要素とクローズするためのアンカーを付けるvar e1=document.createElement('hr');
    e1.style.margin='2em 0 0';
    canvas.appendChild(e1);
    e1=document.createElement('ul');
    e1.style.margin='1em 0 0';
    canvas.appendChild(e1);
    var e2=document.createElement('li');
    e1.appendChild(e2);
    var e3=document.createElement('a');
    e2.appendChild(e3);
    var e4=document.createTextNode('戻る');
    e3.appendChild(e4);
    e3.onclick=closeCanvas;
    e3.setAttribute('href','#');

    /**********************************************************
         加工したXHTML文書の表示。
    **********************************************************/
    e1=(document.getElementsByTagName('body'))[0];
    var h=e1.offsetHeight;
    var w1=document.documentElement.clientWidth || document.body.clientWidth ||
           window.innerWidth;
    var h1=document.documentElement.clientHeight || document.body.clientHeight ||
           window.innerHeight;
    var t=e1.offsetTop;
    var l=e1.offsetLeft;
    var ie6=document.all && !window.opera &&
           navigator.userAgent.indexOf('MSIE 7.')<0 &&
           navigator.userAgent.indexOf('Trident/')<0;

    //    幅を決める。
    window_width=Math.floor(w1*0.7);

    //    IE 6.0まで(position fixed;が使えない)。
    if (ie6) {
        bgscreen.style.position='absolute';
        bgscreen.style.visiblity='visible';
        bgscreen.style.display='block';
        bgscreen.style.top=0;
        bgscreen.style.left=0;
        bgscreen.style.zIndex='1000';
        bgscreen.style.width=w1+'px';
        bgscreen.style.height=h+'px';
        bgscreen.style.background='#000000';
        bgscreen.style.overflow='hidden';
        bgscreen.style.margin=0;
        bgscreen.style.padding=0;
        bgscreen.style.filter='alpha(opacity=70)';
        bgscreen.style.opacity='0.7';

        canvas.style.visiblity='visible';
        canvas.style.display='block';
        canvas.style.position='absolute';
        canvas.style.top=((document.body.scrollTop || document.documentElement.scrollTop)+32)+'px';
        canvas.style.left=((w1-window_width-64)/2)+'px';
        canvas.style.width=window_width+'px';
        canvas.style.height=(h1-128)+'px';
        }

    //    その他(position fixed;が使える)。
    else {
        bgscreen.style.position='fixed';
        bgscreen.style.visiblity='visible';
        bgscreen.style.display='block';
        bgscreen.style.top=0;
        bgscreen.style.left=0;
        bgscreen.style.zIndex='1000';
        bgscreen.style.width=w1+'px';
        bgscreen.style.height=h1+'px';
        bgscreen.style.overflow='hidden';
        bgscreen.style.margin=0;
        bgscreen.style.padding=0;
        bgscreen.style.background='#000000';
        bgscreen.style.filter='alpha(opacity=70)';
        bgscreen.style.opacity='0.7';

        canvas.style.visiblity='visible';
        canvas.style.display='block';
        canvas.style.position='fixed';
        canvas.style.top='32px';
        canvas.style.left=((w1-window_width-64)/2)+'px';
        canvas.style.width=window_width+'px';
        canvas.style.height=(h1-128)+'px';
        }
    canvas.style.zIndex='1001';
    canvas.style.overflow='auto';
    canvas.style.margin='0';
    canvas.style.padding='32px';
    canvas.style.background='#ffffff';
    return(false);
}

/********************************************************************************
    閉じる処理。
********************************************************************************/
function closeCanvas() {
    bgscreen.style.display='none';
    bgscreen.style.visiblity='hidden';
    canvas.style.display='none';
    canvas.style.visiblity='hidden';
    return(false);
}

Ajaxを利用したサムネール処理のサンプルコードの説明。

Ajaxを利用したサムネール処理のサンプルのコードはちょっと長いので、どれがどのように動作するか簡単に説明させていただきます。

Ajaxを利用したサムネール処理のサンプルコードの具体的な処理の流れ。

Ajaxを利用したサムネール処理のサンプルのコードの簡単な処理の流れは以下のようになります。

  1. 先ず、HTML文書読み込み完了時に、指定されたサムネール内のアンカーをクリックされると、Ajaxが起動してリンク先のXHTML文書に対応するXHTML文書(すなわち、XML文書)を取得するようにします。
  2. 指定されたサムネールがクリックされたときに起動するAjax起動処理では、リンク元のアンカーのhref属性を元にしたXHTML文書のURLをリクエストします。
  3. リクエストされたXML文書は受け取り処理でDOM形式で受け取り、それを加工して表示させる処理に引き渡します。
  4. 受け取ったXHTML文書を加工して表示させる処理では、欲しい要素のみを抽出してスタイルを調整したうえで親HTML文書のノードに追加します。更に、元の状態に戻すアンカーも追加します。このアンカーのリンク先はこのスクリプトの一番最後にある消去処理へのアンカーとなります。

それでは、もう少し詳しく解説しましょう。

HTML文書読み込み完了時の処理。

先ず、読み込み完了後にthumbnail_prepare() 函数を呼ぶように読み込み時に設定します。

thumbnail_prepare() 函数では、指定されたサムネール(ここではクラス名に aj_thumbnail を含んだ<ul>要素)内にある<a>要素に対し、クリックでXHTML文書をHTTP通信で取得するための処理である getHTML() 函数をコールするようにDOM操作を行います。

サムネールクリック時に起動するAjax起動処理。

getHTML() 函数では、クリック元のアンカーが参照しているURLに対応するXML文書をHTTP通信で取得するようにしております。

また、通信完了時(実際には通信状況が変わった際)に通信で取得したXML文書の受け取り処理を担当するgetHTML2() 函数を割り込むようにします。

これらの処理はAjaxでの文書類リクエスト処理内のデータを送信する必要がない場合のリクエスト方法でのコードと殆ど同じですが、今回は取得する文書のURLとして、クリック元の<a>要素のhref属性の値を加工したものを用いております。

リクエストしたXHTML文書の受け取り処理。

getHTML2() 函数サムネールクリック時に起動するAjax起動処理で、通信状況が変わった際に割り込む処理です。

実際には通信完了時以外には処理出来る事はないので、通信が完了した場合のみ処理を続けます。

正常にHTTPが実行された事を確認したうえで、取得したXHTML文書をXML文書のDOMとして受け取ります。

ここでの処理はAjaxでのデータ取得処理内のAjaxでXML文書としてデータを受け取る場合でのコードと殆ど同じですが、今回はDOMのエラーチェックは後で行う事としております。

また、DOMを受け取ったら、それをproccessHTML2display() 函数に引渡します。

受け取ったXHTML文書を加工して表示させる処理。

proccessHTML2display() 函数リクエストしたXHTML文書の受け取り処理であるgetHTML2() 函数から呼び出されます。

引数として、取得したXML文書のDOMデータを受け取ります。

今回は、取得したXHTML文書から欲しい要素のみを抽出して表示させるため、その表示場所となる要素ノードが必要となります。

また、表示時には背景を暗くしたいため、半透明の黒い要素ノードを画面全体に被さるようにします。

これらのノードは取得したHTML文書の表示用ノードの確保の処理で行います。

具体的には、

となります。

表示用の準備が整ったら、いよいよ取得したXHTML文書の加工に入ります。

注釈にあるように、取得したXHTML文書の<body>要素の子要素のうち、id="TOP"属性を与えられた要素の次の要素から、id="TO_TOP"属性を与えられた要素の直前までを取得します。

先ず、取得したXHTML文書のDOMから、一番目の<body>要素(XHTML文書なので<body>要素は一つしか存在しませんが)を抽出しますが、これに失敗した場合にはエラーダイアログを出して終了させます。

<body>要素を抽出したら、続いてその子要素を先頭から順に見ていきます。

  1. 先ず、id="TOP"属性を持つ要素までスキップします。
  2. スキップしたら、今度はid="TO_TOP"属性を持つ要素までをcanvas ノードに追加します(但し、class属性に noAjax が含まれている要素はスキップします)。

    このとき、取得したXHTML文書は、コードを埋め込んでいるHTML文書とは別文書である事を忘れてはいけません。従って、canvas.appendChild(e[i]) でcanvasノードにXHTML文書のノードを追加する事は出来ません。

    このため、併用している HTTPRequest.js 内にある appendOthersNode() 函数を用いてcanvasノードに追加して行きます。

  3. 抽出が終わったら、今度は元の状態に戻すアンカーを附加します。これはコードを埋め込んでいるHTML文書にも取得したXHTML文書にもないものなので、要素ノードを一つずつ追加して行きます。
  4. これで表示用要素ノードの準備が整いましたので、最後に表示用ノードのスタイルを調整します。これは一つずつスタイルプロパティを与えていくだけですが、画面や文書の要素の大きさなどをスクリプトで取得してそれを基にした値を与えていきます。また、インターネットエクスプローラ 6.0まででは、position: fixed;プロパティに対応していないので、スクロールに合わせて表示位置を決める事になります。

表示を消す処理。

さて、指定されたサムネールのアンカーをクリックすると、リンク先のHTML文書に対応するXHTML文書が取得され、それから重要な要素のみが抜き取られて画面に表示されるようになりましたが、何時までも表示しっ放しと言う訳にも行きません。

そのため、表示処理では閲覧者が見終わったら元の状態に戻せるようにアンカーを仕掛けておりますが、そのアンカーをクリックされたときに実行されるcloseCanvas() 函数では、表示用の要素ノードと画面を暗くするための要素ノードをスタイル操作で非表示にしております。

しらぎくのウェブサイト作成入門サイトマップ



marguerite.site@gmail.com