【GAS】ストップウォッチを作成する【JavaScript】

deadline-stopwatch プログラミング

GASを使うとWebアプリが簡単に作成できます。

今回は、ストップウォッチを作成します。

ストップウォッチアプリの完成形

ストップウォッチアプリの画面とコードです。

stopwatch-html
const doGet = () => {
  return htmlOutput = HtmlService.createTemplateFromFile("index")
      .evaluate()
      .setTitle("ストップウォッチ")
      .addMetaTag("viewport", "width=device-width,initial-scale=1");
};
<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
    <div class='timer'>00:00.000</div>
    <button class='start-stop'>スタート</button>
    <button class='reset'>リセット</button>
    <?!= HtmlService.createHtmlOutputFromFile('js').getContent(); ?>
  </body>
</html>
<script>
//Appクラス
class App {
  constructor() {
    //stopwatctクラスのインスタンスの作成
    this.stopwatch = new Stopwatch();
  }

  mount() {
  	const startStopElement = document.querySelector('.start-stop');
    const resetElement = document.querySelector('.reset');
    //startStopボタンを押したとき
    startStopElement.addEventListener("click", () => {
      //ストップウォッチが止まっているとき
      if(this.stopwatch.isStop) {
        //ストップウォッチを動かす
        this.stopwatch.start();
        //ボタン表示をストップに
        startStopElement.textContent = "ストップ";
      //ストップウォッチが動いているとき
      } else {
        //ストップウォッチを止める
        this.stopwatch.stop();
        //ボタン表示をスタートに
        startStopElement.textContent = "スタート";
      }
    });
    //resetボタンを押したとき
    resetElement.addEventListener("click", () => {
      //ストップウォッチが止まっているとき
      if(this.stopwatch.isStop){
        //ストップウォッチをリセット
        this.stopwatch.reset();
      }
    });
  }
}

//画面の時間表示
const view = (value) => {
  let min = Math.floor(value / (60 * 1000));
  let sec = Math.floor(value % (60 * 1000) / 1000);
  let minSec = value % 1000;
  //2桁表示に
  if(min < 10) {
    min = ("0" + min).slice(-2);
  }
  sec = ("0" + sec).slice(-2);
  minSec = ("00" + minSec).slice(-3);
  
  //timerの表示を書き換え
  const timerElement = document.querySelector('.timer');
  timerElement.textContent = `${min}:${sec}.${minSec}`;
};

//stopwatchクラス
class Stopwatch {
  constructor() {
    //リセットメソッドを実行
    this.reset();
  }
  //ストップウォッチをリセット
  reset() {
    this.isStop = true;
    this.id = 0;
    this.elapsedTime = 0;
    view(0);
  }
  //ストップウォッチをスタート
  start() {
    this.isStop = false;
    this.startTime = Date.now();
    this.id = setInterval(() => {
      view((Date.now() - this.startTime) + this.elapsedTime);
    }, 5);
  }
  //ストップウォッチをストップ
  stop() {
    this.isStop = true;
    this.elapsedTime += Date.now() - this.startTime;
    clearInterval(this.id);
  }
}

//Appクラスのインスタンスを作成
const app = new App();
//マウントメソッドの実行
app.mount();

</script>

「コード.gs」は、「index.html」で書いたhtmlファイルをアプリとして表示するスクリプトになります。

「index.html」は、アプリの骨組みです。ストップウォッチの時間を表示部分とスタートボタン、リセットボタンを作っています。

JavaScriptコードの解説

メインである「js.html」について見ていきます。

具体的なコードの前に、ストップウォッチの機能について考えてみます。

1 スタートボタンを押したら時間が進む

2 ストップボタンを押したら時間が止まる。

3 リセットボタンを押したら時間が0になる。

※リセットボタンはストップウォッチが止まっているときときだけ動作する。

※ストップウォッチが止まっているときは、ボタンは「スタート」。動いているときは、ボタンは「ストップ」。

これをもとに機能を実装していきます。

Stopwatchクラス

Stopwatchクラスについて見ていきます。

//stopwatchクラス
class Stopwatch {
  constructor() {
    //リセットメソッドを実行
    this.reset();
  }
  //ストップウォッチをリセット
  reset() {
    this.isStop = true;
    this.id = 0;
    this.elapsedTime = 0;
    view(0);
  }
  //ストップウォッチをスタート
  start() {
    this.isStop = false;
    this.startTime = Date.now();
    this.id = setInterval(() => {
      view((Date.now() - this.startTime) + this.elapsedTime);
    }, 5);
  }
  //ストップウォッチをストップ
  stop() {
    this.isStop = true;
    this.elapsedTime += Date.now() - this.startTime;
    clearInterval(this.id);
  }
}

