この記事は公開または最後に更新されてから2122日が経過しています。情報が古くなっている可能性があるのでご注意下さい。

この画像サイトを作りたかった理由の一つに、アップした画像のスライドショーを観たいという事があったので、これはなんとしても外せない機能なのです。
スライドショーに関してもプラグインが数多くありそうなのですが、モニター表示領域に可能な限り大きく、そしてアップしてあるすべての画像を対象にするとなると、どれで可能なのかはなかなか探しても見つかりませんでした。

javascript を使えば画像の切り替えに関しては簡単なことですが、私のレベルで考えて難しいのはアップしてある画像のURLをいかにして取得するかというところです。javascript からmysql にアクセスするにはなんにせよphpを経由しないとできないはずだし。

無い知恵を絞りだした目論見は、事前にphp にて画像ファイルのリストをxml として作成しておいて、そのxmlのファイルをjavascriptAjax1]にて読み込んで配列に格納し、発生させた乱数をその配列の添え字として画像のURLを取得して画像を切り替えようというものです。

作成する画像リストのxml1]はwordpress2]のデータベースを使うことなく、phpscandir関数 でファイル名を配列に取得します。この方法だとwordpress のデータベースを利用しないので投稿の状態を参照することは出来ず、まだ予約状態の投稿の分もリストされます。データベースを介してリストを作成するよりもこの方法のほうがサーバーにかかる負荷が少ないのではと思ったのですが。なにせ今や13,000枚以上の画像ファイルが存在します。それに私の場合は公開前の投稿分の画像も含めてスライドショーしたほうがよいのでこのほうが良かったのです。

このxml1]を作成する関数は投稿の公開の時に、バックグラウンドで動かせばいいでしょう。
で、作ったコードは以下の通り。

<?php
function imagefile_to_xml(){
	$tmpstr=array();
	$tmpstr[]='<?xml version="1.0" encoding="UTF-8" ?>';
	$tmpstr[]='<files>';
	$xmlfile="./wp-content/~/ilist.xml";
	
	$dirname="./wp-content/uploads/";
	
	$filearrayasc=scandir($dirname);

	$i=0;
	$fcount=0;
	
	foreach($filearrayasc as $val){
		if(mb_strpos($val,"20")!==false){
			$cdir=$dirname.$val."/";
			$cfile=scandir($cdir);
			foreach($cfile as $data){
				if($data!=="." and $data!==".."){
					$gcdir=$cdir.$data."/";
					$gcfile=scandir($gcdir);
					foreach($gcfile as $fname){
						if($fname!=="." and $fname!==".." and mb_strpos($fname,"x")===FALSE){
							$imgname=$gcdir.$fname;
							$imgname=str_replace("/home/users/1/main.jp-strix/web/","./",$imgname);
							$tmpstr[]="<imgs>".$imgname."</imgs>\n";
							$fcount+=1;
						}
					}
					
				}
			}
		}
	}
	
	$tmpstr[]="</files>\n";
	file_put_contents($xmlfile,$tmpstr,LOCK_EX);
}

add_action('publish_post','imagefile_to_xml');
?>
PHP
CopyExpand

投稿の公開の時のアクションフックはpublish_post です。
6行目で生成する xml ファイルの指定、8行目で画像のアップロードディレクトリの指定をしています。
この場合はwordpress のインストールディレクトリからの相対バスにて指定していますが、サーバーの環境によってはフルパスでないとダメな場合もあるかもしれません。
フルパスは <?php phpinfo(); ?> を書いたphpファイルをアップして実行すれば、その下の方に表示される「Environment」の「DOCUMENT_ROOT 」の項目に表示されます。 16行目においてuploads/ ディレクトリで、画像をアップロードしてあるディレクトリ名には、2012 のようにアップした年のディレクトリ名になっていますからそれを判別しています。プラグイン等の具合によっては画像とは関係のないディレクトリも存在している可能性があります。

実は一度プラグインというものを作ってみたかったので、私の場合はこれをプラグインにして使用していますがfunction.php 内に記述しても同じだと思います。
この関数によって生成される超シンプルなxml は以下のようになります。

<?xml version="1.0" encoding="UTF-8" ?>
<files>
<imgs>./wp-content/uploads/2011/10/0911085193.jpg</imgs>
<imgs>./wp-content/uploads/2011/10/0911085212.jpg</imgs>
<imgs>./wp-content/uploads/2011/10/0911085214.jpg</imgs>
<imgs>./wp-content/uploads/2011/10/0911085219.jpg</imgs>
<imgs>./wp-content/uploads/2011/10/0911085233.jpg</imgs>
<imgs>./wp-content/uploads/2011/10/0911085354.jpg</imgs>
<imgs>./wp-content/uploads/2012/02/1202194470.jpg</imgs>
</files>
XML
CopyExpand

