[Labyrinthe Noir]>[Top]>[こども工作教室]>

「キッチンタイマー」のソースと解説

プログラムの説明

任意の秒数から0秒までカウントダウンするタイマーです。
最終的には時間指定をするボタンを組み込みます。

保存ファイルの準備

メモ帳などテキストエディタに基本のHTMLを記入します。
ファイル名は「ktimer.html」で保存します。

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>キッチンタイマー</title> </head> <body> <h3>キッチンタイマー</h3> <hr>
</body> </html>

表示フォームの作成

タイマーのカウントを表示するテキストフィールドとスタートボタンをフォームに置きます。

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>キッチンタイマー</title> </head> <body> <h3>キッチンタイマー</h3> <hr> <form name="ktimer"> <input type="text" name="counter" size="10"> <input type="button" name="b_start" size="10" value="スタート">
</form>
</body> </html>

フォーム、テキストフィールド、ボタンにはそれぞれ名前を付けておきます。

カウントダウンを実行(1)

スクリプトを書き始めましょう。

</form>

<script type="text/javascript">
//初期設定
def_count = 60;
document.ktimer.counter.value = def_count;

function count_start() {
	//カウント開始
	count = document.ktimer.counter.value;
	timerID = setInterval('countdown()',1000);
}

function countdown() {
	//カウント表示
	count--;
	document.ktimer.counter.value = count;	
}
</script>
</body>
</html>

まず、初期設定において、標準値として変数def_countで最初の表示秒数を決定します。
これは一旦フォームへ表示しますが、後でフォームを書き換えて使えるようにします。

ユーザー関数count_startには、スタートボタンを押した後の動きを記述します。
フォームから変数countに数値を取得します。
次にsetInterval命令でユーザー関数countdownを1秒毎に呼び出してタイマーを起動します。

timerIDは変数で、タイマーが起動したときに割り当てられる数値が入っています。

ユーザー関数countdownでは、変数countを1減らしてフォームに表示します。

カウントダウンを実行(2)

<form name="ktimer">
<input type="text" name="counter" size="10">
<input type="button" name="b_start" size="10" value="スタート" onClick="count_start()">
</form>

スタートボタンにonClickでユーザー関数count_startを呼び出して、カウントダウンを開始します。

カウントダウンの停止

この時点ではカウントは停止しませんので、ユーザー関数countdownにおいて、変数countが0以下になったらタイマーを止めることにします。

function countdown() {
	//カウント表示
	count--;
	document.ktimer.counter.value = count;
	if (count <= 0) {
		count_stop();
	}
}

function count_stop() {
	//カウント停止
	clearInterval(timerID);
}

ユーザー関数countdownにif文を追加します。
変数countが0になり、表示がされた後に、ユーザー関数count_stopを呼び出しています。
0以下としているのは、タイマーが二重起動するなどのトラブルを想定し、0を飛び越えても止まるようにしておきます。

実際にこの時点では、スタートボタンを押すと複数のタイマーが起動するため、タイマーは0でも止まらなくなります。

ユーザー関数count_stopではclearInterval命令でタイマーを止めています。
このとき、変数timerIDを指定しています。この中には起動時に受け取ったタイマーの識別番号が入っており、複数のタイマーが起動すると、それぞれ違う番号になります。

現時点では複数のタイマーを起動すると正常に動作しません。
変数timerIDには最後のタイマーの番号だけが残っています。

タイマーの初期化

カウントが0で止まった後、初期状態に戻します。

//初期設定
def_count = 60;

timer_reset();

function timer_reset() {
	//タイマーの初期化
	document.ktimer.counter.value = def_count;
}

function count_stop() {
	//カウント停止
	clearInterval(timerID);
	timer_reset();
}

ユーザー関数timer_reset()を作って、その中に初期設定からフォームに関数def_countを設定する一行を移動します。

初期設定の最後でユーザー関数timer_resetを呼び出します。
関数def_countは移動させずに残しておきます。
初期値を設定する関数はできるだけスクリプトの最初に置いてある方がメンテナンスが簡単です。

タイマーのテストをする時は、関数def_countの値を小さくするなどして、テストの時間を短くしましょう。

