skip to Main Content

when I click start, the count begins, and the start button hides and shows the pause and reset buttons. If I click start and reset repeatedly, the count will no longer count correctly and the reset buttons and pause buttons won’t even matter anymore.

var c = 0;
var t;

function count(){
  document.getElementById("count").innerHTML = c;
  c = c + 1;
  t = setTimeout(count, 1000);
}

function start(){
    count();
    document.getElementById("startb").style.display = "none";
    document.getElementById("pauseb").style.display = "inline";
}

function pause(){
  clearTimeout(t);
  document.getElementById("startb").style.display = "inline";
  document.getElementById("pauseb").style.display = "none";
  document.getElementById("startb").innerHTML = "Resume";
  document.getElementById("resetb").style.display = "inline";
}

function reset(){
  c = 0;
  clearTimeout(t);
  document.getElementById("count").innerHTML = c;
  document.getElementById("startb").style.display = "inline";
  document.getElementById("startb").innerHTML = "Start";
  document.getElementById("pauseb").style.display = "none";
  document.getElementById("resetb").style.display = "none";
}
*{
    margin: 0;
    padding: 0;
    font-family: Arial;
  }
  body{
    background-color: #333;
    color: black;
  }
  button{
    width: 100px;
    height: 30px;
    line-height: 30px;
    text-align: center;
    color: #000;
    background-color: #c3c3c3;
    border: 1px solid #000;
  }
  #count{
      font-size: 175px;
  }
  #startb {
    background-color: #800080;
    border-color: #220022;
    color: #2e002e;
  }
  #pauseb {
    display: none;
    background-color: black;
    color: #b6b6b6;
  }
  #resetb {
    display: none;
    background-color:red;
    color: #3b0000;
    border-color: #3b0000;
    font-weight: bold;
  }

  #lapb{
    display: none;
    background-color: #008800;
    color: black;
    border-color: darkgreen;
    font-weight: bold;
  }
<!DOCTYPE html>
<html>
<head>
<title>Stopwatch</title>
<script src="Stopwatch.js"></script>
<link rel="stylesheet" href="Stopwatch.css">
</head>
<body>
<h1>Stopwatch</h1>
<span id="count">0</span><br />
<button id="startb" onClick="start()">Start</button>
<button id="pauseb" onClick="pause()">Pause</button>
<button id="resetb" onClick="reset()">Reset</button>
<button id="lapb" onClick="lap()">Lap</button>
</body>
</html>

i havent tried anything im guessing multiple instances of the start function are being processed, im thinking if else statements somewhere could prevent this.

2

