Home > OS >  Countdown timer with Pause/Resume Start/Stop function
Countdown timer with Pause/Resume Start/Stop function

Time:06-19

I am creating my function where I can manage pause and resume and reset the countdown. I have read various threads but I don't know how I merge that code with my own function. basically I am doing countdown, my default countdown is 15sec once I click start button that counter will start 15,14,13... in this between If I click pause the counter will pause and same will resume on click resume and finally the time will reset as 15 sec on click reset Please help, I create my own function with wonderful UI, how I add this above, pause, resume, reset function in my code.

// Credit: Mateusz Rybczonec

const FULL_DASH_ARRAY = 283;
const WARNING_THRESHOLD = 10;
const ALERT_THRESHOLD = 5;

const COLOR_CODES = {
  info: {
    color: "green"
  },
  warning: {
    color: "orange",
    threshold: WARNING_THRESHOLD
  },
  alert: {
    color: "red",
    threshold: ALERT_THRESHOLD
  }
};

const TIME_LIMIT = 15;
let timePassed = 0;
let timeLeft = TIME_LIMIT;
let timerInterval = null;
let remainingPathColor = COLOR_CODES.info.color;

document.getElementById("app").innerHTML = `
<div >
  <svg  viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
    <g >
      <circle  cx="50" cy="50" r="45"></circle>
      <path
        id="base-timer-path-remaining"
        stroke-dasharray="283"
        
        d="
          M 50, 50
          m -45, 0
          a 45,45 0 1,0 90,0
          a 45,45 0 1,0 -90,0
        "
      ></path>
    </g>
  </svg>
  <span id="base-timer-label" >${formatTime(
    timeLeft
  )}</span>
</div>
`;

function onTimesUp() {
  clearInterval(timerInterval);
}

function startTimer() {
  timerInterval = setInterval(() => {
    timePassed = timePassed  = 1;
    timeLeft = TIME_LIMIT - timePassed;
    document.getElementById("base-timer-label").innerHTML = formatTime(
      timeLeft
    );
    setCircleDasharray();
    setRemainingPathColor(timeLeft);

    if (timeLeft === 0) {
      onTimesUp();
      alert("Time Up");
    }
  }, 1000);
}

function formatTime(time) {
  const minutes = Math.floor(time / 60);
  let seconds = time % 60;

  if (seconds < 10) {
    seconds = `0${seconds}`;
  }

  return `${minutes}:${seconds}`;
}

function setRemainingPathColor(timeLeft) {
  const { alert, warning, info } = COLOR_CODES;
  if (timeLeft <= alert.threshold) {
    document
      .getElementById("base-timer-path-remaining")
      .classList.remove(warning.color);
    document
      .getElementById("base-timer-path-remaining")
      .classList.add(alert.color);
  } else if (timeLeft <= warning.threshold) {
    document
      .getElementById("base-timer-path-remaining")
      .classList.remove(info.color);
    document
      .getElementById("base-timer-path-remaining")
      .classList.add(warning.color);
  }
}

function calculateTimeFraction() {
  const rawTimeFraction = timeLeft / TIME_LIMIT;
  return rawTimeFraction - (1 / TIME_LIMIT) * (1 - rawTimeFraction);
}

function setCircleDasharray() {
  const circleDasharray = `${(
    calculateTimeFraction() * FULL_DASH_ARRAY
  ).toFixed(0)} 283`;
  document
    .getElementById("base-timer-path-remaining")
    .setAttribute("stroke-dasharray", circleDasharray);
}

function starTimer(){
    startTimer();
}

function pauseTimer(){
    //pause timer
}
function resumeTimer(){
    //resume timer
}
function resetTimer(){
    //reset time to 15sec by default;
}
body {
  font-family: sans-serif;
  display: grid;
  height: 100vh;
  place-items: center;
}

.base-timer {
  position: relative;
  width: 300px;
  height: 300px;
}

.base-timer__svg {
  transform: scaleX(-1);
}

.base-timer__circle {
  fill: none;
  stroke: none;
}

.base-timer__path-elapsed {
  stroke-width: 7px;
  stroke: grey;
}

.base-timer__path-remaining {
  stroke-width: 7px;
  stroke-linecap: round;
  transform: rotate(90deg);
  transform-origin: center;
  transition: 1s linear all;
  fill-rule: nonzero;
  stroke: currentColor;
}

.base-timer__path-remaining.green {
  color: rgb(65, 184, 131);
}

.base-timer__path-remaining.orange {
  color: orange;
}

.base-timer__path-remaining.red {
  color: red;
}

.base-timer__label {
  position: absolute;
  width: 300px;
  height: 300px;
  top: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 48px;
}
<div id="app"></div>

<input type="button" onclick="starTimer()" value="Start"/>
<input type="button" onclick="pauseTimer()" value="Pause"/>
<input type="button" onclick="resumeTimer()" value="Resume"/>
<input type="button" onclick="resetTimer()" value="Reset"/>

CodePudding user response:

function onTimesUp() {
  clearInterval(timerInterval);
  timerInterval = undefined;
}

All you have to do is clear the interval and save the state for pausing the timer, and on resume let the start value be the previous stopped value.

In case of resume, it's same as the start function you've written.

For resetting, clear the timer and just set everything to your initial value.

function starTimer() {
  if (!timerInterval) startTimer();
}


function pauseTimer() {
  onTimesUp();
}


function resumeTimer() {
  if (!timerInterval) startTimer();
}


