JavaScript:正確なストップウォッチを作る

JavaScript:正確なストップウォッチを作る JavaScript

JavaScriptで以前作ったストップウォッチの挙動がおかしかったので修正した。
表示は、100分の1秒単位だが、内部的には1000分の1秒単位で計測している。実際に市販のストップウォッチと同時にスタートさせて1時間ほど測ってみたが、ずれは全くなかった。

↓タッチでサンプル実行
StopWatch2

DateクラスのgetTime()メソッドを利用して、スタート時刻との差分を求めて表示している。単純にsetTimeout(run, 1000)などとしても、1000ミリ秒毎に完全に呼ばれるわけではない。JavaScriptのMDNマニュアルでも、setTimeoutの第2引数に関して、「実際の呼び出しはこれより長くなる場合があります。」と記述されている。最初に作ったストップウォッチは、この方法で、1秒ごとにカウントしたが、3分も経過しないうちに30秒以上も狂った。

一式ダウンロード

ソースコード

HTML部分

1<!DOCTYPE html>
2<html>
3<head>
4    <meta charset="utf-8">
5    <link rel="stylesheet" href="mystyle.css">
6    <script src="stopWatch.js"></script>
7    <title>ストップウォッチ - Another Sky</title>
8</head>
9<body>
10    <h1>ストップウォッチ</h1>
11    <form name="form1" id="form1">
12    <p id="time">
13    00:00:00.00
14    </p>
15    <button type="button" id="btnStart" onclick="startStop()">
16    スタート
17    </button>
18    <button type="button" id="btnClear" onclick="resetStopWatch()">
19    クリア
20    </button>
21    </form>
22    <footer>&copy; 2014 Shuichi Takeda.</footer>
23</body>
24</html>

CSS部分

1@charset "utf-8";
2*{
3    margin: 0;
4    padding: 0;
5}
6body{
7    font-family: 'メイリオ', Osaka;
8    margin: 2em;
9}
10h1{
11    border-bottom:solid 1px #555;
12}
13p#time{
14    font-size: 48pt;
15    padding-top: 0.5em;
16}
17button{
18    width:5em;
19    padding:5pt;
20    font-size: 20pt;
21    border:solid 1px #555;
22    border-radius: 12pt;
23}
24button:hover{
25    background-color: pink;
26}
27footer{
28    color: #ddd;
29    background-color: transparent;
30    text-align: right;
31}

JavaScript部分

1// -------------------------------------------------------------------------
2// stopWatch.js ストップウォッチプログラム
3//
4//      1970年1月1日からの経過時間(ミリ秒単位)を使っている
5//
6//                  created at 2014-06-26 on torisky.com
7// -------------------------------------------------------------------------
8 
9var mode;                   // ストップウォッチのモード RUN/STOP
10var startTime;              // スタートした時刻
11var nowTime;                // ストップした時刻
12var addTime;                // 経過時間(ストップウォッチ再開時に加算する)
13var millisec;                   // 1000分の1秒
14var sec100;                 // 100分の1秒
15var sec;                        // 秒
16var min;                        // 分
17var hour;                   // 時
18var gmt;                        // タイムゾーンのオフセット値
19                            //  例)GMT+0900 なら 標準時より9時間後をさしているので-9する
20var timerId;                    // タイマー
21 
22/*
23 * 定数
24 */
25var RUN = 1;                // 動作中
26var STOP = 0;               // 停止中
27 
28/*
29 * ストップウォッチのリセット
30 */
31function resetStopWatch(){
32    mode = STOP;
33    addTime = 0;
34    millisec = sec100 = sec = min = hour = 0;
35    gmt = new Date().getTimezoneOffset() / 60;  // 戻り値は分のため60で割る
36    document.getElementById("time").innerHTML = "00:00:00.00";
37}
38         
39/*
40 * ボタン処理
41 */
42function startStop(){
43    switch(mode){
44        case STOP:      // スタートを押したとき
45            mode = RUN;
46            timerId = setTimeout(runStopWatch, 10);
47            document.getElementById("btnClear").disabled = "true"// クリアボタンを使用不可
48            document.getElementById("btnStart").innerHTML = "ストップ";
49            // スタート時刻を設定(ストップウォッチが進んでいれば加算)
50            startTime = new Date().getTime();
51            addTime = (hour*60*60*1000 + min*60*1000 + sec * 1000 + millisec);
52            startTime -= addTime;
53            break;
54 
55        case RUN:       // ストップを押したとき
56            mode = STOP;
57            clearTimeout(timerId);
58//          nowTime = new Date().getTime();
59            document.getElementById("btnStart").innerHTML = "スタート";
60            document.getElementById("btnClear").disabled = "";      // クリアボタンを使用可
61            drawTime();
62    }
63}
64 
65/*
66 * 時間表示
67 */
68function drawTime(){
69    var strTime = "";
70    var strSec100, strSec, strMin, strHour;
71 
72    // 数値を文字に変換及び2桁表示設定
73    strSec100 = "" + sec100;
74    if ( strSec100.length < 2){
75        strSec100 = "0" + strSec100;
76    }
77    strSec = "" + sec;
78    if ( strSec.length < 2){
79        strSec = "0" + strSec;
80    }
81    strMin = "" + min;
82    if ( strMin.length < 2){
83        strMin = "0" + strMin;
84    }
85    strHour = "" + hour;
86    if ( strHour.length < 2){
87        strHour = "0" + strHour;
88    }
89    // 表示形式を設定
90    strTime = strHour + ":" + strMin + ":" + strSec + "." + strSec100;
91    document.getElementById("time").innerHTML = strTime;
92}
93 
94/*
95 * 時間計測
96 */
97function runStopWatch(){
98    // スタートからの差分をとる
99    nowTime = new Date().getTime();
100    diff = new Date(nowTime - startTime);
101    // ミリ秒、100分の1秒、秒、分、時を設定
102    millisec = diff.getMilliseconds();
103    sec100 = Math.floor(millisec / 10);
104    sec = diff.getSeconds();
105    min = diff.getMinutes();
106    hour = diff.getHours() + gmt;   // タイムゾーンのオフセットを考慮する
107 
108    drawTime();         // 時間表示
109    timerId = setTimeout(runStopWatch, 10);
110}
111 
112/*
113 * 実行時の処理
114 */
115window.onload = function(){
116    resetStopWatch();
117}

コメント

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