Answers


  1. Try this. It has precision upto milliseconds

    var startTime;
    var elapsedTime = 0;
    var timerInterval;
    
    function start() {
      startTime = Date.now() - elapsedTime;
      if (!timerInterval) {
        timerInterval = setInterval(updateTime, 10);
      }
    }
    
    function pause() {
      clearInterval(timerInterval);
      timerInterval = null;
    }
    
    function reset() {
      clearInterval(timerInterval);
      timerInterval = null;
      elapsedTime = 0;
      var formattedTime = formatTime(elapsedTime);
      document.querySelector(".time").textContent = formattedTime;
    }
    
    function updateTime() {
      var currentTime = Date.now();
      elapsedTime = currentTime - startTime;
      var formattedTime = formatTime(elapsedTime);
      document.querySelector(".time").textContent = formattedTime;
    }
    
    function formatTime(time) {
      var hours = Math.floor(time / 3600000);
      var minutes = Math.floor((time % 3600000) / 60000);
      var seconds = Math.floor((time % 60000) / 1000);
      var milliseconds = Math.floor((time % 1000) / 10);
    
      return (
        pad(hours, 2) +
        ":" +
        pad(minutes, 2) +
        ":" +
        pad(seconds, 2) +
        "." +
        pad(milliseconds, 2)
      );
    }
    
    function pad(value, count) {
      var padding = "";
      for (var i = 0; i < count; i++) {
        padding += "0";
      }
      return (padding + value).slice(-count);
    }
    .container {
      text-align: center;
      margin-top: 100px;
    }
    
    .time {
      font-size: 48px;
      margin-bottom: 20px;
    }
    
    .buttons {
      margin-top: 20px;
    }
    <!DOCTYPE html>
    <html>
    
    <head>
      <title>Stopwatch</title>
    </head>
    
    <body>
      <div class="container">
        <div class="time">00:00:00</div>
        <div class="buttons">
          <button onclick="start()">Start/Resume</button>
          <button onclick="pause()">Pause</button>
          <button onclick="reset()">Reset</button>
        </div>
      </div>
    </body>
    
    </html>

    Edit:

    Request animation frame is not the right solution for this use case for the following reasons:

    1. There is no animation going on in here.
    2. Even if there was animation going on requestAnimationFrame calls are paused when running in background tabs or hidden iframe tags which is not ideal for a stopwatch app

    Read more about requestAnimationFrame on MDN

    Login or Signup to reply.
    • Don’t use setInterval (specially not set to such an expensive ms interval) when in need to do frequent updates to your UI. You don’t want to cog the main thread with setInterval, instead use the absolute winner in performance, and that’s the Window.requestAnimationFrame.
    • In HTML, don’t use IDs. Why not have several watches on a single page? If you use ID-s you code becomes tightly coupled to one element only. Use classes instead
    • Avoid the use of Element.style from JS, instead use the Element.classList methods like .add(), .remove()

    Here’s a better and performant example for a stopwatch that previews h+:m:s.mil

    const pad = (int, pad) => String(int).padStart(pad, "0");
    
    const stopwatch = (el) => {
    
      const elCount = el.querySelector(".stopwatch-count");
      const elStart = el.querySelector(".stopwatch-start");
      const elResume = el.querySelector(".stopwatch-resume");
      const elPause = el.querySelector(".stopwatch-pause");
      const elReset = el.querySelector(".stopwatch-reset");
    
      let timeStart;
      let timeElapsed;
      let raf;
    
      const draw = () => {
        const mil = timeElapsed % 1000;
        const sec = Math.floor(timeElapsed / 1000 % 60);
        const min = Math.floor(timeElapsed / 1000 / 60 % 60);
        const hou = Math.floor(timeElapsed / 1000 / 60 / 60);
        elCount.textContent = `${pad(hou)}:${pad(min, 2)}:${pad(sec, 2)}.${pad(mil, 3)}`;
      };
    
      const count = () => {
        timeElapsed = Date.now() - timeStart;
        draw();
        raf = requestAnimationFrame(count);
      };
    
      const start = () => {
        timeStart = Date.now() - timeElapsed;
        el.classList.remove("isPaused");
        el.classList.add("isStarted");
        count();
      };
    
      const pause = () => {
        cancelAnimationFrame(raf);
        el.classList.add("isPaused");
      };
    
      const reset = () => {
        cancelAnimationFrame(raf);
        
        timeStart = 0;
        timeElapsed = 0;
        timeDiff = 0;
        
        el.classList.remove("isPaused");
        el.classList.remove("isStarted");
        
        draw();
      };
    
      // Events:
      elStart.addEventListener("click", start);
      elPause.addEventListener("click", pause);
      elResume.addEventListener("click", start);
      elReset.addEventListener("click", reset);
    
      // Init:
      reset();
    };
    
    // Initialize:
    document.querySelectorAll(".stopwatch").forEach(stopwatch);
    * {
      box-sizing: border-box;
      margin: 0;
      font-family: Arial;
    }
    
    button {
      border: 1px solid #000;
      color: #fff;
      min-width: 5rem;
      padding: 0.6em;
    }
    
    .stopwatch-count {
      font-size: 3rem;
    }
    
    .stopwatch-start {
      background-color: green;
    }
    
    .stopwatch-resume {
      display: none;
      background-color: blue;
    }
    
    .stopwatch-pause {
      display: none;
      background-color: black;
    }
    
    .stopwatch-reset {
      display: none;
      background-color: red;
    }
    
    .isStarted .stopwatch-start {
      display: none;
    }
    
    .isStarted .stopwatch-pause {
      display: initial;
    }
    
    .isPaused .stopwatch-pause {
      display: none;
    }
    
    .isPaused .stopwatch-reset {
      display: initial;
    }
    
    .isPaused .stopwatch-resume {
      display: initial;
    }
    <div class="stopwatch">
      <span class="stopwatch-count"></span><br />
      <button class="stopwatch-start">Start</button>
      <button class="stopwatch-resume">Resume</button>
      <button class="stopwatch-pause">Pause</button>
      <button class="stopwatch-reset">Reset</button>
    </div>

    and will work for any number of stopwatch on a single page.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search