JavaScript - ストップウォッチの作り方
JavaScript でストップウォッチを作ります。Date.now() を使用し経過時間を計算してミリ秒から時間、分、秒に変換する方法や、0 を付け足して数字の表示を二桁に揃えるゼロ埋めの方法などを学びましょう。
00 : 00 : 00 . 00 で表示するストップウォッチ
今回紹介するのは、JavaScript でシンプルなストップウォッチを作る方法です。0.01 秒ごとにカウントし、ミリ秒から時間までを二桁の数字で表示します。開始と停止は一つのボタンでコントロールできるようにコーディングします。
この記事を読むと分かること
Date.now()
- 除算演算子
/
- 剰余演算子
%
- ゼロ埋め
setInterval()
clearInterval()
if…else
サンプルプロジェクト
最初に、ストップウォッチの動きを確認しておきましょう。
- スタートボタンを押すと開始。ボタンの表示は STOP になる。
- ストップボタンを押すと停止。ボタンの表示は START になる。
- 再びスタートボタンを押すと、前の経過時間に引き続き開始する。
- リセットボタンを押すと表示時間がゼロになる。
HTML
まずは HTML です。今回は開始と停止を一つのボタンで操作するので、作成するボタンは二つです。
- 時間を表示する
stopwatch <div>
を用意します。 toggle-button <button>
は、スタートとストップを切り替えるボタンです。reset-button <button>
は、ストップウォッチをゼロにリセットするボタンです。
<!-- ストップウォッチ(時間の表示) -->
<div class="stopwatch">00 : 00 : 00 . 00</div>
<div class="button-container">
<!-- スタートとストップを切り替えるボタン -->
<button class="toggle-button button">START</button>
<!-- リセットボタン -->
<button class="reset-button button">RESET</button>
</div>
JavaScript
続いて JavaScript です。JavaScript では関数を四つ定義します。また、時間を計算・変換するために、除算演算子 /
や剰余演算子 %
を使用します。計算する文が多くコードも長めですが、一つずつ順番に解説していきますね。
要素を取得する
最初に、JavaScript で操作したい HTML 要素を querySelector()
メソッドで取得します。それぞれ変数に格納しておきましょう。
// ストップウォッチ(時間の表示)
const stopwatch = document.querySelector('.stopwatch');
// 切り替えボタン(スタートorストップ)
const toggleBtn = document.querySelector('.toggle-button');
// リセットボタン
const resetBtn = document.querySelector('.reset-button');
変数を宣言する
次に行うのは、変数の宣言です。
- 開始時間を格納するための変数
startTime
を用意します。 - 経過時間を格納する変数を
elapsedTime
とし、0
で初期化します。 - 一定間隔で時間の表示を更新するためにタイマーを使います。そのタイマーを入れておくための変数
intervalTimer
を用意しておきます。この変数は、タイマーを停止するときに必要になります。
// 開始時間
let startTime;
// 経過時間
let elapsedTime = 0;
// タイマー
let intervalTimer;
ストップウォッチを開始する
ここからは、ストップウォッチを開始する関数 start
を定義していきます。start
は、一定間隔で時間の表示を更新する関数です。
// ストップウォッチを開始する関数
function start() {
// 0.01秒間隔のタイマーを設定する
// 0.01秒ごとに経過時間を計算する
// 経過時間を「時間」「分」「秒」「二桁のミリ秒」に変換する
// 0.01秒ごとにストップウォッチの表示を更新する
}
0.01 秒間隔のタイマーを設定する
まずは、タイマーを設定します。指定した時間間隔で何かを定期的に実行したいときに使うのは、setInterval()
メソッドです。
- あとでタイマーを停止できるように、変数
intervalTimer
を使用します。 - 0.01 秒間隔で時間の表示を更新したいので、遅延間隔を
10
ミリ秒とします。
function start() {
// 0.01秒間隔のタイマーを設定する
intervalTimer = setInterval(function() {
// 0.01秒ごとに経過時間を計算する
// 経過時間を「時間」「分」「秒」「二桁のミリ秒」に変換する
// 0.01秒ごとにストップウォッチの表示を更新する
// …
}, 10);
}
0.01 秒ごとに経過時間を計算する
次に、setInterval()
メソッドで実行する処理を書いていきましょう。
時間の表示を更新するためには、0.01 秒ごとに経過時間を計算する必要があります。そのために使うのが、Date.now()
メソッドです。Date.now()
を使うと、UTC1970年 1 月 1 日 0 時 0 分 0 秒 からの経過時間を取得することができます。この経過時間はタイムスタンプといい、単位はミリ秒です。
Date.now()
の例:
// 現在のタイムスタンプ
Date.now(); //1716860077437(ミリ秒)
経過時間を計算する文は以下のようになります。
- 現在のタイムスタンプ
Date.now()
から開始時間startTime
を引いて、ストップウォッチをスタートさせてからの経過時間を計算します。 - 割り出した経過時間は、変数
elapsedTime
に格納します。
function start() {
intervalTimer = setInterval(function() {
// 0.01秒ごとに経過時間を計算する
elapsedTime = Date.now() - startTime;
// 経過時間を「時間」「分」「秒」「二桁のミリ秒」に変換する
// 0.01秒ごとにストップウォッチの表示を更新する
// …
}, 10);
}
最初にスタートボタンを押した瞬間は、Date.now()
の値と変数 startTime
の値が同じになるので、経過時間 elapsedTime
の値は 0
です。この文は、setInterval()
メソッドで 0.01 秒ごとに繰り返し実行され、 その度に Date.now()
で返る値が変わるため、経過時間も変化します。
経過時間を「時間」「分」「秒」「二桁のミリ秒」に変換する
上の文で割り出した経過時間 elapsedTime
の値はミリ秒です。このままの値だとストップウォッチとして表示できませんね。「00時間:00分:00秒 . 00ミリ秒」の形式で表示できるよう、それぞれの値に変換しましょう。
Step 1:「ミリ秒」から「時間」を計算する
経過時間ミリ秒から「時間」を計算し、変数 hours
に格納します。考え方は次のとおりです。
- 1時間は、3,600,000 ミリ秒(1,000 ミリ秒 × 60 秒 × 60 分)です。
- 「ミリ秒」から「時間」を算出するには、経過時間
elapsedTime
を3600000
で割ります。
「ミリ秒」から「時間」を計算する式:
// 経過時間 / (1,000ミリ秒 × 60秒 × 60分)
elapsedTime / (1000 * 60 * 60)
// または
elapsedTime / 3600000
たとえば、経過時間 elapsedTime
に 4000000
という値が格納されているとします。計算結果は 1.11111111
となり、少数です。割り出した値を「時間」として表示できるように、Math.floor()
メソッドで整数にしてから変数に格納します。
// ミリ秒から時間を割り出して整数にする
let hours = Math.floor(elapsedTime / (1000 * 60 * 60));
経過時間ミリ秒から「時間」を計算し、整数にした値を変数 hours
に格納する文ができました。この文は、下のように割り算で表すこともできます。今回は、こちらの書き方を使ってコーディングしていきますね。
// 経過時間 / 1,000ミリ秒 / 60秒 / 60分
let hours = Math.floor(elapsedTime / 1000 / 60 / 60);
Step 2:「ミリ秒」から「分」を計算する
経過時間ミリ秒から「分」を計算し、変数 minutes
に格納します。
- 1分は、60,000 ミリ秒(1,000 ミリ秒 × 60 秒 )です。
- 「ミリ秒」から「分」を算出するには、経過時間
elapsedTime
を1000
と60
で割ります。 - 60 分を超えたら「時間」になるので、剰余演算子
%
を使って60
で割った余りだけを「分」とします。
// (経過時間 / 1,000ミリ秒 / 60秒) % 60分
let minutes = Math.floor((elapsedTime / 1000 / 60) % 60);
Step 3:「ミリ秒」から「秒」を計算する
経過時間ミリ秒から「秒」を計算し、変数 seconds
に格納します。
- 1秒は、1,000 ミリ秒です。
- 「ミリ秒」から「秒」を算出するには、経過時間
elapsedTime
を1000
で割ります。 - 60 秒を超えたら「分」になるので、
%
を使って60
で割った余りだけを「秒」とします。
// (経過時間 / 1,000ミリ秒) % 60秒
let seconds = Math.floor((elapsedTime / 1000) % 60);
Step 4:「ミリ秒」の二桁を取得する
最後に「ミリ秒」です。二桁のみを取得して、変数 milliseconds
に格納します。
- 1,000 ミリ秒を超えたら「秒」になるので、
%
を使って1000
で割った余りだけを「ミリ秒」とします。 - ミリ秒は「999」までの三桁となりますが、今回は二桁で表示させたいので、
10
で割ります。
// (経過時間 % 1,000ミリ秒) / 10->二桁
let milliseconds = Math.floor((elapsedTime % 1000) / 10);
以上で、経過時間ミリ秒の値を変換する文ができました。
function start() {
intervalTimer = setInterval(function() {
elapsedTime = Date.now() - startTime;
// 経過時間を「時間」「分」「秒」「二桁のミリ秒」に変換する
let hours = Math.floor(elapsedTime / 1000 / 60 / 60);
let minutes = Math.floor((elapsedTime / 1000 / 60) % 60);
let seconds = Math.floor((elapsedTime / 1000) % 60);
let milliseconds = Math.floor((elapsedTime % 1000) / 10);
// 0.01秒ごとにストップウォッチの表示を更新する
// …
}, 10);
}
0.01 秒ごとにストップウォッチの表示を更新する
経過時間を「時間」「分」「秒」「二桁のミリ秒」で取得できたら、その値を使ってストップウォッチの表示を更新しましょう。
// ストップウォッチの表示を更新する
stopwatch.textContent = `${hours} : ${minutes} : ${seconds} . ${milliseconds}`;
` ${ } `
を使って文字列を表すテンプレートリテラルについてはこちらの記事で紹介しているので参考にしてください。
たとえば、「2 時間 34 分 5 秒 66 ミリ秒」の場合、上の文に当てはめると、表示は「2 : 34 : 5 . 66」となります。今回は、それぞれの数字を二桁にして「02 : 34 : 05 . 66」のように表示したいので、関数 pad()
を使って下のような文にしますよ。関数 pad()
については、このあと説明しますね。
function start() {
intervalTimer = setInterval(function() {
elapsedTime = Date.now() - startTime;
let hours = Math.floor(elapsedTime / 1000 / 60 / 60);
let minutes = Math.floor((elapsedTime / 1000 / 60) % 60);
let seconds = Math.floor((elapsedTime / 1000) % 60);
let milliseconds = Math.floor((elapsedTime % 1000) / 10);
// 0.01秒ごとにストップウォッチの表示を更新する
stopwatch.textContent = `${pad(hours)} : ${pad(minutes)} : ${pad(seconds)} . ${pad(milliseconds)}`;
}, 10);
}
以上で、ストップウォッチを開始して 0.01 秒ごとに時間の表示を更新する関数 start
を定義できました。
ゼロ埋めして桁を揃える関数
さて、先ほど使用した関数 pad()
ですが、これは、文字列の桁数を揃えるための関数です。「2 時間」を「02 時間」とするように「0」を付け足すことを、ゼロ埋め(ゼロパディング)といいます。今回は二桁に揃えたいので、関数 pad()
は次のように定義することができます。
// ゼロ埋めする関数
function pad(number) {
return number.toString().padStart(2, '0');
}
ゼロ埋めについてはこちらの記事で詳しく紹介しているので参考にしてください。
開始と停止を切り替える
さて今度は、開始と停止を切り替えるための関数 startStop
を定義していきますよ。今回はストップウォッチの開始と停止を一つのボタンで操作するので、その切り替えを実行する関数です。
// 開始と停止を切り替える関数
function startStop() {
// if...else文で条件分岐する
// 開始時間を計算する
// ストップウォッチを開始してボタンの表示をSTOPにする
// タイマーを停止してボタンの表示をSTARTにする
}
if...else 文で条件分岐する
開始と停止の処理を分けるために使うのは、if…else
文です。
- もしボタンの表示が
START
ならストップウォッチを開始し、そうでなければ停止します。
function startStop() {
// if...else文で条件分岐する
if (toggleBtn.textContent === 'START') {
//*** ストップウォッチを開始する処理 ***
// 開始時間を計算する
// ストップウォッチを開始してボタンの表示をSTOPにする
} else {
//*** ストップウォッチを停止する処理 ***
// タイマーを停止してボタンの表示をSTARTにする
}
}
開始時間を計算する
ストップウォッチを開始するときの処理を書いていきましょう。
まずは、開始時間を計算して値を取得します。変数 startTime
には、一旦停止してから再びスタートボタンを押したときのことも考えて計算した値を格納しなければいけません。なぜ単純に開始時間を現在のタイムスタンプ startTime = Date.now()
にしてはいけないかというと、それだと再開したときに経過時間がゼロになってしまうからです。
Date.now()
で取得した値からそれまでの経過時間elapsedTime
を引いた値を変数startTime
に格納します。
function startStop() {
if (startStopBtn.textContent === 'START') {
// 開始時間を計算する
startTime = Date.now() - elapsedTime;
// ストップウォッチを開始してボタンの表示をSTOPにする
// …
} else {
// タイマーを停止してボタンの表示をSTARTにする
// …
}
}
最初にスタートボタンを押したときは経過時間 elapsedTime
の値は 0
なので、変数 startTime
には単純に現在のタイムスタンプが入ります。
ストップウォッチを開始してボタンの表示を STOP にする
開始時間を取得できたら、ストップウォッチを開始して時間が更新されるようにしましょう。
- 先ほど定義した関数
start
を実行してストップウォッチを開始します。 - ボタンの表示を
STOP
に切り替えます。
function startStop() {
if (toggleBtn.textContent === 'START') {
startTime = Date.now() - elapsedTime;
// ストップウォッチを開始する
start();
// ボタンの表示をSTOPにする
toggleBtn.textContent = 'STOP';
} else {
// タイマーを停止してボタンの表示をSTARTにする
// …
}
}
タイマーを停止してボタンの表示を START にする
続いて、ストップウォッチを停止する処理です。else
の部分に書いていきますよ。
clearInterval()
メソッドで変数intervalTimer
を指定し、ストップウォッチを更新するタイマーを停止します。- ボタンの表示を
START
に切り替えます。
function startStop() {
if (toggleBtn.textContent === 'START') {
startTime = Date.now() - elapsedTime;
start();
toggleBtn.textContent = 'STOP';
} else {
// タイマーを停止する
clearInterval(intervalTimer);
// ボタンの表示をSTARTにする
toggleBtn.textContent = 'START';
}
}
以上で、ストップウォッチを開始または停止する関数 startStop
を定義できました。
ストップウォッチをリセットする
開始と停止を実行する関数を用意できたら、残るはストップウォッチをゼロにリセットするための関数 reset
です。この関数の内容はとてもシンプルです。
- タイマーを停止します。
- 経過時間を
0
にします。 - ストップウォッチの表示を
00 : 00 : 00 . 00
にします。 - ボタンの表示を
START
にします。
// ストップウォッチをリセットする関数
function reset() {
clearInterval(intervalTimer);
elapsedTime = 0;
stopwatch.textContent = '00 : 00 : 00 . 00';
toggleBtn.textContent = 'START';
}
ボタンにクリックイベントを追加する
最後に、二つのボタンに click
イベントを追加しましょう。ユーザーがボタンをクリックしてストップウォッチを操作できるようにしますよ。
- スタートまたはストップボタンを押したら、ストップウォッチを開始または停止する関数
startStop
を呼び出します。 - リセットボタンを押したら、ストップウォッチをリセットする関数
reset
を呼び出します。
toggleBtn.addEventListener('click', startStop);
resetBtn.addEventListener('click', reset);
完成コード
ストップウォッチのコードが完成です。
//************************
// ストップウォッチのコード
//************************
const stopwatch = document.querySelector('.stopwatch');
const toggleBtn = document.querySelector('.toggle-button');
const resetBtn = document.querySelector('.reset-button');
let startTime;
let elapsedTime = 0;
let intervalTimer;
// ストップウォッチを開始する
function start() {
intervalTimer = setInterval(function() {
elapsedTime = Date.now() - startTime;
let hours = Math.floor(elapsedTime / 1000 / 60 / 60);
let minutes = Math.floor((elapsedTime / 1000 / 60) % 60);
let seconds = Math.floor((elapsedTime / 1000) % 60);
let milliseconds = Math.floor((elapsedTime % 1000) / 10);
stopwatch.textContent = `${pad(hours)} : ${pad(minutes)} : ${pad(seconds)} . ${pad(milliseconds)}`;
}, 10);
}
// 前に0を付け足して二桁に揃える
function pad(number) {
return number.toString().padStart(2, '0');
}
// 開始と停止を切り替える
function startStop() {
if (toggleBtn.textContent === 'START') {
startTime = Date.now() - elapsedTime;
start();
toggleBtn.textContent = 'STOP';
} else {
clearInterval(intervalTimer);
toggleBtn.textContent = 'START';
}
}
// ストップウォッチをリセットする
function reset() {
clearInterval(intervalTimer);
elapsedTime = 0;
stopwatch.textContent = '00 : 00 : 00 . 00';
toggleBtn.textContent = 'START';
}
// ボタンにクリックイベントを追加する
toggleBtn.addEventListener('click', startStop);
resetBtn.addEventListener('click', reset);
See the Pen JavaScript - Stopwatch by Pyxofy (@pyxofy) on CodePen.
まとめ
今回は、JavaScript でストップウォッチを作る方法を紹介しました。
経過時間を計算するために使用したのが Date.now()
メソッドです。時間は二桁にゼロ埋めして、桁数を揃えて表示されるようにしました。ミリ秒から他の単位に変換する計算は、演算子や数字がたくさん出てきて少し難しかったかもしれませんね。開始ボタンと停止ボタンは別で作っても良いですが、一つのボタンで開始と停止を切り替えられるようにしたところも、今回のコードのポイントでした。
最後まで読んでいただき、ありがとうございます。この記事をシェアしてくれると嬉しいです!
SNSで Pyxofy とつながりましょう! LinkedIn・ Threads・ Mastodon・ X (Twitter) @pyxofy・ Facebook