nanmaida.com⇒ JS手習

JS手習

BLINKINGを関数で作る

1 動作を関数にしてみた

ロードされて開始、マウスオーバーで停止

とりあえず素材をつくり、ファイル名の末尾に半角数字で番号づけ

new200000000_1~6.png

new204000255_1~3.png

new255000000_1~7.png

そしてjavascript作成

① 画像取得、② 画像のソース(ファイル名)を変える(+1 して最後までいったら戻る)、③ ②を繰り返す、④ そして③をいつ始めいつ終わらせるかを決める。ということならば、画像ファイルとその数、HTML要素、時間の間隔、どのように始まりどのように終わるかを引数にすればよいだろうか。このような感じで次が出来上がった。

						
<img id="new_1" style="width:100px;" class="centering">
<script>

	function serialImg(intervalT, endT, noStart, noEnd, srcURI, kakuchoshi, imgid){
/*
引数はそれぞれ、 arguments[0] 間隔 arguments[1] 継続時間(終了時間) arguments[2] 画像ファイルの連番の開始値 arguments[3] 画像ファイルの終了値 arguments[4] 画像ファイルの連番の左に付加する文字列 arguments[5] 画像ファイルの連番の右に付加する文字列 arguments[6] HTML要素のid
*/ if((noStart)&&(noEnd)&&(srcURI)&&(kakuchoshi)){ myNum = noStart; myNumo = noStart; var myImg = []; var HDIMG = document.getElementById(imgid); for(var i = noStart; i <= noEnd; i++){ myImg[i] = document.createElement('img'); myImg[i].src = srcURI + i + kakuchoshi; }; //動作前にイメージデータなどを取得しておくのが定石らしい。 function imgChange(){ HDIMG.src = myImg[myNum].src; if(myNum < noEnd){ myNum = myNum + 1; } else { myNum =myNumo; }; }; var timer1 = setInterval(imgChange,intervalT); function intervaloff() { clearInterval(timer1); }; if(endT == "on"){ HDIMG.onmouseover = intervaloff;//mouseoverで終了 } else { if(endT){ var endTime = endT; } else { var endTime = 60000; };//それ以外は指定した時間あるいは60秒経過したら終了。 var timer2 = setTimeout(intervaloff,endTime); onload = timer2; }; onload = timer1; }; }; serialImg(153,"on",1,6,"new200000000_",".png","new_1"); </script>
				

以上ひとまず書いてはみたものの(H28年8月末)、使用して致命的な欠点に気付いた。
せっかく関数にしたにも関わらず、複数の要素に対して動作しない。
HTMLをあれこれ変えてみた結果、関数に原因があると結論した。自分の勉強が不十分なところは「タイマー」という変数だったのでそこに原因があるとすればどのような理由を考えることができるだろうか。複数の箇所でインターバルをおいて同名の関数が使われると、同名の変数も使われるがそれは問題がないだろうか。たぶんない。なぜならば { から } で閉じられた部分まで実施されて確かに変数に代入された値は変わるが、次の関数で適切な時に変数は初期化される。
”timer”は初期化されているのかな?これはsetInterval()を代入しているけれど、これは初期化とは違うだろうか?setInervalは一定の時間後一回仕事を行って、
timerに代入されるsetIntervalには”返り値”がある。それは文字列とか数値などの値ではなく、立派なオブジェクトである。
確かに代入後にtimer1;と書けば直ちに実行される。

2 複数の要素に別々のタイマーを設定した。

問題はおそらくタイマーの配列を宣言して、連想配列を使えば解決しそうに思われる。
配列は文字列なのか配列なのか明らかでない関数などを受けてくれるのだろうかという不安もあったが実際には動いていただけたようだ。



下記のblinking要素はマウスオーバーでそれぞれ停止する。



						
			<img id="new_2" style="width:50px;"> 
			<img id="new_3" style="width:50px;"> 
			<img id="new_4" style="width:50px;"> 
			<img id="new_5" style="width:50px;">
<script>
//2個以上の要素にserialImgが使用できなかった。
//その最初の答えがタイマーの記載の問題
//タイマーを連想配列として1関数ごとに変えてみたのが次の実験。

timer_alpha = new Array();
//タイマーαという配列を宣言

function serialimg2(intervalT, endT, noStart, noEnd, srcURI, kakuchoshi, imgid){
	if((noStart)&&(noEnd)&&(srcURI)&&(kakuchoshi)){
		var myNum = noStart;
		var myNumo = noStart;
		var myImg = [];
		var HDIMG = document.getElementById(imgid);

		for(var i = noStart; i <= noEnd; i++){
			myImg[i] = document.createElement('img');
			myImg[i].src = srcURI + i + kakuchoshi;
		};


		function imgChange(){
			HDIMG.src = myImg[myNum].src;
			if(myNum < noEnd){
				myNum = myNum + 1;
			} else {
				myNum =myNumo;
			};
		};

		timer_alpha[imgid] = setInterval(imgChange,intervalT);
//indexに要素のidを指定する。

		function intervaloff() {
			clearInterval(timer_alpha[imgid]);
		};
		
		if(endT == "on"){
			HDIMG.onmouseover = intervaloff;
		}
		else {
			if(endT){
				var endTime = endT;
			}
			else {
				var endTime = 60000;
			}
			setTimeout(intervaloff,endTime);
				}
		timer_alpha[imgid];
//「オンロードされた時」は「スクリプトが読まれた時」と同じ。スクリプトが読まれたときにタイマーは始まる。
	};
};
	serialimg2(152,"on",1,3,"new204000255_",".png","new_2");
	serialimg2(151,"on",1,3,"new204000255_",".png","new_3");
	serialimg2(72,"on",1,7,"new255000000_",".png","new_4");
	serialimg2(71,"on",1,7,"new255000000_",".png","new_5");
</script>
						
					
				

しかしそれでは満足できないことが生まれてしまった。この関数はロードされたタイミングでしか開始できないことである。
setIntervalとclearIntervalを意のままに発火させたいならばどうする?オライリーには何と書いてあるのか。そもそもイベントとはなんなのか。

3 そしてイベントリスナというものを知った

初心者というものはたいていこういうものではないだろうか。押したら動いた、うれしいな。しかしどうしてこういう書き方なのかな?難しいな。と
しかし塩漬け期間を経てから再度こうやって学習すると理解に至る。うれしいものじゃないか。
イベントは要素タグの中に
 onclick=""

またある時はプロパティとして
 myImg.onclick = …;

この二つはプロパティの記述法に似ている。どちらかを理解すれば両方理解したことになる。
ところがイベントリスナはその書き方が特異的なだけでなく、同一要素に複数のイベントを指定できるという機能を持っている。
これで意のままに発火できるということになる。2016年10月3日この実験終了。

ウォーミングア・プログラム トグルタイマー

0:0:0
OFF

ON-OFFにカーソルを乗せると動作するタイマー。厳密なタイマーではない。プログラムを動かす時間が加算される、それに加えて…

						
<table>
	<tr>
		<td id="ClockFace" style="font-size:30px;">0:0:0</td>
	</tr>
	<tr style="background-color:#ffaaaa;">
		<td id="ToggleButton" style="font-size:30px;">OFF</td>
	</tr>
</table>
<script>
	var Min = 0;var Sec = 0;var dSec = 0;
//タイマー表示ための変数初期化、Min、Sec、dSecは分、秒、0.1秒

	var clock_face = document.getElementById("ClockFace");
	var toggle_button = document.getElementById("ToggleButton");
//ClockFace、ToggleButtonを取得(セレクタとして登録)

//実行ごとに表示を加算していく関数を作成する。ある部分は60進法、ある部分は10進法。
	function amount_of_time (){
		clock_face.innerHTML = Min + ":" + Sec + ":" + dSec;
//ロードしたときは上記の初期値を代入して、0:0:0と表示。そして以下の加算関数に進む。
		if(Sec==59){
		Sec=0;Min=Min+1;
//秒における60進法。
		} else if(dSec==9){
			Sec=Sec+1;dSec=0;
//デシ秒における10進法。
		} else {
			dSec=dSec+1;
//繰り上がらないときはただdSecを0.1秒ごとに積み上げるだけ。
		};
	};
/*
amount_of_time関数で0.1秒ごとにclock face(時計の文字盤)を加えていく。
amount_of_time関数をToggleButtonのマウスオーバーで
中止、再開を切り替えることを意図して次の関数作成
*/

//トグルスイッチ
	var toggle = 0;
//トグル変数を宣言し初期化。
	function toGuru (){
//
	if(toggle ==0){
		toggle =1;
//まずトグルが0ならば1にしましょう。………①
	} else {
		toggle = 0;
//もし0以外ならば0としましょう。………②
	};
//ロードされた時はトグルは1になっている。
//あとは関数が実施されるごとにトグルは0、1が交互に切り替わる。
	if(toggle == 1){
		addtime = setInterval(amount_of_time, 100);//………③
//100ミリ秒ごとにamount_of_timeを実施。その返り値をaddtimeに代入。
	} else {
		clearInterval(addtime);//………④
//トグルが0ならばaddtimeをストップさせる。
	};
	OnOff = new Array; OnOff[0] ="OFF"; OnOff[1] ="ON";
	toggle_button.innerHTML = OnOff[toggle];
//トグルを表示。
};
/*
②までトグルの切り替え、④までトグルの値によりClockFaceの加算を進めるかあるいは止めるか決める。
トグル値を1(ON),0(OFF)表示。
*/
toggle_button.addEventListener("mouseover",toGuru,false);
//エベント追加:文字盤にマウスオーバーでtoGuru関数が1回実施される。
</script>
						
					
				


タイマーのトグルをもとにserialimg2を次のように変更した。

						
			<div class="centering">
				<img id="new_6" style="width:60px;"> 
				<img id="new_7" style="width:60px;"> 
				<img id="new_8" style="width:60px;"> 
				<img id="new_9" style="width:60px;">
			</div>

<script>

toGGle = new Array();
timer_beta =  new Array();

function serialimg3(intervalT, event, noStart, noEnd, srcURI, kakuchoshi, imgid){
	if((noStart)&&(noEnd)&&(srcURI)&&(kakuchoshi)){
/*
arguments[1] 動作を開始あるいは終了させるイベント
*/
		var myNum = noStart;
		var myNumo = noStart;
		var myImg = [];
		var HDIMG = document.getElementById(imgid);
		toGGle[imgid] = 1;

		for(var i = noStart; i <= noEnd; i++){
			myImg[i] = document.createElement('img');
			myImg[i].src = srcURI + i + kakuchoshi;
		};

		function imgChange(){
			HDIMG.src = myImg[myNum].src;
			if(myNum < noEnd){
				myNum = myNum + 1;
			} else {
				myNum =myNumo;
			};
		};

		function toggle_change(){
			if(toGGle[imgid] == 1){
				timer_beta[imgid]  = setInterval(imgChange,intervalT);
				toGGle[imgid] = 0;
			} else if((toGGle[imgid] == 0)){
				clearInterval(timer_beta[imgid]);
				toGGle[imgid] = 1;
			};
		};

	HDIMG.addEventListener(event,toggle_change,false);

	}
};

	serialimg3(152,"mouseover",1,3,"new204000255_",".png","new_6");
	serialimg3(151,"click",1,3,"new204000255_",".png","new_7");
	serialimg3(72,"mouseover",1,7,"new255000000_",".png","new_8");
	serialimg3(71,"dblclick",1,7,"new255000000_",".png","new_9");

</script>

						
					
				



左からマウスオーバー、クリック、マウスオーバー、ダブルクリックで開始/停止

iphoneでは別バージョン

結局見た目とてもシンプル。2016年10月4日BLINKINGの章