次にこの xml ファイルを javascript に読みこむ処理を作らないといけないのですが、これらの関数に関しては手持ちの書籍ではなく、ネットから探し出してきたものだと思いますが出所がどこかは忘れてしまいました。
xml ファイルを読み込んでスライドショーの処理を行う関数に続く、一連の javascript を次のように作りました。

スライドショーを実行させるにおいて、いくつかの機能を持たせました。
今、何枚目の画像か、画像のurlを格納した配列 imagesStr の添え字、画像のファイル名、何秒毎か、あと何秒で切り替わるかというカウントダウンなどの表示とスライドショーのstop、pause、restart、stop&backのjavascriptへのリンクです。
これらのための複数の関数で値を持ちまわるためにいくつかグローバル変数を使用しています。

  • var imagesStr=new Array();3]xmlから読み出した画像のurlを格納するための配列
  • var img01=new Image();3]次の画像を先読みさせるための変数
  • var pastimg=new Array();3]表示した画像を戻って表示させるための既出の画像番号を順番に格納するための配列
  • var backnum=2;3]戻って表示するときにいくつ戻っているかのカウント
  • var tarlist=new Array();3]既に表示されたか否かのフラグでimagesStrの添え字に対応
  • var tarnum;3]乱数で得られた表示する画像の番号でimagesStrの添え字にて使用
  • var sumnum=1;3]表示した画像の枚数

2015/11/14 追記: ふと気が付いてみると下記のXMLHttpRequest の方法では、現在のFireFox では、ちゃんと動いてくれていない。どんなにファイルを更新しても読み込むのはブラウザがキャッシュしている古いデータのままのようです。ちなみにFireFox のバージョンは42.0 です。
色々と試してみて、GET ではなく POST で送信すればその問題は解決できる。そう、GET で送信されたものはキャッシュされるのですが、キャッシュされないようにする記述もしてあるのですが。
と、いう事でPOST に書き直したものがこの下にあります。

var imagesStr=new Array();
var img01=new Image();
var pastimg=new Array();
var backnum=2;
var tarlist=new Array();
var tarnum;
var sumnum=1;

function createHttpRequest() {
	var x = null;

	//IE7,Firefox, Safari
	if (window.XMLHttpRequest) {
		return new XMLHttpRequest();
	}

	//IE6
	try {
		return new ActiveXObject("Msxml2.XMLHTTP");
	} catch(e) {
		// IE5
		try {
			return new ActiveXObject("Microsoft.XMLHTTP");
		} catch(e) {
			x = null;
		}
	}
	return x;
}
JavaScript
CopyExpand

createHttpRequest関数は次の requestFile 関数から呼び出されます。ブラウザの互換性を考慮したものと思われます。

