I have a stopwatch controlled by pressing space which looks something like this:
let startTime;
let stopTime;
let timerStatus = 0;
let timePassed;
let interval;
window.onkeyup = function(event) {
if(event.keyCode == 32) {
if(timerStatus == 0) {
start();
display();
} else if(timerStatus == 2) {
timerStatus = 0;
}
}
}
window.onkeydown = function(event) {
if(event.keyCode == 32) {
if(timerStatus == 1) {
stop();
} else if(timerStatus == 0) {
$("#time").html("0.00");
}
}
}
function start() {
let d = new Date();
startTime = d.getTime();
timerStatus = 1;
}
function stop() {
let d = new Date();
stopTime = d.getTime();
clearInterval(interval);
timerStatus = 2;
}
function display() {
interval = setInterval(function() {
let now = Date.now();
timePassed = now - startTime;
let seconds = Math.floor(timePassed / 1000);
let minutes = Math.floor(timePassed / 60000);
let milliseconds = timePassed % 1000;
//getting rid of third decimal place
milliseconds = milliseconds.toString().slice(0, -1);
parseFloat(milliseconds);
console.log(milliseconds);
let time = minutes + ":" + seconds + "." + milliseconds;
if(milliseconds < 10) milliseconds = "0" + milliseconds;
if(milliseconds < 1) milliseconds = "0" + milliseconds;
if(minutes < 1) {
time = seconds + "." + milliseconds;
}
$("#time").html(time);
}, 10);
}
<h1 id='time'>0.00</h1>
This works just fine, apart from the fact that sometimes when pressing space to stop the stopwatch, it will instead stop and then immediately start the stopwatch again. Often after this happens once, you then can't ever stop the stopwatch until the page is reloaded.
Any help would be greatly appreciated.
Thanks.
Related
So what I'm trying to do is to self replicate a Rubik's cube timer like cstimer.net
What I do is detect a spacebar key press and it is meant to start a timer, however it only adds 1 millisecond at a press instead of a continuous timer, what I'm thinking is to find a way to continuously hold the spacebar if the javascript file, how do I fix this?
const minute = document.getElementById("minute");
const second = document.getElementById("second");
const millisecond = document.getElementById("millisecond");
let ms = 0;
let sec = 0;
let min = 0;
const start = () => console.log("start")
document.addEventListener('keypress', function(event) {
if (event.code === "Space") {
timeoutId = setTimeout(function() {
ms = parseInt(ms);
sec = parseInt(sec);
min = parseInt(min);
ms++;
if (ms == 100) {
sec = sec + 1;
ms = 0;
}
if (sec == 60) {
min = min + 1;
sec = 0;
}
if (ms < 10) {
ms = '0' + ms;
}
if (sec < 10) {
sec = '0' + sec;
}
if (min < 10) {
min = '0' + min;
}
minute.innerHTML = min;
second.innerHTML = sec;
millisecond.innerHTML = ms;
start();
}, 10);
}
});
<span id="minute"></span>
<span id="second"></span>
<span id="millisecond"></span>
setTimeout only triggers the timer function once; instead you should use requestAnimationFrame to update the timer every repaint.
Let's also fix the unreliableness of the timer implementation as mentioned by #gre_gor. Instead of adding to the ms counter each time, store the initial time (via Date.now()) and then calculate the elapsed milliseconds each time.
const minute = document.getElementById("minute");
const second = document.getElementById("second");
const millisecond = document.getElementById("millisecond");
let initialTime;
function timer() {
let ms = Date.now() - initialTime;
let sec = Math.floor(ms / 1000);
ms = ms % 1000;
let min = Math.floor(sec / 60);
sec = sec % 60;
minute.innerHTML = min;
second.innerHTML = sec;
millisecond.innerHTML = ms;
requestAnimationFrame(timer);
}
document.addEventListener('keypress', function(event) {
if (event.code === "Space") {
initialTime = Date.now();
requestAnimationFrame(timer);
}
});
<span id="minute"></span>
<span id="second"></span>
<span id="millisecond"></span>
If you need to stop the timer, it's a bit trickier for a rAF loop than for setTimeout - see How to stop a requestAnimationFrame recursion/loop?.
This one is more precise and has animation built in. (You could be even more precise using function like performance.now())
const timer = document.getElementById("timer");
var start_time = null;
var state = "paused";
function draw() {
if (state == "playing") {
var diff = Date.now() - start_time
var time = (new Date(diff).toISOString().slice(11, 23));
timer.innerHTML = time;
}
}
function loop() {
draw();
requestAnimationFrame(loop)
}
loop();
document.addEventListener('keypress', function(event) {
if (event.code === "Space") {
if (state == "paused") {
state = "playing";
start_time = Date.now()
return;
}
if (state == "playing") {
state = "paused";
start_time = null;
return;
}
}
});
#timer {
font-size:48px;
}
Press [space]<br>
<span id="timer"></span>
I would like to make the time display that time 01: 02: 03:43, but I get 0:0:00000000000000001:15 I tired add 0 in dev **0:0:0:0, but it doesn't work. Is it good code for timer?
var hour = 0;
var min = 0;
var sec = 0;
var miliSec = 0;
var timer;
function callTimer() {
miliSec++;
if (miliSec < 100) {
if (miliSec === 99) {
miliSec = 0;
sec++;
if (sec === 60) {
sec = 0;
min++;
if (min === 60) {
min = 0;
hour++
}
}
}
} else {
miliSec = 0;
}
document.getElementById("#timer").innerHTML = hour + ":" + min + ":" + sec + ":" + miliSec;
}
function start() {
document.getElementById("#start").disabled = true;
timer = setInterval(callTimer, 10);
}
function stop() {
document.getElementById("#start").disabled = false;
clearInterval(timer);
}
function reset() {
stop();
hour = 0;
min = 0;
sec = 0;
miliSec = 0;
document.getElementById("#timer").innerHTML = hour + ":" + min + ":" + sec + ":" + miliSec;
}
I have to give more details about this problem, because validation don't allow post me that problem. Well I wrote this ;)
I added toString().padStart(2, "0") to each element.
You can read more about padStart() here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padStart
var hour = 0;
var min = 0;
var sec = 0;
var miliSec = 0;
var timer;
function callTimer() {
miliSec++;
if (miliSec < 100) {
if (miliSec === 99) {
miliSec = 0;
sec++;
if (sec === 60) {
sec = 0;
min++;
if (min === 60) {
min = 0;
hour++
}
}
}
} else {
miliSec = 0;
}
/* Add 0 every time -- This does not work because it changes the type from a number to string, causing the unexpected behavior
if (sec < 10) {
sec = "0" + sec;
}else{
sec;
}
*/
document.getElementById("#timer").innerHTML = hour.toString().padStart(2, "0") + ":" + min.toString().padStart(2, "0") + ":" + sec.toString().padStart(2, "0") + ":" + miliSec;
}
function start() {
document.getElementById("#start").disabled = true;
clearInterval(timer);//stop any previous interval before starting another
timer = setInterval(callTimer, 10);
}
function stop() {
document.getElementById("#start").disabled = false;
clearInterval(timer);
}
function reset() {
stop();
hour = 0;
min = 0;
sec = 0;
miliSec = 0;
document.getElementById("#timer").innerHTML = hour.toString().padStart(2, "0") + ":" + min.toString().padStart(2, "0") + ":" + sec.toString().padStart(2, "0") + ":" + miliSec;
}
<nav class="controls">
START
STOP
CLEAR
</nav>
<div id="#timer">00:00:00:0</div>
Instead of keeping four counters, you could very easily get the delta in milliseconds on every run of the callTimer callback and then do a few simple calculations to get seconds, hours, weeks... whatever the time units you may need. Something along these lines should do the trick:
var startTS
function formatNumber(num, digits) {
return `000${num}`.slice(-digits) // Get last X digits (in our case will be either 2 or 3)
}
function callTimer() {
const currentTS = Date.now()
const elapsed = currentTS - startTS // Elapsed time in milliseconds
const elapsedSec = Math.floor(elapsed/1000) // Whole seconds
const elapsedMin = Math.floor(elapsedSec/60) // Whole minutes
const elapsedHr = Math.floor(elapsedMin/60) // Whole hours
...
const msec = elapsed % 1000 // Get the "milliseconds" part
const sec = elapsedSec % 60 // Seconds part
const min = elapsedMin % 60 // Minutes
const hr = elapsedHr % 60 // Hours
const fmtStr = `${formatHumber(hr,2)}:${formatNumber(min,2)}:${formatNumber(sec,2)}.${formatNumber(msec,3)}`
document.getElementById("#timer").innerHTML = fmtStr
}
...
function start() {
document.getElementById("#start").disabled = true;
startTS = Date.now()
timer = setInterval(callTimer, 10);
}
...
Hope that helps!
I have to create a stopwatch that has a start button, a stop button and a pause button. I have so far reached start and stop buttons but the are not working. What is the issue. I have to even go ahead and create a pause button , how to do that. Please help.
var seconds = 0,
minutes = 0,
hours = 0,
timer;
var toStop = false;
var h1 = document.getElementsByTagName('h1')[0];
function start() {
while (!toStop) {
seconds++;
if (seconds >= 60) {
seconds = 0;
minutes++;
if (minutes >= 60) {
minutes = 0;
hours++;
if (hours >= 12) {
hours = 0;
toStop = true;
stop();
}
}
}
document.getElementById("h").value = (hours ? (hours > 9 ? hours : "0" + hours) : "00") + ":" +
(minutes ? (minutes > 9 ? minutes : "0" + minutes) : "00") + ":" +
(seconds > 9 ? seconds : "0" + seconds);
myTimer();
}
}
function stop() {
clearTimeout(myTimer());
console.log(timer);
}
function myTimer() {
timer = setInterval(start, 1000);
console.log(timer);
}
function clear() {
document.getElementById("h").value = "00:00:00";
seconds = 0;
minutes = 0;
hours = 0;
}
<h1 id="h"><time>00:00:00</time></h1>
<button onclick="myTimer()">Start</button>
<button onclick="stop()">Stop</button>
<button onclick="clear()">Clear</button>
while (!toStop) {
Get rid of that. The start() func should just calc and print elapsed time. Also, don't call myTimer(); in start(). You already call setInterval() which will call start() every second.
Instead of calculating the elapsed time the way you do, you should create a Date object in myTimer(). Then in start() create another one. To calc elapsed time, subtract one from the other.
And since you call setInterval() you should call clearInterval() to stop.
var startTime = null;
var timer = null;
var totalTime = 0;
function getElapsedTime()
{
var now = new Date();
return (now - startTime) / 1000;
}
function start() {
// Calculate elapsed time since start btn was hit
var elapsedTime = getElapsedTime();
// Add prev times (from pause)
elapsedTime += totalTime;
// elapsedTime is in seconds. Calc, h/m/s
var hours = Math.floor(elapsedTime / (60 * 60));
elapsedTime %= (60 * 60);
var minutes = Math.floor(elapsedTime / 60);
elapsedTime %= 60;
var seconds = Math.floor(elapsedTime);
if (hours > 12) {
stop();
}
// Build string
var timeStr = (hours < 10 ? "0" : "") + hours + ":" +
(minutes < 10 ? "0" : "") + minutes + ":" +
(seconds < 10 ? "0" : "") + seconds;
// Update timer
document.getElementById("h").textContent = timeStr;
document.getElementById("h").value = timeStr;
}
var amPaused = false;
function pause()
{
if (amPaused) {
amPaused = false;
startTime = new Date();
timer = setInterval(start, 1000);
}
else {
amPaused = true;
totalTime += getElapsedTime();
if (timer) {
clearInterval(timer);
timer = null;
}
}
}
function stop() {
if (timer) {
clearInterval(timer);
timer = null;
}
amPaused = false;
document.getElementById("start").disabled = false;
document.getElementById("stop").disabled = true;
document.getElementById("pause").disabled = true;
}
function myTimer() {
stop();
totalTime = 0;
// Store the start time
startTime = new Date();
// Start the timer
timer = setInterval(start, 1000);
document.getElementById("start").disabled = true;
document.getElementById("stop").disabled = false;
document.getElementById("pause").disabled = false;
}
<h1><time id="h">00:00:00</time></h1>
<button onclick="myTimer()" id="start">▶</button>
<button onclick="stop()" id="stop" disabled="true">■</button>
<button onclick="pause()" id="pause" disabled="true">⏸</button>
<html>
<head>
<title>
Stop-Watch
</title>
</head>
<body>
<script>
var myCounter;
var seconds = 0, minutes = 0, hours = 0, timer;
var toStop = false;
var h1 = document.getElementsByTagName('h1')[0];
function start() {
if (!toStop) {
seconds++;
if (seconds >= 60) {
seconds = 0;
minutes++;
if (minutes >= 60) {
minutes = 0;
hours++;
if (hours >= 12) {
hours = 0;
toStop = true;
stop();
}
}
}
var time = (hours ? (hours > 9 ? hours : "0" + hours) : "00") + ":" +
(minutes ? (minutes > 9 ? minutes : "0" + minutes) : "00") + ":" +
(seconds > 9 ? seconds : "0" + seconds);
document.getElementById("h").innerHTML = time;
// myTimer();
}
}
function stop() {
toStop = true;
clearInterval(myCounter);
}
function myTimer() {
if (!toStop) {
document.getElementById("h").innerHTML = "00:00:00";
seconds = 0; minutes = 0; hours = 0;
}
clearInterval(myCounter);
toStop = false;
myCounter = setInterval(start, 1000);
}
function clearTime() {
toStop = true;
seconds = 0; minutes = 0; hours = 0;
clearInterval(myCounter);
document.getElementById("h").innerHTML = "00:00:00";
}
</script>
<h1>
<time id="h">00:00:00</time>
</h1>
<button onclick="myTimer()">Start</button>
<button onclick="stop()">Stop</button>
<button onclick="clearTime()">Clear</button>
</body>
</html>
Don't use while or any loops they block io events, so there is no chance for the browser to update html.
If you like to use loops then you could try async/await:
async start() {
while (!stop) {
await sleep(1000)
// some code to get elapsedTime
render()
}
}
function sleep(ms) {
return new Promise(resolve => {
setTimeout(() => resolve(), ms)
})
}
But I like to avoid to use loops for this task.
I believe it could be less coding and cleaner.
const timer = {
start() {
this.time = new Date()
clearInterval(this.interval)
this.interval = setInterval(() => { this.tick() }, 1000)
},
stop() {
clearInterval(this.interval)
},
reset() {
this.time = new Date()
clearInterval(this.interval)
this.render(0, 0, 0)
},
tick() {
const now = new Date()
const elapsedTime = new Date(now - this.time)
const hours = elapsedTime.getUTCHours()
const minutes = elapsedTime.getUTCMinutes()
const seconds = elapsedTime.getUTCSeconds()
if (hours >= 12) this.stop()
this.render(hours, minutes, seconds)
},
render(hours, minutes, seconds) {
const time = [hours, minutes, seconds].map(v => v.toString().padStart(2, `0`))
const html = document.getElementById(`timer`)
html.textContent = time.join(`:`)
}
}
<h1>
<time id="timer">00:00:00</time>
</h1>
<button onclick="timer.start()">Start</button>
<button onclick="timer.stop()">Stop</button>
<button onclick="timer.reset()">Reset</button>
I'm working on a pomodoro clock. The application is almost done; however, when adding and subtracting numbers the number can go into negative. And that's not desire. The workTicker and breakTicker function are responsible for this. I implemented an if statement that check whether the number is > than 1. But when the number is = 1, it will no longer execute. How can I implement this? thanks codepen: https://codepen.io/zentech/pen/vJGdjN
javascript / jquery
$(document).ready(function() {
//variables
var session;
var seconds;
var minutes;
var clockDisplay = document.getElementById("display");
var counterId = 0;
var state = "work";
var start; //getting start time
//start / stop clock listener functionality
$("#start").click(function() {
var value = $(".button").text();
console.log(value);
if(value == "Start") {
session = Number($(".work").text() * 60);
start = new Date().getTime();
state = "work";
console.log("started!");
//starting counter
counterId = setInterval(countDown, 1000);
$("#session").text("Work");
$(".button").text("Stop");
} else {
console.log("stopped");
// | 0 same as Number()
session = (($(".work").text() * 60) | 0);
//clear counter
clearInterval(counterId);
clockDisplay.innerHTML = (session/60) +":00";
$("#session").text("Session");
$(".button").text("Start");
}
});
//add work time
$('.plusWork').click(function() {
var value = "plus";
console.log(value);
workTicker(value);
});
//substract work time
$('.minWork').click(function() {
var value = "minus";
workTicker(value);
});
//add break time
$('.plusBreak').click(function() {
var value = "plus";
breakTicker(value);
});
//substract break time
$('.minBreak').click(function() {
var value = "minus";
breakTicker(value);
});
//work countdown timer function
function countDown() {
//getting time now in ms
var now = new Date().getTime();
/*difference since clock started. now and start are in ms
we need to / by 1000 to bring to sec*/
var diff = Math.floor(session - ((now - start) / 1000));
console.log("diff: "+diff+" min: "+Math.floor(diff/60)+" sec: "+Math.floor(diff%60));
//getting minutes
minutes = Math.floor((diff / 60));
//getting seconds
seconds = Math.floor((diff % 60));
//dealing with minutes and sec under 10: 09, 07...
minutes = (minutes < 10) ? "0"+minutes : minutes;
seconds = (seconds < 10) ? "0"+seconds : seconds;
//update clock display
clockDisplay.innerHTML = minutes+":"+seconds;
//if difference reached < 0 stop counter;
if(diff == 0) {
restartSession(state);
}
}
//add substract work from timer/display
function workTicker(value) {
var min = Number($('.work').text());
//add substract while min > 0
if(min > 1) {
(value == "plus") ? min++ : min--;
clockDisplay.innerHTML = min+":00";
$(".work").text(min);
console.log(min);
}
}
//add substract break time
function breakTicker(value) {
var min = Number($(".break").text());
//add substract as long as min > 0
if(min > 1) {
(value == "plus") ? min++ : min--;
$(".break").text(min);
}
}
//restart countdown clock
function restartSession(state) {
//if state is work, change to break and visebersa
if(state == "work") {
alert("Stop working!");
$("#session").text("Break")
session = $(".break").text();
} else {
alert("Get to work!");
$("#session").text("Work");
session = $(".work").text();
}
clearInterval(counterId); //clear counter
console.log("session: "+session+" state: "+state);
start = new Date().getTime(); //setting start time
session = Number(session * 60); //converting min to sec
state = state == "work" ? "break" : "work";
counterId = setInterval(countDown, 1000); //starting counter
}
});
Try checking only if user is trying to subtract...
function breakTicker(value) {
var min = Number($(".break").text());
//add substract as long as min > 0
if(value == "plus") {
min++
} else {
if(min > 1){
min--;
}
}
$(".break").text(min);
}
Codepen: https://codepen.io/anon/pen/VzmLLd
The timer, start/pause button and reset button all work as expected.
The only bug it seems to have is, when I run the timer and reset it, it
won't start again. Only after I press the Start/Pause button 2 times it will run again.
Live demo: http://codepen.io/Michel85/full/pjjpYY/
Code:
var timerTime;
var time = 1500;
var currentTime;
var flag = 0;
var calculateTime
// Start your Timer
function startTimer(time) {
document.getElementById("btnUp").disabled = true;
document.getElementById("btnDwn").disabled = true;
timerTime = setInterval(function(){
showTimer();
return flag = 1;
}, 1000);
}
// Reset function
function resetTimer(){
clearInterval(timerTime);
document.getElementById('showTime').innerHTML=(calculateTime(1500));
document.getElementById("btnUp").disabled = false;
document.getElementById("btnDwn").disabled = false;
return time=1500;
}
// Pause function
function pauseTimer(){
clearInterval(timerTime);
currentTime = time;
document.getElementById('showTime').innerHTML=(calculateTime(time));
return flag = 0;
}
// Update field with timer information
function showTimer(){
document.getElementById("showTime").innerHTML=(calculateTime(time));
flag = 1;
if(time < 1){
resetTimer();
}
time--;
};
// Toggle function (Pause/Run)
function toggleTimmer(){
if(flag == 1){
pauseTimer();
} else {
startTimer();
}
}
/*
Round-time up or down
*/
// Set timer Up
function timeUp(){
time += 60;
document.getElementById("showTime").innerHTML=(calculateTime(time));
return time;
}
// Set timer Down
function timeDown(){
if(time > 60){
time-=60;
}
document.getElementById("showTime").innerHTML=(calculateTime(time));
return time;
}
/*
Break-time up down
*/
// Set timer Up
function breakUp(){
time += 60;
document.getElementById("showTime").innerHTML=(calculateTime(time));
return time;
}
// Set timer Down
function breakDown(){
if(time > 60){
time-=60;
}
document.getElementById("showTime").innerHTML=(calculateTime(time));
return time;
}
// Calculate the Days, Hours, Minutes, seconds and present them in a digital way.
function calculateTime(totalTime) {
// calculate days
var days = Math.floor(totalTime / 86400);
totalTime = totalTime % 86400
// calculate hours
var hours = Math.floor(totalTime / 3600);
totalTime = totalTime % 3600;
// calculate minutes
var minutes = Math.floor(totalTime / 60);
totalTime = totalTime % 60;
// calculate seconds
var seconds = Math.floor(totalTime);
function convertTime(t) {
return ( t < 10 ? "0" : "" ) + t;
}
// assign the variables
days = convertTime(days);
hours = convertTime(hours);
minutes = convertTime(minutes);
seconds = convertTime(seconds);
// Make sure the "00:" is present if empty.
if(days !== "00"){
var currentTimeString = days + ":" + hours + ":" + minutes + ":" + seconds;
return currentTimeString;
} else if (hours !== "00"){
var currentTimeString = hours + ":" + minutes + ":" + seconds;
return currentTimeString
} else if(minutes !== "0:00"){
var currentTimeString = minutes + ":" + seconds;
return currentTimeString
} else {
var currentTimeString = seconds;
return currentTimeString
}
}
Any help is welcome.
Thanks in advance.
Greets,
Michel
resetTimer needs to set flag to 0. If it leaves it set at 1, then toggleTimer will call pauseTimer rather than startTimer.
BTW, it's better style to use boolean values (true/false) for flags.
Just remove clearInterval(timerTime); in function resetTimer();
function resetTimer() {
//clearInterval(timerTime);
document.getElementById('showTime').innerHTML = (calculateTime(300));
document.getElementById("btnUp").disabled = false;
document.getElementById("btnDwn").disabled = false;
return time = 300;
}