The main issue with the jumping numbers was due to string concatenation and then using that string in the date functions. Parts of the code such as this:
if (min < 10){
min = "0" + min;
}
An example proving why this is happening
var end1 = new Date();
var minutesleft1 = 9;
console.log("Minutes to assign to current time");
console.log(end1.getMinutes() + minutesleft1); // Logs expected amount of minutes to calculate
end1.setMinutes(end1.getMinutes() + minutesleft1);
var end2 = new Date();
var minutesleft2 = "09";
console.log("Wrong Minutes to assign to current time");
console.log(end2.getMinutes() + minutesleft2); // Logs big number
end2.setMinutes(end2.getMinutes() + minutesleft2);
console.log(end1); // Logs expected result
console.log(end2); // Logs a time a day or so in the future
■
Explanation: If you were to set your start timer to 9 in the minutes var, it would immediately need to be padded with a 0 for display. Since you are now setting the minutesleft
variable to "09"
you are effectively doing 9 + "09"
when you call end.setMinutes(end.getMinutes()+minutesleft);
Once you concatenate a string "0"
to the number, you are effectively trying to do numeric operations with a string, which is causing unexpected results. This wasn't happening at the start, because your if statements weren't running yet and thus the min
, sec
, and msec
vars were still numeric. You should only pad the numbers when displaying them, not in the calculations themselves.
I replaced the string concatenation with a padding function borrowed from this post.
I also added a play function to reset your pause parameter. This makes the code more readable and easier for me to understand. Also, change it to paused at the start because the timer isn't running yet.
var minutesleft = 10;
var secondsleft = 05; // This would normally just be returned as 5, that's why we need the pad function for display
var millisecondsleft = 0;
var firstCall = true;
var paused = true;
var end;
var now;
function pause() {
paused = true;
}
function play() {
if (paused === false) // Shorcut out because we are already running
return;
paused = false;
cd();
}
function stop() {
end = now;
paused = true;
cd();
}
document.addEventListener("DOMContentLoaded", function(event) {
document.getElementById("cdtime").innerHTML = pad(minutesleft, 2) + ":" + pad(secondsleft, 2) + ":" + pad(millisecondsleft, 2);
});
function cd() {
if (firstCall) {
end = new Date();
end.setMinutes(end.getMinutes() + minutesleft);
end.setSeconds(end.getSeconds() + secondsleft);
end.setMilliseconds(end.getMilliseconds() + millisecondsleft);
firstCall = false;
}
now = new Date();
diff = end - now;
diff = new Date(diff);
var msec = diff.getMilliseconds();
var sec = diff.getSeconds();
var min = diff.getMinutes();
if (now >= end) {
clearTimeout(timerID);
document.getElementById("cdtime").innerHTML = 'POLICE IS HERE';
} else {
document.getElementById("cdtime").innerHTML = pad(min, 2) + ":" + pad(sec, 2) + ":" + pad(msec, 2);
}
if (paused === false) {
timerID = setTimeout("cd()", 10);
} else {
bool = true;
minutesleft = min;
secondsleft = sec;
millisecondsleft = msec;
}
}
function pad(n, width, z) {
z = z || '0';
n = n + '';
return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
}
<body>
<div id='timer'>
<button class='playerButtons' id='playT' type='submit' onclick='play()'>Play</button>
<button class='playerButtons' id='pauseT' type=' submit' onclick='pause()'>Pause</button>
<button class='playerButtons' id='stopT' type='submit' onclick='stop()'>Stop</button>
<div id='cdtime'></div>
</div>
</body>