function requestFile(fileName){
	var xmlHttpReq=createHttpRequest();

	xmlHttpReq.open("GET",fileName,true);
	xmlHttpReq.setRequestHeader('Pragma','no-cache');
	xmlHttpReq.setRequestHeader('Cache-Control','no-cache');
	xmlHttpReq.setRequestHeader('If-Modified-Since','Thu, 01 Jun 1970 00:00:00 GMT');

	xmlHttpReq.onreadystatechange=function(){
		if(xmlHttpReq.readyState==4){
			var xmlData=xmlHttpReq.responseXML;
	
			/*読み込んだxmlのデータから<imgs>タグのデータ(画像のurl)だけを配列で取得*/
			var userData=xmlData.getElementsByTagName("imgs");
	
			for(var i=0;i<userData.length;i++){
				/*画像のurlをグローバル変数のimagesStrに配列で格納*/
				imagesStr[i]=userData[i].childNodes[0].nodeValue;
				/*同じ画像を2度表示させないために表示させたフラグをimagesStrの添え字に対応させた配列を作り値を1で初期化*/
				tarlist[i]=1;
			}
	
			/*0から100000000までの乱数を発生させ画像の個数で割った余りを表示する画像の番号としてimagesStrの添え字として指定します*/
			var rand=Math.floor(Math.random()*100000000);
			tarnum=rand%userData.length;
			/*一度表示した画像のフラグを-1に置き換えます*/
			tarlist.splice(tarnum,1,-1);
	
			imgsrc=imagesStr[tarnum];
			/*次に表示させる画像を先読みさせる処理なので後でよさそうですが後にすると動かなくなってしまいます*/
			img01.src=imgsrc;
	
			rand=Math.floor(Math.random()*100000000);
			tarnum=rand%userData.length;
			tarlist.splice(tarnum,1,-1);
	
			var doc=document;
	
			/*フォームにて指定した画像を切り替える間隔の秒数を変数に代入*/
			var timenum=doc.getElementById("intnum").value;
			/*指定した間隔の秒数が5秒より短い、または50秒より長いときは強制的に10秒に指定*/
			if(timenum<5||timenum>50){
				timenum=10;
			}
	
			/*切り替えの秒数と画像の情報の表示の更新*/
			doc.getElementById("slctdown").innerHTML="last"+timenum+"seconds";
			doc.getElementById("slidecount").innerHTML=sumnum+":"+tarnum+":"+imgsrc.substring(imgsrc.indexOf("20",20))+":int."+timenum+"sec";
			var ctdownnum=timenum;
			var callnum=timenum*1000;
	
			imgsrc=imagesStr[tarnum];
			doc.getElementById("explain").style.visibility="hidden";
			/*一枚目の表示はshowpop関数を使って表示*/
			showpop(imgsrc);
			doc.getElementById("slidestop").style.visibility="visible";
			pastimg[0]=0;
			pastimg.unshift(0);
			pastimg.unshift(tarnum);
			/*画像を表示している隠しdivがどの関数から呼ばれて表示されているかを判別するフラグでグローバル変数*/
			flmflg=2;
	
			/*秒数のカウントダウンを表示する関数を1秒後に呼び出し*/
			setTimeout("sldcountdown('"+ctdownnum+"')",1000);
			/*スライドショー本家の関数に引き継ぎ*/
			setTimeout("slideimg('"+timenum+"')",callnum);
		}
	}

	xmlHttpReq.send(null)
}
JavaScript
CopyExpand

createHttpRequest requestFile関数が xml を読み込むための Ajax の処理で、ネット上から拾ってきたものです。requestFile 関数は xml ファイルから画像の url のリストを読み込み、画像の url を格納したグローバル変数の配列を生成し、一枚目の画像を表示して二枚目の画像を先読みしたあとスライドショー本元の関数 slideimg 関数に引き継ぎます。

2015/11/14 追記:上のXMLHttpRequest をPOST で書き直したもの