function resetTimer() {
  if (timerInterval) {
    onTimesUp();
  }
  timePassed = 0;
  timeLeft = TIME_LIMIT;
  timerInterval = null;

  document.getElementById('base-timer-label').innerHTML = formatTime(timeLeft);
  setCircleDasharray();
  setRemainingPathColor(timeLeft);
}

Here is a link to working codepen

CodePudding user response:

To pause the timer, you need to clear the interval.
To resume, it is the same as starting.
To reset, you need to wrap the document.getElementById("app").innerHTML = with a named function, so you can call it again. See init below. Additionnally, you need to restore the initial variables.

// Credit: Mateusz Rybczonec

const FULL_DASH_ARRAY = 283;
const WARNING_THRESHOLD = 10;
const ALERT_THRESHOLD = 5;

const COLOR_CODES = {
  info: {
    color: "green"
  },
  warning: {
    color: "orange",
    threshold: WARNING_THRESHOLD
  },
  alert: {
    color: "red",
    threshold: ALERT_THRESHOLD
  }
};

let TIME_LIMIT = 15;
let timePassed = 0;
let timeLeft = TIME_LIMIT;
let timerInterval = null;
let remainingPathColor = COLOR_CODES.info.color;

function init() {
  document.getElementById("app").innerHTML = `
  <div >
    <svg  viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
      <g >
        <circle  cx="50" cy="50" r="45"></circle>
        <path
          id="base-timer-path-remaining"
          stroke-dasharray="283"
          
          d="
            M 50, 50
            m -45, 0
            a 45,45 0 1,0 90,0
            a 45,45 0 1,0 -90,0
          "
        ></path>
      </g>
    </svg>
    <span id="base-timer-label" >${formatTime(
      timeLeft
    )}</span>
  </div>
  `;
}

function onTimesUp() {
  clearInterval(timerInterval);
  resetTimer();
}

function startTimer() {
  timerInterval = setInterval(() => {
    timePassed = timePassed  = 1;
    timeLeft = TIME_LIMIT - timePassed;
    document.getElementById("base-timer-label").innerHTML = formatTime(
      timeLeft
    );
    setCircleDasharray();
    setRemainingPathColor(timeLeft);

    if (timeLeft === 0) {
      onTimesUp();
      alert("Time Up");
    }
  }, 1000);
}

function formatTime(time) {
  const minutes = Math.floor(time / 60);
  let seconds = time % 60;

  if (seconds < 10) {
    seconds = `0${seconds}`;
  }

  return `${minutes}:${seconds}`;
}

function setRemainingPathColor(timeLeft) {
  const {
    alert,
    warning,
    info
  } = COLOR_CODES;
  if (timeLeft <= alert.threshold) {
    document
      .getElementById("base-timer-path-remaining")
      .classList.remove(warning.color);
    document
      .getElementById("base-timer-path-remaining")
      .classList.add(alert.color);
  } else if (timeLeft <= warning.threshold) {
    document
      .getElementById("base-timer-path-remaining")
      .classList.remove(info.color);
    document
      .getElementById("base-timer-path-remaining")
      .classList.add(warning.color);
  }
}

function calculateTimeFraction() {
  const rawTimeFraction = timeLeft / TIME_LIMIT;
  return rawTimeFraction - (1 / TIME_LIMIT) * (1 - rawTimeFraction);
}

function setCircleDasharray() {
  const circleDasharray = `${(
    calculateTimeFraction() * FULL_DASH_ARRAY
  ).toFixed(0)} 283`;
  document
    .getElementById("base-timer-path-remaining")
    .setAttribute("stroke-dasharray", circleDasharray);
}

function starTimer() {
  startTimer();
}

function pauseTimer() {
  //pause timer
  clearInterval(timerInterval);
}

function resumeTimer() {
  //resume timer
  startTimer();
}

function resetTimer() {
  TIME_LIMIT = 15;
  timePassed = 0;
  timeLeft = TIME_LIMIT;
  init();
}

// On page load
init();
body {
  font-family: sans-serif;
  display: grid;
  height: 100vh;
  place-items: center;
}

.base-timer {
  position: relative;
  width: 300px;
  height: 300px;
}

.base-timer__svg {
  transform: scaleX(-1);
}

.base-timer__circle {
  fill: none;
  stroke: none;
}

.base-timer__path-elapsed {
  stroke-width: 7px;
  stroke: grey;
}

.base-timer__path-remaining {
  stroke-width: 7px;
  stroke-linecap: round;
  transform: rotate(90deg);
  transform-origin: center;
  transition: 1s linear all;
  fill-rule: nonzero;
  stroke: currentColor;
}

.base-timer__path-remaining.green {
  color: rgb(65, 184, 131);
}

.base-timer__path-remaining.orange {
  color: orange;
}

.base-timer__path-remaining.red {
  color: red;
}

.base-timer__label {
  position: absolute;
  width: 300px;
  height: 300px;
  top: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 48px;
}
<div id="app"></div>

<input type="button" onclick="starTimer()" value="Start" />
<input type="button" onclick="pauseTimer()" value="Pause" />
<input type="button" onclick="resumeTimer()" value="Resume" />
<input type="button" onclick="resetTimer()" value="Reset" />


Your next task will be to reuse the buttons. So after on click on "Start", the button will turn to "Pause". Once paused, the button will be "Resume"... And will be "Start" after a "reset" click (which has to be another button).
  • Related