4

I have this timer which works fine, but i need to be able to pause and resume it after that. i would appreciate it if someone could help me.

<html>
<head>
<script>
function startTimer(m,s)
    {
        document.getElementById('timer').innerHTML= m+":"+s;
        if (s==0)
            {
               if (m == 0)
                {
                    return;
                }
                else if (m != 0)
                {
                    m = m-1;
                    s = 60;
                }
        }
    s = s-1;
    t=setTimeout(function(){startTimer(m,s)},1000);
}


</script>
</head>

<body>
<button onClick = "startTimer(5,0)">Start</button>

<p id = "timer">00:00</p>
</body>
</html>
user2303981
  • 61
  • 1
  • 2
  • 3
  • If you're not working with _Date_ objects, you'll need to have your timer run much faster, keeping the counting variable up to date so that when `clearTimeout` is called, you've a more accurate reflection of where you were for when you resume. If you are working with date objects, record the pause time and resume time and you'll be able to calculate the difference and accommodate for it. – Paul S. Apr 21 '13 at 19:07

2 Answers2

12

I simply can't stand to see setTimeout(...,1000) and expecting it to be exactly 1,000 milliseconds. Newsflash: it's not. In fact, depending on your system it could be anywhere between 992 and 1008, and that difference will add up.

I'm going to show you a pausable timer with delta timing to ensure accuracy. The only way for this to not be accurate is if you change your computer's clock in the middle of it.

function startTimer(seconds, container, oncomplete) {
    var startTime, timer, obj, ms = seconds*1000,
        display = document.getElementById(container);
    obj = {};
    obj.resume = function() {
        startTime = new Date().getTime();
        timer = setInterval(obj.step,250); // adjust this number to affect granularity
                            // lower numbers are more accurate, but more CPU-expensive
    };
    obj.pause = function() {
        ms = obj.step();
        clearInterval(timer);
    };
    obj.step = function() {
        var now = Math.max(0,ms-(new Date().getTime()-startTime)),
            m = Math.floor(now/60000), s = Math.floor(now/1000)%60;
        s = (s < 10 ? "0" : "")+s;
        display.innerHTML = m+":"+s;
        if( now == 0) {
            clearInterval(timer);
            obj.resume = function() {};
            if( oncomplete) oncomplete();
        }
        return now;
    };
    obj.resume();
    return obj;
}

And use this to start/pause/resume:

// start:
var timer = startTimer(5*60, "timer", function() {alert("Done!");});
// pause:
timer.pause();
// resume:
timer.resume();
Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
  • how could i add a reset function, that reset starts the timer all over again? – Lukas Baliūnas Sep 08 '16 at 16:55
  • @LukasBaliūnas The variable `ms` keeps track of milliseconds remaining. You could add `obj.reset = function() {ms = seconds*1000;}` in the `startTimer` function, and call `timer.reset()` to implement the reset. Note however that if the timer has already completed, then `.resume()` won't do anything - you may need to delete the `obj.resume = function() {}` line to allow it to run a second time after a reset. – Niet the Dark Absol Sep 08 '16 at 19:42
  • another one, how would i add a function to add a second or decrease a second on the timer? would be executed either when the timer is running or it is paused. thanks – Lukas Baliūnas Sep 12 '16 at 10:27
  • `obj.modify = function(diff) {ms += diff*1000;}` - pass in `timer.modify(+1)` to add one second, `modifiy(-2)` to subtract two... – Niet the Dark Absol Sep 12 '16 at 11:54
2
<p id="timer">00:00</p>
<button id="start">Start</button>
<button id="pause">Pause</button>
<button id="resume">Resume</button>

var timer = document.getElementById("timer");
var start = document.getElementById("start");
var pause = document.getElementById("pause");
var resume = document.getElementById("resume");
var id;
var value = "00:00";

function startTimer(m, s) {
    timer.textContent = m + ":" + s;
    if (s == 0) {
        if (m == 0) {
            return;
        } else if (m != 0) {
            m = m - 1;
            s = 60;
        }
    }

    s = s - 1;
    id = setTimeout(function () {
        startTimer(m, s)
    }, 1000);
}

function pauseTimer() {
    value = timer.textContent;
    clearTimeout(id);
}

function resumeTimer() {
    var t = value.split(":");

    startTimer(parseInt(t[0], 10), parseInt(t[1], 10));
}

start.addEventListener("click", function () {
    startTimer(5, 0);
}, false);

pause.addEventListener("click", pauseTimer, false);

resume.addEventListener("click", resumeTimer, false);

on jsfiddle

There are a whole load of improvements that could be made but I'm sticking with the code that the OP posted for the OP's comprehension.

Here is an extended version to give you further ideas on jsfiddle

Xotic750
  • 22,914
  • 8
  • 57
  • 79