function requestFile( fileName ) {

	var xhr = new XMLHttpRequest();
	var senddata = 'post xml';
	xhr.open( 'POST', fileName );
	xhr.send( senddata );
	xhr.onreadystatechange = function(){
		if ( 4 === xhr.readyState && 200 === xhr.status ) {

			//読み込むファイルがxmlの時はこれを使用
			var xmlData = xhr.responseXML;
			var userData = xmlData.getElementsByTagName( 'imgs' );
			for ( var i = 0; i<userData.length; i++ ) {
				imagesStr[ i ] = userData[ i ].childNodes[0].nodeValue;
				tarlist[ i ] = 1;
			}

			//読み込むファイルがテキストファイルの時は下記を使用
			/*var userData = xhr.responseText;
			var arrData = userData.split( ',' );
			var j = 0;
			for ( var i = 0; i < arrData.length; i++ ) {
				if ( arrData[ i ].length > 5 ) {
					imagesStr[ j ] = arrData[ i ];
					tarlist[ j ] = 1;
					j++;
				}
			}*/

			/*乱数を発生させるところから後は同じ*/
}
JavaScript
CopyExpand

なんにしてもこちらの方がシンプルですっきりしていていい。今のIE であれば上記のcreateHttpRequest() のような関数ももう必要ないし。
読み込むファイルは xml でも良いし、それに限る必要も無くただのドット区切りのテキストファイルでも良い。その方がデータ量がぐっと少なく出来てより良いと思われます。
↑ここまで

function slideimg(intervalnum){
	var doc=document;
	var imgsrc;
	var timenum=intervalnum;
	
	/*先読みさせていた画像を表示*/
	imgsrc=img01.src;
	doc.getElementById("upimage").src =imgsrc;
	sumnum+=1;
	
	/*切り替えの秒数と画像の情報の表示の更新*/
	doc.getElementById("slctdown").innerHTML="last "+timenum+" seconds";
	doc.getElementById("slidecount").innerHTML=sumnum+" : "+tarnum+" : "+imgsrc.substring(imgsrc.indexOf("20",20))+" : int."+timenum+" sec";
	var ctdownnum=timenum;
	var callnum=timenum*1000;

	/*次の画像のための番号をつくります*/
	var knum=0;
	var tarflg;
	var knum=0;
	var tarflg;
	while(knum<3){
		tarflg=0;
		var nowday=new Date();
		var nowsecond=nowday.getSeconds();
		/*乱数をよりユニークな数にするために秒数をかけてみました*/
		var rand = Math.floor((Math.random()*100000000))*nowsecond;
		tarnum=rand % imagesStr.length;
		/*一度表示した画像番号にならないように配列tarlistのフラグで検証し、3回まで作り直します*/
		if(tarlist[tarnum]==-1){
		tarflg=1;
	}
	if(tarflg==0){break;}
		knum+=1;
	}
	var lastflg=0;
	/*3回作っても既出でない番号を作れなかったときはtarlistの中から未使用の番号を最後から順に探し出して使用します。*/
	if(tarflg==1){
		lastflg=1;
		for(var i=tarlist.length-1;i>=0;i--){
			if(tarlist[i]!=-1){
				tarnum=i;
				lastflg=2;
				break;
			}
		}
	}
	/*それでも無い場合は全ての画像を表示したということなのでtarlistの値を全て1に初期化します*/
	if(lastflg==1){
		for(var i=0;i<tarlist.length;i++){
			tarlist[i]=1;
		}
	}
	tarlist.splice(tarnum,1,-1);


	/*次の画像を先読みさせます*/
	var tmpimg;
	tmpimg=imagesStr[tarnum];
	img01.src=tmpimg;

	/*戻る表示の時のために表示した画像の番号を配列に格納していきます*/
	pastimg.unshift(tarnum);
	/*画像の履歴が50以上になったら配列の末から一つづつ削除します*/
	if(pastimg.length>50){
		var kuzu=pastimg.pop();
	}
	setTimeout("sldcountdown('"+ctdownnum+"')",1000);
	timeId=setTimeout("slideimg('"+timenum+"')",callnum);
}
JavaScript
CopyExpand

で、stop、pause、restart、back、countdownなどの機能のための javascript

function stopslide(){
	var doc=document;
	clearTimeout(timeId);
	clearTimeout(sldctId);
	sumnum=1;
	doc.getElementById("slidecount").innerHTML="";
	doc.getElementById("slidestop").style.visibility="hidden";
	erasepop();
}

function pauseslide(){
	var doc=document;
	clearTimeout(timeId);
	clearTimeout(sldctId);
	doc.getElementById("slctdown").innerHTML="nowpausing";
	doc.getElementById("sldrestart").style.visibility="visible";
}

function resldstart(){
	var doc=document;
	backnum=2;

	var timenum=doc.getElementById("intnum").value;
	if(timenum<5 || timenum>50){
		timenum=10;
	}
	slideimg(timenum);
	doc.getElementById("slctdown").innerHTML="";
	doc.getElementById("sldrestart").style.visibility = "hidden";
}

function backslide(){
	var doc=document;

	clearTimeout(timeId);
	clearTimeout(sldctId);
	doc.getElementById("slctdown").innerHTML="";

	doc.getElementById("sldrestart").style.visibility = "visible";

	var tmpimg;
	var tmpnum=pastimg[backnum];
	tmpimg=imagesStr[tmpnum];
	doc.getElementById("upimage").src =tmpimg;
	doc.getElementById("slidecount").innerHTML="stop & back : -"+backnum+" : "+tmpimg.substring(tmpimg.indexOf("20",20));
	backnum+=1;
}

function sldcountdown(slctnum){
	var secnum=slctnum;
	secnum-=1;
  
	document.getElementById("slctdown").innerHTML="last "+secnum+" seconds";
	if(secnum>1){
		sldctId=setTimeout("sldcountdown('"+secnum+"')",1000);   
	}
}
JavaScript
CopyExpand

stopslide 関数において画像表示用の div を閉じる処理はここの初めの記事画像クリック時のjavascript erasepop 関数を使っています。ちなみに requestFiled 関数で一枚目の画像を表示するのに使用した showpop 関数は上と同じ記事と改良したものが画像をクリックした時のログの記事にあります。

このスライドショーの呼び出しはリンクなら <a href="javascript:requestFile('./wp-content/***/ilist.xml')"> という書式になります。 xml のパスは省略してあります。
最後に画像表示用の隠しdivのhtmlも載せておきます。

<div id="imageframe">
	<p id="explain">画像をクリックすると元に戻ります。</p>
	<div id="popup"><a href="JavaScript:erasepop()"><img src="" id="upimage" name="upimage" alt="" /></a></div>
	<div id="slidestop">
		<div id="slidecount"></div>
		<div id="slidecom">
			<a href="Javascript:stopslide()">stop slide show</a>&emsp;&emsp;
			<a href="Javascript:pauseslide()">pause</a>&emsp;&emsp;
			<a href="Javascript:resldstart()" id="sldrestart">restart</a>&emsp;&emsp;
			<a href="Javascript:backslide()">stop & back</a>&emsp;&emsp;
			<div id="slctdown"></div>
		</div>
	</div> 
</div>
HTML
CopyExpand

と、いう具合にしています。このdivのcssにおいて visibility hidden position absolute z-index は最前の値にしないと意味がありません。

このスライドショーのプログラムにおいては、 javascript の乱数を使っているわけですが、はじめに作った基本的な動作だけのコードでは、どうしても同じ画像ばかりが表示される傾向にあって、二度表示されないようにするために少し工夫が必要でした。
そのための手段が画像のurlを格納した配列 imagesStr と添え字の番号が同じ番号までの添え字を持つ配列を作り、その配列のそれぞれの値をフラグにして既出か否かを判別させるということをしました。 requestFile 関数の22行目で作られる tarlist という配列がそれにあたります。これによりひとまわりするまでは同じ画像が2度表示されることはなくなりました。

尚、同じ requestFile 関数の63行目に突然出てくる flmflg という変数はグローバル変数で宣言してあり、隠し div がなにから表示されたものかを判別するフラグとして使用しています。
というのは続、画像クリック時のjavascriptの記事内のスクロールが発生した時の関数、 onScroll 関数において画像表示用のdivが表示されている場合は再び隠す処理が実行されますが、その時呼び出すのが erasepop 関数か stopslide 関数かを判別させるためのものです。
スライドショーを実装した以後の onScroll 関数は以下のように最後の部分を変更してあります。が、さらに言及しますと現在のところスライドショーを設置してあるimages viewerのページにはスクロールサイドバーは使用していないので、このページにおける onScroll 関数の処理は画像表示用のdivを閉じる26~30行目までだけの記述となっています。

function onScroll(evt){
	var preposi;
	var movposi;
	var posistr;
	var doc=document;
	var numscroll = getScrollPosY();


	if(numscroll>2000){
		doc.getElementById("blind").style.visibility="visible";
		doc.getElementById("mnavi").style.visibility="visible";
	}
	if(numscroll>3000){
		doc.getElementById("bpict").style.visibility="visible";
	}

	preposi=2200;
	movposi=numscroll-50;

	if(movposi<preposi){
		movposi=2200;
	}
	
	doc.getElementById("mnavi").style.top=movposi + "px";
	
	if(flmflg==1){
		erasepop();
	}else if(flmflg==2){
		stopslide();
	}
}
JavaScript
CopyExpand

サイト内でこのスライドショーはimages viewerのページのサイドバーの一番下に設置してあります。

この記事を書くにあたって自分の作ったコードを改めてしげしげと見直した訳ですが、ここでなぜこういうことをやっているのだろうかという不合理な部分が数多くあって手直しするいい機会となりました。
随分と直しましたが私のサイトでは動いているので大丈夫のはずです。

2013年3月22日追加
画像を次々と見たい場合は余計なエフェクトなど必要無いと思うのですが、スライドショーにおいてはただ切り替わるだけではなんとなく味気ないように思えてきました。 そこで、fadeout + fadein のエフェクトを加える事に。
スライドショーにフェイドイン+フェイドアウトにて。

Leave a Reply!

JavaScript is necessary to send a comment.
You can edit and delete your comment if you input a edit key.
Edit key is necessary for attesting you when you edit and delete it.
The tag of HTML cannot be used in comment.
When you comment for the first time, it is displayed after the approval of the administrator.
Because I cannot speak English so much, it takes time to answer.
Required fields are marked *.

※Please enter more than 5 characters only alphabets.
※Edit or delete are possible for 2000 days after approval.

*

♠Simplistic Comment User Editable v4.0

♠When visitors leave comments on the site this site collect the data shown in the comments form, and also the visitor’s IP address and browser user agent string to help spam detection.
♠This site does not use cookie when visitors leave comments and commenter edit comment.
♠This site uses Akismet to reduce spam. Learn how your comment data is processed.

Comments feed

Trackback URL : https://strix.main.jp/wp-trackback.php?p=16578

Sanbanse Funabashi
2011.01.01 sunrise

Top

スクロールさせるか画像をクリックすると元に戻ります。