1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

初心者によるJavaScriptでストップウォッチを作るための学習 その1

1
Last updated at Posted at 2019-08-27

ストップウォッチの枠組みを作る

タイマー部分とStart、Stop、Resetボタンを用意し、ストップウォッチをつくります。

htmlの中身は

  <div id="timer">00:00.000</div>
  <button id="start">Start</button>
  <button id="stop">Stop</button>
  <button id="reset">Reset</button>

と、こんな感じにタイマー部分とそれを操作するボタンを配置。

まずは個々のボタンが動くようにする。

{
  const timer = document.getElementById('timer');
  const start = document.getElementById('start');
  const stop = document.getElementById('stop');
  const reset = document.getElementById('reset');

  let startTime;
  let timeoutId;

  function countUp() {
    const d = new Date(Date.now() - startTime);
    const m = String(d.getMinutes()).padStart(2, '0');
    const s = String(d.getSeconds()).padStart(2, '0');
    const ms = String(d.getMilliseconds()).padStart(3, '0');
    timer.textContent = `${m}:${s}.${ms}`;

    timeoutId = setTimeout(() => {
      countUp();
    }, 10);
  }

  start.addEventListener('click', () => {
    startTime = Date.now();
    countUp();
  });

  stop.addEventListener('click', () => {
    clearTimeout(timeoutId);
  });

  reset.addEventListener('click', () => {
    timer.textContent = '00:00.000';
  });
}

ざっと大枠だけ用意するとこうなります。

問題点を解決する

ただしこれだと一旦ストップしてから再スタートすると、00:00:000から始まってしまう。これを止めた時点から再スタートさせたい。
つまりストップした時点の経過時間を保持し、それを足してから再スタートさせれば良い。

経過時間をelapsedTimeと宣言し、0を入れておく(そうすることで最初のスタート時には影響されないようにする)

  let startTime;
  let timeoutId;
  let elapsedTime = 0; // タイマーが走っていた時間 === 経過時間

ストップした時点での経過時間は`Date.now() - startTime`で計算して`elapsedTime`に入れる。
  stop.addEventListener('click', () => {
    clearTimeout(timeoutId);
    elapsedTime = Date.now() - startTime; // ストップした時点での経過時間
  });

次にスタート時に経過時間を加える。
  const d = new Date(Date.now() - startTime + elapsedTime);

ただ、これでは、elapsedTimeが直近の経過時間しか保持していないため、ストップ・スタートを繰り返すと時間が巻き戻ってしまうという問題がある。
従って

    elapsedTime += Date.now() - startTime; // ストップした時点での経過時間

のようにして、今までの経過時間を積み重ねるようにすれば良い。

これで良しと思いきや、リセットを押して再スタートした際は、前回ストップした状態から始まってしまうので、

  reset.addEventListener('click', () => {
    timer.textContent = '00:00.000';
    elapsedTime = 0; // 経過時間のリセット
  });

として、経過時間もリセットすることを忘れないようにする。

通常の操作以外で発生する問題点を解決する

ストップウォッチとしては動くのですが、いくつかの問題点を抱えたままです。

1.スタートを複数回押した後だと、一回ストップを押しても止まらない
2.ストップを複数回押した後だと、正しい秒数から再開されない

これらは主に、各ボタンを押すごとにstartTimeやelapsedTimeが多重起動してしまうことが原因です。

それらの解決方法は、必要のないボタンは押させないが良いでしょう。フォールトアボイダンスというやつですね。

ボタンの状態を管理する

必要のないボタンを押させない状態は.disabled = true;と設定します。

従って、各状態ごとの状況は

Start Stop Reset
開始時(Initual) false true true
カウント中(Running) true false true
停止時(Stopped) false true false
※true = 非表示 / false = 表示

となります。

これを設定するのは

  function setButtonStateInitial() {
    start.disabled = false;
    stop.disabled = true;
    reset.disabled = true;
  }
  function setButtonStateRunning() {
    start.disabled = true;
    stop.disabled = false;
    reset.disabled = true;

  }
  function setButtonStateStopped() {
    start.disabled = false;
    stop.disabled = true;
    reset.disabled = false;

  }

  setButtonStateInitial(); //初期設定

とし、各ボタンをクリックしたときの関数に、これらの状態へ移行するようにする。

  start.addEventListener('click', () => {
    setButtonStateRunning(); // Runningへ以降
    startTime = Date.now();
    countUp();
  });
  stop.addEventListener('click', () => {
    setButtonStateStopped(); // Stoppedへ以降
    clearTimeout(timeoutId);
    elapsedTime += Date.now() - startTime;
   console.log(elapsedTime);
  });
  reset.addEventListener('click', () => {
    setButtonStateInitial(); // Initualへ以降
    timer.textContent = '00:00.000';
    elapsedTime = 0;
  });

これで操作そのものの問題は概ね解決できたと思います。

続きは装飾部分について取り組みます。その2はこちら https://qiita.com/amanomunt/items/b667aaea307f1df6b104

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?