ユーザー関数count_stopには、タイマー停止の次に、ユーザー関数timer_resetの呼び出しを行います。これで、タイマーの初期化ができます。

タイマーの二重起動を防ぐ(1)

現時点では、スタートボタンを押すと、その数だけタイマーが起動し、同時にカウントダウンを行います。
そのため、3つタイマーが起動すると1秒間に3つもカウントが減ります。
そこで、カウントが始まるとカウントボタンを押せないようにして、二重起動を防ぐことにします。

function timer_reset() {
	//タイマーの初期化
	document.ktimer.counter.value = def_count;
	document.ktimer.b_start.disabled = false;
}

function count_start() {
	//カウント開始
	count = document.ktimer.counter.value;
	document.ktimer.b_start.disabled = true;
	timerID = setInterval('countdown()',1000);
}

まずは、ユーザー関数count_startで、ボタンを使用禁止にします。使用禁止はプロパティdisabledに対してtrueの値を入れてやると設定されます。

次に、ユーザーtimer_reset内で禁止の解除を行います。

ボタンの使用禁止解除は、ユーザー関数count_stop内に記述しても良いのですが、更新ボタンが押されるようなことがあると、ブラウザによってはボタンが使えなくなることがあるため、初期設定後に必ず実行される位置に置くことにします。

【この時点の ktimer.html を別枠で表示】

タイマーのリセットボタン

カウントが終了するとタイマーが自動的に初期化されますが、ボタンでいつもで初期化(リセット)できるようにしましょう。

<form name="ktimer">
<input type="text" name="counter" size="10">
<input type="button" name="b_start" size="10" value="スタート" onClick="count_start()">
<input type="button" name="b_reset" size="10" value="リセット" onClick="count_stop()">
</form>

フォームにリセットボタンを足します。onClickからユーザー関数count_stopを呼び出せばタイマーを停止して、初期化が実行されます。

規定時間の設定(1)

任意の数字をテキストフィールドに入力すると、そこからカウントダウンが始まります。
しかし、よく使われる時間についてはその手間を省くことも重要です。
そこで、ボタンを押すと自動的にカウントがセットされて、タイマーが起動するようにしましょう。

<form name="ktimer">
<input type="text" name="counter" size="10">
<input type="button" name="b_start" size="10" value="スタート" onClick="count_start()">
<input type="button" name="b_reset" size="10" value="リセット" onClick="count_stop()">
<input type="button" size="10" value="3分" onClick="set_timer(180)">
<input type="button" size="10" value="5分" onClick="set_timer(300)">
</form>

まずは、フォームに2つのボタンを設置します。name属性はなくても良いでしょう。表示は3分と5分ですが、秒数では180秒と300秒です。
onClickからユーザー関数set_timerを呼び出し、同時に秒数を値として渡します。

規定時間の設定(2)

function set_timer(num) {
	//規定時間の設定
	document.ktimer.counter.value = num;
	count_start();
}

ユーザー関数set_timerでは、関数numで値を受け取ります。

受け取った値はフォームに表示し、ユーザー関数count_startを実行してカウントを始めます。

タイマーの二重起動を防ぐ(2)

このままでは、規定時間のボタンを何度も押すことができますので、ここでもタイマーの二重起動の対策が必要です。

function timer_reset() {
	//タイマーの初期化
	timerID = 0;
	document.ktimer.counter.value = def_count;
	document.ktimer.b_start.disabled = false;
}

function set_timer(num) {
	//規定時間の設定
	if (timerID > 0) {
		count_stop();
	}
	document.ktimer.counter.value = num;
	count_start();
}

今度は変数timerIDを利用しましょう。

まずは、ユーザー関数timer_resetの中で変数timerIDの初期値を0とします。これがタイマーが動いてない状態となります。

次に、ユーザー関数set_timerでタイマーが起動しているとき、すなわち変数timerIDが0より大きいときにユーザー関数count_stopを呼び出してタイマーを止めます。

ユーザー関数set_timerにおいて、変数timerIDをif文で調べるため、それ以前に初期値を設定しておかないとエラーが発生します。
また、タイマー起動後は値が設定されますが、停止後も値がそのままだと、if文が無意味となるため、変数timerIDの初期化は必須となっています。

