Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

js 設定した時間とタイマーが同じになった際に効果音を鳴らしたい

解決したいこと

現在jsでストップウォッチのプログラムを作成しているのですが、
設定した時間をストップウォッチが踏んだら(?)効果音を鳴らすというプログラムを作成しております。
効果音を鳴らすプログラムの書き方がわからず悩んでいます。

現座のコード

index.html
<div class="container">
    <p class="display"><span id="timer">00:00:00</span></p>

    <div>
        <button id="start_stop" class="btn btn-lg btn-primary">START</button>
    </div>
    
    <!-- アラーム時間設定 -->
    <input id="setHour" type="number" min="0" max="23" oninput="javascript: this.value = this.value.slice(0, 2)"
            oninput="inputChange()">
    <input id="setMinute" type="number" min="0" max="59" oninput="javascript: this.value = this.value.slice(0, 2)"
            oninput="inputChange()">
    <input id="setSecond" type="number" min="0" max="59" oninput="javascript: this.value = this.value.slice(0, 2)"
            oninput="inputChange()">

    <div class="display">
        <p>
            <span id="displayHour">00</span>
            :
            <span id="displayMinute">00</span>
            :
            <span id="displaySecond">00</span>
        </p>
    </div>
</div>
main.js
// 時間用、ゼロを追加する
var addZero = function (value) {
    if (value < 10) {
        value = '0' + value;
    }
    return value;
};

//スタート・ストップボタン機能
document.getElementById('start_stop').addEventListener('click', function () {
    if (this.innerHTML === 'START') {
        start = new Date();

        salary_id = setInterval(salaryTimer, 1);

        // STOP ボタンにする
        this.innerHTML = 'STOP';
        this.classList.remove('btn-primary');
        this.classList.add('btn-danger');
    } else {
        clearInterval(salary_id);

        // START ボタンにする
        this.innerHTML = 'START';
        this.classList.remove('btn-danger');
        this.classList.add('btn-primary');
    }
});

