ストップウォッチを作ってみる[Visualforce]

概要

Visualforceでストップウォッチを作成します。
スタートの時間とストップの時間の差分を計算します。
ミリ秒単位で計測します。

ソースコード

Stopwatch.vfp

<apex:page docType="html-5.0" LightningStylesheets="true">
    <html lang="ja">
        <head>
            <meta charset="UTF-8" />
            <meta name="viewport" content="width=device-width, initial-scale=1.0" />
            <title>ストップウォッチ</title>
            <apex:slds />
        </head>
        <body>
            <div class="slds-align_absolute-center">
                <div class="slds-size_2-of-3">
                    <apex:pageBlock >
                    <div class="slds-grid slds-einstein-header slds-card__header">
                        <header class="slds-media slds-media_center slds-has-flexi-truncate">
                            <div class="slds-grid slds-grid_vertical-align-center slds-size_3-of-4 slds-medium-size_2-of-3">
                                <h1 class="slds-truncate" title="ストップウォッチ">
                                    <span class="slds-text-heading_large">ストップウォッチ</span>
                                </h1>
                            </div>
                            <div class="slds-einstein-header__figure slds-size_1-of-4 slds-medium-size_1-of-3"></div>
                        </header>
                    </div>
                    <div class="slds-align_absolute-center">
                        <div class="slds-m-top_large">
                        <header class="slds-col slds-size_1-of-1 slds-align_absolute-center" >
                            <div class="curentTime slds-text-heading_large">00:00:000</div>
                        </header>
                        <main class="slds-align_absolute-center">
                            <div class="slds-button-group slds-m-vertical_medium" role="group">
                                <button id="start" class="slds-button slds-button_neutral slds-text-heading_medium slds-p-around_small">スタート</button>
                                <button id="stop" class="slds-button slds-button_neutral slds-text-heading_medium slds-p-around_small" disabled="true">ストップ</button>
                                <button id="reset" class="slds-button slds-button_text-destructive slds-text-heading_medium slds-p-around_small">リセット</button>
                            </div>
                        </main>
                        </div>
                    </div>
                    </apex:pageBlock>
                </div>
            </div>
            <apex:include pageName="StopwatchJs"/>
        </body>
    </html>
</apex:page>

Stopwatch.Js

<apex:page >
    <script>
    const stopwatchButton = document.querySelectorAll('.slds-button'),
          startButton = document.querySelector('#start'),
          stopButton = document.querySelector('#stop'),
          curentTimeText = document.querySelector('.curentTime');
    
    let startTime, // 計測開始時刻
        timeToAdd = 0, // 経過時間
        measuringTime = 0, // 計測時間
        timerId; // clearTimeout用のID
    
    stopwatchButton.forEach(function (button) {
        button.addEventListener('click', event => {
            let clickedButtonId = event.currentTarget.id;
            if(clickedButtonId === 'start') {
                // 計測開始
                this.startTimmer();
            } else if(clickedButtonId === 'stop') {
                // 計測終了
                this.stopTimmer();
            } else {
                // 計測リセット
                this.resetTimmer();
            }
        })
    })
    
    // 計測開始
    function startTimmer() {
        startButton.disabled = true;
        stopButton.disabled = false;
        
        startTime = Date.now();
        // 10ミリ秒毎に計測する
        countUp();
    }
    
    // 計測終了
    function stopTimmer() {
        startButton.disabled = false;
        stopButton.disabled = true;
        clearTimeout(timerId);
        timeToAdd += Date.now() - startTime; // 経過時間を記録
    }
 
    // 計測リセット
    function resetTimmer() {
        startButton.disabled = false;
        stopButton.disabled = true;
        clearTimeout(timerId);
        
        measuringTime = 0;
        timeToAdd = 0;

        // 計測時間を分に変換して表示する
        updateTimeText();
    }
    
    // 計測時間を分に変換して表示する
    function updateTimeText(){
        let min = Math.floor(measuringTime / 60000); // 分
        let sec = Math.floor(measuringTime % 60000 / 1000); // 秒
        let ms = measuringTime % 1000; // ミリ秒

        // 桁数を固定
        min = ('0' + min).slice(-2); 
        sec = ('0' + sec).slice(-2);
        ms = ('00' + ms).slice(-3);

        // 計測時間を表示
        curentTimeText.textContent = min + ':' + sec + ':' + ms;
    }
    
    // 10ミリ秒毎に計測する
    function countUp(){
        timerId = setTimeout(function(){
            measuringTime = Date.now() - startTime + timeToAdd;
            // 計測時間を分に変換して表示する
            updateTimeText()
            // 10ミリ秒毎に計測する
            countUp();
        },10);
    }
    </script>
</apex:page>