自家焙煎コーヒー記録アプリ(8バッチまで記録可)

こんにちはハッピーサトです。

PCでもスマホでも使いやすいシンプルな焙煎記録アプリを開発しました。

イメージ画像

タイマーには#1~#8と番号を付けているので、当日の焙煎メニューと連動させてご活用下さい☆彡

>使い方はコチラ<

コーヒー自家焙煎タイマー


#1
00:00



#2
00:00



#3
00:00



#4
00:00



#5
00:00



#6
00:00



#7
00:00



#8
00:00




プログラム内容

アプリのHTML、CSS、JAVAコードを公開しておきます。

HTMLコード

<p><!-- 各タイマーのコンテナ。以下をタイマーの数だけ繰り返します --><br />
<!-- タイマー #1 --></p>
<div id="timer1" class="timer-container">
<div class="timer-header">
<div class="timer-title">#1</div>
<div class="timer-display">00:00</div>
</div>
<div class="buttons-container"><button class="start">Start</button><br />
<button class="first-crack">1st<br />
Crack</button><br />
<button class="second-crack">2nd<br />
Crack</button><br />
<button class="stop-reset">Stop<br />
Reset</button></div>
<div class="crack-times"></div>
</div>
<div id="timer2" class="timer-container">
<div class="timer-header">
<div class="timer-title">#2</div>
<div class="timer-display">00:00</div>
</div>
<div class="buttons-container"><button class="start">Start</button><br />
<button class="first-crack">1st<br />
Crack</button><br />
<button class="second-crack">2nd<br />
Crack</button><br />
<button class="stop-reset">Stop<br />
Reset</button></div>
<div class="crack-times"></div>
</div>
<div id="timer3" class="timer-container">
<div class="timer-header">
<div class="timer-title">#3</div>
<div class="timer-display">00:00</div>
</div>
<div class="buttons-container"><button class="start">Start</button><br />
<button class="first-crack">1st<br />
Crack</button><br />
<button class="second-crack">2nd<br />
Crack</button><br />
<button class="stop-reset">Stop<br />
Reset</button></div>
<div class="crack-times"></div>
</div>
<div id="timer4" class="timer-container">
<div class="timer-header">
<div class="timer-title">#4</div>
<div class="timer-display">00:00</div>
</div>
<div class="buttons-container"><button class="start">Start</button><br />
<button class="first-crack">1st<br />
Crack</button><br />
<button class="second-crack">2nd<br />
Crack</button><br />
<button class="stop-reset">Stop<br />
Reset</button></div>
<div class="crack-times"></div>
</div>
<div id="timer5" class="timer-container">
<div class="timer-header">
<div class="timer-title">#5</div>
<div class="timer-display">00:00</div>
</div>
<div class="buttons-container"><button class="start">Start</button><br />
<button class="first-crack">1st<br />
Crack</button><br />
<button class="second-crack">2nd<br />
Crack</button><br />
<button class="stop-reset">Stop<br />
Reset</button></div>
<div class="crack-times"></div>
</div>
<div id="timer6" class="timer-container">
<div class="timer-header">
<div class="timer-title">#6</div>
<div class="timer-display">00:00</div>
</div>
<div class="buttons-container"><button class="start">Start</button><br />
<button class="first-crack">1st<br />
Crack</button><br />
<button class="second-crack">2nd<br />
Crack</button><br />
<button class="stop-reset">Stop<br />
Reset</button></div>
<div class="crack-times"></div>
</div>
<div id="timer7" class="timer-container">
<div class="timer-header">
<div class="timer-title">#7</div>
<div class="timer-display">00:00</div>
</div>
<div class="buttons-container"><button class="start">Start</button><br />
<button class="first-crack">1st<br />
Crack</button><br />
<button class="second-crack">2nd<br />
Crack</button><br />
<button class="stop-reset">Stop<br />
Reset</button></div>
<div class="crack-times"></div>
</div>
<div id="timer8" class="timer-container">
<div class="timer-header">
<div class="timer-title">#8</div>
<div class="timer-display">00:00</div>
</div>
<div class="buttons-container"><button class="start">Start</button><br />
<button class="first-crack">1st<br />
Crack</button><br />
<button class="second-crack">2nd<br />
Crack</button><br />
<button class="stop-reset">Stop<br />
Reset</button></div>
<div class="crack-times"></div>
</div>
<p><script src="script.js"></script></p>