//画面表示処理
var salaryTimer = function () {
    var now = new Date();
    
    milli = now.getTime() - start.getTime(); //1ミリ秒時間計測
    seconds = Math.floor(centi / HUNDRED_DIV); //1秒の計測(ミリ秒/1000)
    minutes = Math.floor(seconds / TIMES_CON); //1分の計測(秒/60)
    hours = Math.floor(minutes / TIMES_CON); //1時間の計測(分/60)
    
    seconds = seconds - minutes * TIMES_CON; //59秒まで行ったら次は00秒にする(秒-分*60)ー>桁の繰り上げ
    minutes = minutes - hours * TIMES_CON; //59分まで行ったら次は00分にする(分-時*60)ー>桁の繰り上げ

    //経過時間のゼロ追加
    hours = addZero(hours);
    seconds = addZero(seconds);
    minutes = addZero(minutes);

    document.getElementById('timer').innerHTML = hours + ':' + minutes + ':' + seconds;

上記が現在時刻の表示とアラーム設定のコードになります。

ここで私が行いたいのが
設定した時間が、1時間2分3秒

.例
時:分;秒
1:2:3

だった場合

main.js
document.getElementById('timer').innerHTML = hours + ':' + minutes + ':' + seconds;

上記コードの時刻が、1時間2分3秒になった際にアラームを鳴らしたいというものです。
アラームが鳴ったら上記コードの時刻が止まるのではなく、
「「アラームが一度なってもストップウォッチは稼働させたいです。」」

試したこと

index.html
<body>
    <audio id="alarm" src="../static/audios/templeBell.mp3" preload="auto"></audio> <!-- 追加 -->
    <div class="container">
main.js
//null判定(ゼロ代入)
var nullJudge = function(value){
    if(value == null){
        value = '0' + 0;
    }
}

const alarm = document.getElementById("alarm");

//null判定(ゼロ追加)
getHour = nullJudge(getHour);
getMinute = nullJudge(getMinute);
getSecond = nullJudge(getSecond)

//アラーム条件
if(getHour == hours && getMinute == minutes && getSecond == seconds){
    TEMPLE_BELL.play();
}

上記のコードで試してみたのですが、うまくいきませんでした。

最後まで読んでいただきありがとうございます。
教えていただけますと幸いです。
何卒よろしくお願いいたします。

1

2Answer

おそらく、問題は

//アラーム条件
if(getHour == hours && getMinute == minutes && getSecond == seconds){
    TEMPLE_BELL.play();
}

が実行されるタイミングだと思います。

というのは、(時間を扱うプログラムの初心者にはありがちなミスですが)、このif文が処理されるのが一回だけになってしまっているかと見受けられます。

例えば、01:02:03に発火してほしくても、もしこのif文が01:01:00に処理されてそれっきりになると(それ以降処理させないと)、何もしない待機状態のまま01:02:03を迎えます

要するに、指定時刻が来るまで、繰り返しif文を処理させて待ち受ける必要があります。

それには、SetInterval()を用いるとうまくいくと思いますので、試してみてください。
もしピンと来ないようであれば追伸していただければと思います。

1Like

Comments

  1. @Kobayashi0620

    Questioner

    ご回答いただきありがとうございます!!
    まだピンと来ていないのでもう少し教えていただけますでしょうか?

  2. ありがとうございます。
    もう一度質問を読みましたが、もしかしてアラーム音の再生には成功してる、ということでしたか?
    それと、salaryTimer}が書かれていませんが、もしかして2個目のmain.jsのスクリプトもsalaryTimerに含まれているということでしたか?
    でしたら僕の読み間違いなのでお気になさらずに…

    僕が言いたかったのは、述べているif文が独立して(どの繰り返し処理にも組み込まれずに)書かれているように見受けられ、

    「指定時刻が来るまで、繰り返しif文を処理させて待ち受ける必要があります。」

    という点を述べたかったということです。

    すなわち、そのif文は「指定時刻に発火する」ことが意図であると思いますが、その状態だと都合よく指定時間に判定処理がなされることはない、ということです。

    極端な例だと、

    var x = 0
    if (x == 10){
       console.log(発火)
    }
    while(x<100){
      x+=1
    }
    

    と書いても「発火」が出力されませんよね。ifの判定処理がwhile直前の一回切りで完結して、while中に判定処理がなされないからです。

    もしこちらの見通し通りですと、こちらと同様のことをなされていると思うので、一度ご確認をお願いします。

  3. ついでに、指定時刻を過ぎてもタイマーを止める処理は書かれていないようですので、指定時刻を過ぎても問題なく時間表示が進んでいるかと思いますが、どうでしょうか?

  4. @Kobayashi0620

    Questioner

    アラーム音の再生ができない状態です!
    salaryTimerno}は書き忘れです。
    2個目のmain.jsは音声を再生するために実装したもので
    ‘’’

    //null判定(ゼロ追加)
    getHour = nullJudge(getHour);
    getMinute = nullJudge(getMinute);
    getSecond = nullJudge(getSecond)

    //アラーム条件
    if(getHour == hours && getMinute == minutes && getSecond == seconds){
    TEMPLE_BELL.play();
    }
    ‘’’
    がsalaryTimerの中に入っています
    読みづらい書き方ですみません!

    指定時間が過ぎてもタイマーは止まらない仕様です!!

    とても参考になりました!!
    帰ってコードを組んでみます!!
    またつまずいたらご連絡させていただきたいです!!!

  5. あれ?
    salaryTimerの中に入っているんですか!?
    だとするとif文の判定処理も定期実行しているので僕の指摘がクリアされていますね、、

    別の可能性なのですが、

    null判定ゼロ追加
    getHour = nullJudge(getHour);
    getMinute = nullJudge(getMinute);
    getSecond = nullJudge(getSecond)
    

    ここでエラー起きてませんか?
    というのは、事前にgetHourらを定義した素ぶりが見当たらないので。
    ブラウザでF12を表示して、コンソールを確認してみてください

  6. @Kobayashi0620

    Questioner

    コードを整理したのが下記になります。
    不要なコードは編集しました。
    下記のコードで現在作業を行っています!

    main.js
    const TEMPLE_BELL = document.getElementById("templeBell");
    
    //アラーム設定(時)
    const GET_HOUR = document.getElementById('setHour');
    GET_HOUR.addEventListener('change', () => {
        getHour = GET_HOUR.value;
        getHour = addZero (getHour);//設定時間の0追加
        const DISPLAY_VALUE = document.getElementById('displayHour');
        DISPLAY_VALUE.innerHTML = getHour;
    });
    
    //アラーム設定(分)
    const GET_MINUTE = document.getElementById('setMinute');
    GET_MINUTE.addEventListener('change', () => {
        getMinute = GET_MINUTE.value;
        getMinute = addZero (getMinute);//設定時間の0追加
        const DISPLAY_VALUE = document.getElementById('displayMinute');
        DISPLAY_VALUE.innerHTML = getMinute;
    });
    
    //アラーム設定(秒)
    const GET_SECONDE = document.getElementById('setSecond');
    GET_SECONDE.addEventListener('change', () => {
        getSecond = GET_SECONDE.value;
        getSecond = addZero (getSecond);//設定時間の0追加
        const DISPLAY_VALUE = document.getElementById('displaySecond');
        DISPLAY_VALUE.innerHTML = getSecond;
    });
    
    // 時間用、ゼロを追加する
    var addZero = function (value) {
        if (value < 10) {
            value = '0' + value;
        }
        return value;
    };
    
    //null判定(0代入)
    var nullJudge = function(value){
        if(value == null){
            value = '0' + 0;
        }
    }
    
    //スタート・ストップボタン機能
    document.getElementById('start_stop').addEventListener('click', function () {
        if (this.innerHTML === 'START') {
            start = new Date();
    
            id = setInterval(salaryTimer, 1000);
    
            // STOP ボタンにする
            this.innerHTML = 'STOP';
            this.classList.remove('btn-primary');
            this.classList.add('btn-danger');
        } else {
            clearInterval(id);
    
            // START ボタンにする
            this.innerHTML = 'START';
            this.classList.remove('btn-danger');
            this.classList.add('btn-primary');
        }
    });
    
    //表示処理
    var Timer = function () {
        var now = new Date();
    
        milli = now.getTime() - start.getTime(); //1ミリ秒時間計測
        centi = Math.floor(milli / TEN_DIV); //1センチ秒時間計測(ミリ秒/10)
        seconds = Math.floor(centi / HUNDRED_DIV); //1秒の計測(センチ秒/100)
        minutes = Math.floor(seconds / TIMES_CON); //1分の計測(秒/60)
        hours = Math.floor(minutes / TIMES_CON); //1時間の計測(分/60)
    
        seconds = seconds - minutes * TIMES_CON; //59秒まで行ったら次は00秒にする(秒-分*60)ー>桁の繰り上げ
        minutes = minutes - hours * TIMES_CON; //59分まで行ったら次は00分にする(分-時*60)ー>桁の繰り上げ
    
        //経過時間の0追加
        hours = addZero(hours);
        seconds = addZero(seconds);
        minutes = addZero(minutes);
    
        //null判定(0追加)
        getHour = nullJudge(getHour);
        getMinute = nullJudge(getMinute);
        getSecond = nullJudge(getSecond)
    
        document.getElementById('timer').innerHTML = hours + ':' + minutes + ':' + seconds;
    }
    
    
  7. 助かります
    やはり、getHourらを定義(var文)していないので、まずそこでエラーが起きるかと思いますが、コンソールはどうですか?

    コンソールの開き方↓
    https://www.sejuku.net/blog/27205

  8. @Kobayashi0620

    Questioner

    コンソールにあったエラーは下記のエラーのみでした
    127.0.0.1/:1 Unchecked runtime.lastError: The message port closed before a response was received.

  9. ありがとうございます。
    それは割といつも出てくる無害なエラーなのであまり気にしなくていいです。

    そして失礼しました。varなどの宣言文がなくともglobal変数が作成できるのですね。知らなかったです…

    3つ前に頂いたご返事のコードですが、まだそちらのコードで作業されてますか?

    saralyTimerTimerになっていたり、最初に言っていたif文が消えていたりと上手くいかなさそうなポイントがいくつか見当たりますが…

  10. @Kobayashi0620

    Questioner

    saralyTimerは自分が管理しやすいようにTimerに変更しました。

    //アラーム条件
    if(getHour == hours && getMinute == minutes && getSecond == seconds){
        TEMPLE_BELL.play();
    }
    

    に関してはどうしても動かなかったため、一度削除しました。

    その他命名が変わっている個所も自分が管理、わかりやすいように変更しているものです!!
    本当にわかりにくくてすみません(土下座)

    現在は上記のコードで稼働している状況です!!

  11. @Kobayashi0620

    Questioner

    .html
        <!-- アラーム時間設定 -->
        <input id="setHour" type="number" min="0" max="23" oninput="javascript: this.value = this.value.slice(0, 2)"
                oninput="inputChange()">
        <input id="setMinute" type="number" min="0" max="59" oninput="javascript: this.value = this.value.slice(0, 2)"
                oninput="inputChange()">
        <input id="setSecond" type="number" min="0" max="59" oninput="javascript: this.value = this.value.slice(0, 2)"
                oninput="inputChange()">
    
    .js
        //null判定(0追加)
        getHour = nullJudge(getHour);
        getMinute = nullJudge(getMinute);
        getSecond = nullJudge(getSecond)
    
    document.getElementById('settimer').innerHTML = getHour + ':' + getMinute + ':' + getSecond;
    
    

    上記コードで値がどうなっているかを確かめたところ

    01:02:03と表示してほしいところを
    
    undefined:undefined:undefined
    
    

    と表示されてしまいました。

    //アラーム条件
    if(getHour == hours && getMinute == minutes && getSecond == seconds){
        TEMPLE_BELL.play();
    }
    

    が反応しなかった原因の一つにこれが入ってるのではないかと考えています。
    上記のコードを別関数に記述して、setInterval()を実行するのももちろんなのですが、
    undefinedの解消方法がわからず、困っています!!!

  12. あ!!!本当ですね!!!

    
    var nullJudge = function(value){
        if(value == null){
            value = '0' + 0;
        }
    }
    
    

    ここが明確に良くないです。
    というのは、関数の引数(この場合value)の値を変えても、元々の変数はそのままです。

    
    getHour = nullJudge(getHour);
    
    

    ようするにvalueだけが変わってgetHourは変わりません
    そしてgetHourがundefined になっているのは、nullJudge()の値を代入しようとしているのですが、nullJudgeには返り値(return)がありません。この場合undefinedが代入されます

    要するに、nullJudgeにreturnを適切に記述してください

  13. @Kobayashi0620

    Questioner

    ありがとうございます!!
    return返したら条件式が動くようになりました!
    設定した時間に音が鳴りました

    本当に助かりました!!

  14. よかったです!!!!!!!!