constructor()はインスタンスが作成されたときに実行されます。

他のメソッドとして、reset()、start()、stop()があり、次の4つ変数を持ちます。

  • isStop:ストップウォッチが止まっているか。止まっている場合は「true」。
  • id:タイマー処理のsetIntervalを管理するid。
  • elapsedTime:ストップウォッチがストップしたときの経過時間を保持する。
  • startTime:ストップウォッチがスタートしたときの時刻を保持する。

ストップウォッチの時間の計算方法ですが、ストップウォッチをスタートしたときの時間をstartTimeで持っておき、今の時間であるDate.now()から引くことで計算しています。

ストップウォッチは、止まって再びスタートさせることもあるので、前回の経過時間を保持しているelapsedTimeを加算しています。

//(今の時間 ー スタート時間) + 前回の経過時間
(Date.now() - this.startTime) + this.elapsedTime

上の計算をsetIntervalで5ミリ秒ごとに行っています。

view

Stopwatchクラスで計算した時間を画面に表示させるのがview関数式です。

//画面の時間表示
const view = (value) => {
  let min = Math.floor(value / (60 * 1000));
  let sec = Math.floor(value % (60 * 1000) / 1000);
  let minSec = value % 1000;
  //2桁表示に
  if(min < 10) {
    min = ("0" + min).slice(-2);
  }
  sec = ("0" + sec).slice(-2);
  minSec = ("00" + minSec).slice(-3);
  
  //timerの表示を書き換え
  const timerElement = document.querySelector('.timer');
  timerElement.textContent = `${min}:${sec}.${minSec}`;
};

以下のコードは、受け取った引数(ミリ秒)を分、秒、ミリ秒に分けています。

  let min = Math.floor(value / (60 * 1000));
  let sec = Math.floor(value % (60 * 1000) / 1000);
  let minSec = value % 1000;

1分 = 60秒 = 6,000ミリ秒

1秒 = 1,000ミリ秒

Math.floor():小数点以下を切り捨てた整数を返す。

%:剰余演算子。計算した余り。

引数として310,500を受け取った場合について計算してみます。

分 = 310,500 / 60,000 = 5.175 ≒ 5(小数点以下を切り捨て)

秒 = (310,500 / 60,000の余り) / 1,000 = 10,500 / 1,000 = 10.5 ≒ 10(小数点以下を切り捨て)

ミリ秒 = 310,500 / 1,000の余り = 500

それぞれの値について、2桁または3桁の表示にするのが以下のコードです。

  //2桁表示に
  if(min < 10) {
    min = ("0" + min).slice(-2);
  }
  sec = ("0" + sec).slice(-2);
  minSec = ("00" + minSec).slice(-3);

JavaScriptの仕様上、数値に文字列を追加することで、文字列に変換されます。

"0" + min

その文字列をsliceで切り出すことで2桁または3桁表示に変換しています。

2桁または3桁表示にした各値を、以下のコードで画面表示させています。

//timerの表示を書き換え
const timerElement = document.querySelector('.timer');
timerElement.textContent = `${min}:${sec}.${minSec}`;

Appクラス

実際にメインで動くのがAppクラスになります。

//Appクラス
class App {
  constructor() {
    //stopwatctクラスのインスタンスの作成
    this.stopwatch = new Stopwatch();
  }

  mount() {
  	const startStopElement = document.querySelector('.start-stop');
    const resetElement = document.querySelector('.reset');
    //startStopボタンを押したとき
    startStopElement.addEventListener("click", () => {
      //ストップウォッチが止まっているとき
      if(this.stopwatch.isStop) {
        //ストップウォッチを動かす
        this.stopwatch.start();
        //ボタン表示をストップに
        startStopElement.textContent = "ストップ";
      //ストップウォッチが動いているとき
      } else {
        //ストップウォッチを止める
        this.stopwatch.stop();
        //ボタン表示をスタートに
        startStopElement.textContent = "スタート";
      }
    });
    //resetボタンを押したとき
    resetElement.addEventListener("click", () => {
      //ストップウォッチが止まっているとき
      if(this.stopwatch.isStop){
        //ストップウォッチをリセット
        this.stopwatch.reset();
      }
    });
  }
}

constructor()でStopwatchクラスのインスタンスを作成しています。

ボタンを押されたときに動作するのがmount()です。スタートストップボタンが押されたとき、isStopでストップウォッチが止まっているか判定しています。

リセットボタンが押されたときは、ストップウォッチが止まっているときだけリセットします。

タイトルとURLをコピーしました