CSSコード

.crack-times {
    font-size: 14px;
    text-align: left;
    margin-top: 0px;
    margin-bottom: 0; /* クラックタイム表示部分の下部マージンを減らす */
}

.timer-container {
    background-color: #fff;
    border: none;
    padding: 10px;
    margin-bottom: 10px; /* タイマーコンテナ間の間隔 */
    text-align: center;
    border-bottom: 1px solid #ddd; /* 各タイマーコンテナの下部にボーダーを追加 */
}

/* 最後のタイマーコンテナにはボーダーを追加しない */
.timer-container:last-child {
    border-bottom: none;
}

.timer-header {
    display: flex;
    justify-content: center;
    align-items: center;
    margin-bottom: 0px;
}

.timer-title {
    font-size: 24px;
    font-weight: bold;
    margin-right: 10px;
    order: -1; /* タイトルを左に移動 */
}

.timer-display {
    background-color: black;
    color: white;
    font-size: 42px;
    padding: 0px 45px;
    margin: 3px 0;
}

.buttons-container {
    display: flex;
    justify-content: center;
    flex-wrap: nowrap;
}

button {
    background-color: #8B4513; /* 薄茶色より少し濃い茶色 */
    color: white;
    border: none;
    padding: 10px 10px;
    margin: 5px;
    font-size: 16px;
    cursor: pointer;
    min-width: 80px;

JAVAコード

document.addEventListener('DOMContentLoaded', function() {
    const timers = document.querySelectorAll('.timer-container');

    timers.forEach((timerContainer, index) => {
        let startTime = 0;
        let timerInterval = null;
        let firstCrackTimes = [];
        let secondCrackTimes = [];
        let stopTime = 0;
        let resetCount = 0;

        const timerDisplay = timerContainer.querySelector('.timer-display');
        const crackTimesDisplay = timerContainer.querySelector('.crack-times');

        function formatTime(time) {
            const minutes = Math.floor(time / 60000).toString().padStart(2, '0');
            const seconds = ((time % 60000) / 1000).toFixed(0).padStart(2, '0');
            return `${minutes}:${seconds}`;
        }

        function updateTimerDisplay(time) {
            timerDisplay.textContent = formatTime(time);
        }

        function updateCrackTimesDisplay() {
            const firstCracks = firstCrackTimes.map(t => formatTime(t)).join(', ');
            const secondCracks = secondCrackTimes.map(t => formatTime(t)).join(', ');
            const stopDisplay = stopTime ? `Stop: ${formatTime(stopTime)}` : '';

            crackTimesDisplay.innerHTML = [
                firstCracks ? `1st Crack: ${firstCracks}` : '',
                secondCracks ? `2nd Crack: ${secondCracks}` : '',
                stopDisplay
            ].filter(Boolean).join('<br>');
        }

        function startTimer() {
            if (!timerInterval) {
                startTime = Date.now() - (stopTime ? stopTime : 0);
                timerInterval = setInterval(() => {
                    updateTimerDisplay(Date.now() - startTime);
                }, 1000);
            }
        }

        function recordCrack(crackArray) {
            if (timerInterval && crackArray.length < 2) {
                crackArray.push(Date.now() - startTime);
                updateCrackTimesDisplay();
            }
        }

        function stopResetTimer() {
            if (timerInterval) {
                clearInterval(timerInterval);
                stopTime = Date.now() - startTime;
                timerInterval = null;
                updateCrackTimesDisplay();
                resetCount = 0;
            } else {
                resetCount++;
                if (resetCount === 3) {
                    timerDisplay.textContent = '00:00';
                    firstCrackTimes = [];
                    secondCrackTimes = [];
                    stopTime = 0;
                    updateCrackTimesDisplay();
                    resetCount = 0;
                }
            }
        }

        timerContainer.querySelector('.start').addEventListener('click', startTimer);
        timerContainer.querySelector('.first-crack').addEventListener('click', () => recordCrack(firstCrackTimes));
        timerContainer.querySelector('.second-crack').addEventListener('click', () => recordCrack(secondCrackTimes));
        timerContainer.querySelector('.stop-reset').addEventListener('click', stopResetTimer);
    });
});