上記のコードで試してみたのですが、うまくいきませんでした。

「うまくいきません」だけでは何がどううまくいかないのか閲覧者・回答者には分かりません。

簡単な話でコードを見ただけで分かるとか、コードをコピペして試してみればわかるというような話でもないようですし。

現状どれですか?

(1) スクリプトにエラーがあって全く動かない

(2) エラーはないがボタンをクリックしても無反応

(3) ボタンクリックで動き出すが設定した時間にアラームが出ない

(4) 上記はすべて期待通りに動くが音が出ない

たぶん (1) ではないかと想像してますが。

1Like

Comments

  1. @Kobayashi0620

    Questioner

    わかりにくい表記ですみませんでした!!
    (3)のボタンクリックでタイマー自体は動くが、指定時間になっても音が鳴らない状態です!!!
    何か分かりましたら教えていただけると幸いです!

  2. ボタンクリックでタイマー自体は動くが、指定時間になっても音が鳴らない状態

    その意味は、

    //アラーム条件
    if(getHour == hours && getMinute == minutes && getSecond == seconds){
        TEMPLE_BELL.play();
    }
    

    の if 文の条件は指定時間になると true になることは確認されており、条件が true になって TEMPLE_BELL.play() が実行されても音が鳴らないということですか?

    試しに TEMPLE_BELL.play(); に代えて alert("時間です"); とかにすると、指定時間になると alert は表示されるのでしょうか?

  3. もし、上のコメントで聞いた、

    if 文の条件は指定時間になると true になることは確認されており、条件が true になって TEMPLE_BELL.play() が実行されても音が鳴らないということですか?

    の答えが No ということであれば、文字列を比較するのでなく、質問にあったコード

    milli = now.getTime() - start.getTime(); //1ミリ秒時間計測
    

    の milli と、ユーザーがテキストボックスに入力する「アラーム時間設定」をミリ秒に変換して比較し、milli がそれより大きければアラームを鳴らすようにしてはいかがですか?

Your answer might help someone💌