【この時点の ktimer.html を別枠で表示】

「分:秒」の表示(1)

カウントの表示を秒だけの表示から、分と秒の表示に変更します。その方がより判りやすくなるでしょう。

function countdown() {
	//カウント表示
	count--;
	document.ktimer.counter.value = count_format(count);
	if (count <= 0) {
		count_stop();
	}
}

function count_format(num) {
	//カウント表示の書式設定
	var tm,ts;
	tm = Math.floor(num / 60); //分
	ts = num % 60; //秒
	return tm + ":" + ts;
}

表示の書式をユーザー変数で処理しましょう。
秒数を受け取り、分と秒に分けた後、「:」で区切って書式の設定された文字列として値を返します。

ユーザー関数count_formatを記述し、秒数を受け取るため、変数numを用意します。
最初に2つの変数をローカル宣言します。tmとtsです。
次に、変数numから分数を取り出して変数tmに入れます。秒数を60で割って小数点以下を切り捨てています。
その次には、変数numから秒数を取り出すために、60で割ったときの余りを変数tsに入れています。
そして、最後に変数tmと変数tsを「:」で区切って書式を整え、戻り値としています。

ローカル宣言された変数をローカル変数と言います。
この変数はその宣言されたユーザー関数の中でのみ有効となり、それ以外に同じ名前の変数があったとしても、お互いに影響を与えません。

計算式にある「%」は、割り算した余りを計算するという意味です。

ユーザー関数からの戻り値がどこに戻るかというと、呼び出した位置になります。
そこで、今まで秒数を出力していた位置からユーザー関数を呼び出すと、代わりの値が戻って表示されるという仕組みです。

ユーザー関数countdownの中で変数countを出力していますので、その時点で書式を整えて表示を行います。
このようにユーザー関数の呼び出しは式の中で使用することが可能です。

「分:秒」の表示(2)

さて、このままでは1つ問題が発生します。
秒数が一桁の場合、「0:5」のような表示になります。これを「0:05」となるようにして、表示の位置を調整しましょう。

function count_format(num) {
	//カウント表示の書式設定
	var tm,ts;
	tm = Math.floor(num / 60); //分
	ts = num % 60; //秒
	if (ts < 10) ts = "0" + ts;
	return tm + ":" + ts;
}

if文を入れて、変数tsが10より小さいとき、変数tsの頭に文字列の「0」を付け足す式を記述します。

「"」で囲われた部分は文字列の意味を持つため、例え数字であっても文字列となります。
文字列と数字を「+」で接続すると、全体は文字列として扱われます。
そのため、「05」は「5」という数値ではないことになるのです。
「0+5」は「5」という数値ですが、「"0"+"5"」は「05」という文字列だという大きな違いがあるのです。

変数に入っているのが数値か文字列かは、自動的に式の中で判別されます。
しかし、関数を使用する場合には、数値のところに文字列を入れるとエラーが発生する原因となるので、注意が必要です。

フォームの送信を防ぐ

フォーム内に送信ボタンはありませんが、テキストフィールド内にカーソルがある場合にエンターキーを押すとフォームが送信されてしまいます。
送信先は指定されていませんので、このHTMLファイルに対してフォームが送信されます。そうすると再読込(更新)と同じでまたフォームの内容が初期化されてしまいます。

そこで、そのような誤送信を防ぐため、<form>タグに送信時に処理を中断させる記述をします。

<form name="ktimer" onSubmit="return false;">
<input type="text" name="counter" size="10">
<input type="button" name="b_start" size="10" value="スタート" onClick="count_start()">
<input type="button" name="b_reset" size="10" value="リセット" onClick="count_stop()">
<input type="button" size="10" value="3分" onClick="set_timer(180)">
<input type="button" size="10" value="5分" onClick="set_timer(300)">
</form>

onSubmitが送信のイベントが発生した場合の処理です。内容はfalseを返信することで、処理を中止させるのです。

完成

【この時点の ktimer.html を別枠で表示】

規定時間のボタンは自由に増やすことができます。
また、全体的にレイアウトを整えて、使いやすくしたいところです。

戻る