How can I fix the stop-start process within this Javascript stopwatch-clock? - javascript

I have a JavaScript stopwatch here, I require the start-stop button to keep the same time when continuing.
Currently, if I stop and continue the clock diff is something ridiculous such as '-19330839:-3:-53'
Can anyone explain how this is fixed?
I have various method stopwatches made; however I would rather use real date time instead of a counter, this is because (I have tested after being made aware of this) that counters are very inaccurate over a period of time.
Any help is much appreciated.
html:
Please ignore the reset button for now. I will configure this later.
<input id="startstopbutton" class="buttonZ" style="width: 120px;" type="button" name="btn" value="Start" onclick="startstop();">
<input id="resetbutton" class="buttonZ" style="width: 120px;" type="button" name="btnRst1" id='btnRst1' value="Reset" onclick="resetclock();"/>
<div id="outputt" class="timerClock" value="00:00:00">00:00:00</div>
JS:
const outputElement = document.getElementById("outputt");
var startTime = 0;
var running = false;
var splitcounter = 0;
function startstop() {
if (running == false) {
running = true;
startTime = new Date(sessionStorage.getItem("time"))
if (isNaN(startTime)) startTime = Date.now();
startstopbutton.value = 'Stop';
document.getElementById("outputt").style.backgroundColor = "#2DB37B";
updateTimer();
} else {
running = false;
logTime();
startstopbutton.value = 'Start';
document.getElementById("outputt").style.backgroundColor = "#B3321B";
}
}
function updateTimer() {
if (running == true) {
let differenceInMillis = Date.now() - startTime;
sessionStorage.setItem("time", differenceInMillis)
let {
hours,
minutes,
seconds
} = calculateTime(differenceInMillis);
let timeStr = `${pad(hours)}:${pad(minutes)}:${pad(seconds)}`;
outputElement.innerText = timeStr;
requestAnimationFrame(updateTimer);
}
}
function calculateTime(milliS) {
const SECONDS = 1000; // should be 1000 - only 10 to speed up the timer
const MINUTES = 60;
const HOURS = 60;
const RESET = 60;
let hours = Math.floor(milliS / SECONDS / MINUTES / HOURS);
let minutes = Math.floor(milliS / SECONDS / MINUTES) % RESET;
let seconds = Math.floor(milliS / SECONDS) % RESET;
return {
hours,
minutes,
seconds
};
}
function pad(time) {
return time.toString().padStart(2, '0');
}
I just need the timer to continue on from where it was stopped at.

Issue with your code:
You start with initial value for sessionStorage as Date.now but then save difference on update.
You interact a lot with session storage. Any communication with external API is expensive. Instead use local variables and find an event to initialise values.
Time difference logic is a bit off.
Date.now - startTime does not considers the difference between stop action and start action.
You can use this logic: If startTime is defined, calculate difference and add it to start time. If not, initialise it to Date.now()
Suggestions:
Instead of adding styles, use classes. That will help you in reset functionality
Define small features and based on it, define small functions. That would make reusability easy
Try to make functions independent by passing arguments and only rely on them. That way you'll reduce side-effect
Note: as SO does not allow access to Session Storage, I have removed all the related code.
const outputElement = document.getElementById("outputt");
var running = false;
var splitcounter = 0;
var lastTime = 0;
var startTime = 0;
function logTime() {
console.log('Time: ', lastTime)
}
function resetclock() {
running = false;
startTime = 0;
printTime(Date.now())
applyStyles(true)
}
function applyStyles(isReset) {
startstopbutton.value = running ? 'Stop' : 'Start';
document.getElementById("outputt").classList.remove('red', 'green')
if (!isReset) {
document.getElementById("outputt").classList.add(running ? 'red' : 'green')
}
}
function startstop() {
running = !running;
applyStyles();
if (running) {
if (startTime) {
const diff = Date.now() - lastTime;
startTime = startTime + diff;
} else {
startTime = Date.now()
}
updateTimer(startTime);
} else {
lastTime = Date.now()
logTime();
}
}
function printTime(startTime) {
let differenceInMillis = Date.now() - startTime;
let {
hours,
minutes,
seconds
} = calculateTime(differenceInMillis);
let timeStr = `${pad(hours)}:${pad(minutes)}:${pad(seconds)}`;
outputElement.innerText = timeStr;
}
function updateTimer(startTime) {
if (running == true) {
printTime(startTime)
requestAnimationFrame(() => updateTimer(startTime));
}
}
function calculateTime(milliS) {
const SECONDS = 1000; // should be 1000 - only 10 to speed up the timer
const MINUTES = 60;
const HOURS = 60;
const RESET = 60;
let hours = Math.floor(milliS / SECONDS / MINUTES / HOURS);
let minutes = Math.floor(milliS / SECONDS / MINUTES) % RESET;
let seconds = Math.floor(milliS / SECONDS) % RESET;
return {
hours,
minutes,
seconds
};
}
function pad(time) {
return time.toString().padStart(2, '0');
}
.red {
background-color: #2DB37B
}
.green {
background-color: #B3321B
}
<input id="startstopbutton" class="buttonZ" style="width: 120px;" type="button" name="btn" value="Start" onclick="startstop();">
<input id="resetbutton" class="buttonZ" style="width: 120px;" type="button" name="btnRst1" id='btnRst1' value="Reset" onclick="resetclock();" />
<div id="outputt" class="timerClock" value="00:00:00">00:00:00</div>

simple stopwatch example
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<input class="startstop" style="width: 120px;" type="button" value="Start" onclick="startstop();">
<input class="reset" style="width: 120px;" type="button" value="Reset" onclick="reset();"/>
<div class="timerClock" value="00:00:00">00:00:00</div>
<script type="text/javascript">
var second = 0
var minute = 0
var hour = 0
var interval
var status = false
var element = document.querySelector('.startstop')
var clock = document.querySelector('.timerClock')
var string = ''
function startstop()
{
if(status == 'false')
{
element.value = 'Stop'
clock.style.backgroundColor = "#2DB37B";
status = true
interval = setInterval(function()
{
string = ''
second += 1
if(second >= 60)
{
minute += 1
second = 0
}
if(minute >= 60)
{
hour += 1
minute = 0
}
if(hour < 10)
string += `0${hour}:`
else
string += `${hour}:`
if(minute < 10)
string += `0${minute}:`
else
string += `${minute}:`
if(second < 10)
string += `0${second}`
else
string += `${second}`
clock.innerHTML = string
},1000)
}
else
{
clock.style.backgroundColor = "#B3321B";
element.value = 'Start'
status = false
clearInterval(interval)
}
}
function reset()
{
second = 0
minute = 0
hour = 0
status = false
element.value = 'Start'
clearInterval(interval)
clock.innerHTML = `00:00:00`
clock.style.backgroundColor = "transparent";
}
</script>
</body>
</html>

One thing to know about requestAnimationFrame is that it returns an integer that is a reference to the next animation. You can use this to cancel the next waiting animation with cancelAnimationFrame.
As mentioned by #Rajesh, you shouldn't store the time each update, as it will stop the current process for a (very) short while. Better in that case to fire an event, preferably each second, that will wait until it can run. I haven't updated the code to take that into account, I only commented it away for now.
It's also better to use classes than updating element styles. I wrote sloppy code that overwrites all classes on the #outputt element (it's spelled "output"). That's bad programming, because it makes it impossible to add other classes, but it serves the purpose for now. #Rajesh code is better written for this purpose.
I added two variables - diffTime and animationId. The first one corrects startTime if the user pauses. The second one keeps track if there is an ongoing timer animation.
I refactored your style updates into a method of its own. You should check it out, because it defines standard values and then changes them with an if statement. It's less code than having to type document.getElementById("outputt").style... on different rows.
I also added a resetclock method.
const outputElement = document.getElementById("outputt");
var startTime = 0;
var diffTime = 0;
var animationId = 0;
function startstop() {
const PAUSED = 0;
let paused = animationId == PAUSED;
//diffTime = new Date(sessionStorage.getItem("time")) || 0;
startTime = Date.now() - diffTime;
if (paused) {
updateTimer();
} else {
cancelAnimationFrame(animationId);
animationId = PAUSED;
}
updateTimerClass(paused);
}
function updateTimerClass(paused) {
var outputClass = 'red';
var buttonText = 'Start';
if (paused) {
outputClass = 'green';
buttonText = 'Stop';
}
startstopbutton.value = buttonText;
outputElement.classList = outputClass;
}
function updateTimer() {
let differenceInMillis = Date.now() - startTime;
//sessionStorage.setItem("time", differenceInMillis)
let {
hours,
minutes,
seconds
} = calculateTime(differenceInMillis);
let timeStr = `${pad(hours)}:${pad(minutes)}:${pad(seconds)}`;
outputElement.innerText = timeStr;
diffTime = differenceInMillis;
animationId = requestAnimationFrame(updateTimer);
}
function calculateTime(milliS) {
const SECONDS = 1000; // should be 1000 - only 10 to speed up the timer
const MINUTES = 60;
const HOURS = 60;
const RESET = 60;
let hours = Math.floor(milliS / SECONDS / MINUTES / HOURS);
let minutes = Math.floor(milliS / SECONDS / MINUTES) % RESET;
let seconds = Math.floor(milliS / SECONDS) % RESET;
return {
hours,
minutes,
seconds
};
}
function pad(time) {
return time.toString().padStart(2, '0');
}
function resetclock() {
let paused = animationId == 0;
startTime = Date.now();
diffTime = 0;
if (paused) {
const REMOVE_ALL_CLASSES = '';
outputElement.className = REMOVE_ALL_CLASSES;
outputElement.innerText = '00:00:00';
}
}
#outputt.green {
background-color: #2DB37B;
}
#outputt.red {
background-color: #B3321B;
}
<input id="startstopbutton" class="buttonZ" style="width: 120px;" type="button" name="btn" value="Start" onclick="startstop();">
<input id="resetbutton" class="buttonZ" style="width: 120px;" type="button" name="btnRst1" id='btnRst1' value="Reset" onclick="resetclock();"/>
<div id="outputt" class="timerClock" value="00:00:00">00:00:00</div>

class Stopwatch {
constructor(display, results) {
this.running = false;
this.display = display;
this.results = results;
this.laps = [];
this.reset();
this.print(this.times);
}
reset() {
this.times = [ 0, 0, 0 ];
}
click(){
var x=document.getElementById('ctrl');
if(x.value=="start"){
this.start();
x.value="stop";
document.getElementById("outputt").style.backgroundColor = "#2DB37B";
}
else{
x.value="start";
this.stop();
document.getElementById("outputt").style.backgroundColor = "#B3321B";
}
}
start() {
if (!this.time) this.time = performance.now();
if (!this.running) {
this.running = true;
requestAnimationFrame(this.step.bind(this));
}
}
stop() {
this.running = false;
this.time = null;
}
resets() {
document.getElementById("outputt").style.backgroundColor = "#2DB37B";
if (!this.time) this.time = performance.now();
if (!this.running) {
this.running = true;
requestAnimationFrame(this.step.bind(this));
}
this.reset();
}
step(timestamp) {
if (!this.running) return;
this.calculate(timestamp);
this.time = timestamp;
this.print();
requestAnimationFrame(this.step.bind(this));
}
calculate(timestamp) {
var diff = timestamp - this.time;
// Hundredths of a second are 100 ms
this.times[2] += diff / 1000;
// Seconds are 100 hundredths of a second
if (this.times[2] >= 100) {
this.times[1] += 1;
this.times[2] -= 100;
}
// Minutes are 60 seconds
if (this.times[1] >= 60) {
this.times[0] += 1;
this.times[1] -= 60;
}
}
print() {
this.display.innerText = this.format(this.times);
}
format(times) {
return `\
${pad0(times[0], 2)}:\
${pad0(times[1], 2)}:\
${pad0(Math.floor(times[2]), 2)}`;
}
}
function pad0(value, count) {
var result = value.toString();
for (; result.length < count; --count)
result = '0' + result;
return result;
}
function clearChildren(node) {
while (node.lastChild)
node.removeChild(node.lastChild);
}
let stopwatch = new Stopwatch(
document.querySelector('.stopwatch'),
document.querySelector('.results'));
<input type="button" id="ctrl" value="start" onClick="stopwatch.click();">
<input type="button" value="Reset" onClick="stopwatch.resets();">
<div id="outputt" class="stopwatch"></div>

Related

Pause/Continue in Pomodoro Timer project

I am building a pomodoro tracker in order to practice a little bit of JavaScript. It's been a while since I started this project. After this particulary problem which is implement a pause/continue functionality I abandoned the project. I really got stucked. I know programming is not easy and I will be facing many problems in the future but I really can't figure out how to solve this task. I am feeling stupid
Here is the JavaScript code:
// General Variables
let display = document.querySelector('.display');
// is the timer paused?
// let isPaused = true;
// let count = 0;
//const playPomodoro = document.querySelector('.play');
const pause = document.querySelector('.pause');
const resume = document.querySelector('.resume');
const stopPomodoro = document.querySelector('.stop');
const pomodoro = document.querySelector('#pomodoro');
const shortBreak = document.querySelector('#shortbreak');
const longBreak = document.querySelector('#longbreak')
const audioBeep = document.querySelector('#audioBeep');
const twentyFiveMinutes = 60 * 25;
const fiveMinutes = 60 * 5;
const thirtyMinutes = 60 * 30;
// Start Pomodoro timer 25 minutes
pomodoro.addEventListener('click', () => {
startTimer(twentyFiveMinutes, display);
stopClick(shortBreak, longBreak);
pause.style.display = 'block';
stopPomodoro.style.display = 'block';
});
// Start Pomodoro short break
shortBreak.addEventListener('click', () => {
startTimer(fiveMinutes, display);
stopClick(pomodoro, longBreak);
pause.style.display = 'block';
stopPomodoro.style.display = 'block';
});
// Start Pomodoro Long break
longBreak.addEventListener('click', () => {
startTimer(thirtyMinutes, display);
stopClick(pomodoro, shortBreak);
pause.style.display = 'block';
stopPomodoro.style.display = 'block';
});
// Stopping Clicks Events
function stopClick(btn1, btn2) {
btn1.classList.add('avoid-clicks');
btn2.classList.add('avoid-clicks');
}
// Remove .avoid-clicks class
function removeAvoidClick(btn1, btn2, btn3) {
btn1.classList.remove('avoid-clicks');
btn2.classList.remove('avoid-clicks');
btn3.classList.remove('avoid-clicks');
}
// main start timer function
function startTimer(duration, display) {
let timer = duration, min, sec;
let countingDown = setInterval(function() {
min = parseInt(timer / 60, 10);
sec = parseInt(timer % 60, 10);
min = min < 10 ? "0" + min : min;
sec = sec < 10 ? "0" + sec : sec;
display.innerHTML = min + ":" + sec;
if (--timer < 0) {
timer = duration;
}
// stops the counting variable when it hits zero
if (timer == 0) {
clearInterval(countingDown);
display.innerHTML = "00:00";
audioBeep.play();
removeAvoidClick(pomodoro,shortBreak,longBreak);
}
// Pause the clock
pause.addEventListener('click', () => {
});
// Stop the counter and set it to 00:00 when the user clicks the stop button
stopPomodoro.addEventListener('click', () => {
clearInterval(countingDown);
display.innerHTML = "00:00";
removeAvoidClick(pomodoro,shortBreak,longBreak);
});
}, 1000);
}
I will store the timer status in an object, then you activate a timer that decreses the current time left and call UI update.
let timer = {
timeLeft: 0,
running: 0,
};
function startTimer(duration) {
timer.timeLeft = duration;
if (!timer.run) {
timer.run = true;
run();
}
}
function run() {
if (timer.run) {
timer.timeLeft -= 1;
setTimeout(run, 1000)
}
}
function pauseTimer() {
timer.run = false;
}
function resumeTimer() {
if (!timer.run) {
timer.run = true;
run();
}
update();
}
function update() {
// everything you need to update in the UI from the timer object
}

How to make a countdown with input field with how many minutes the countdown must go?

I have made a countdown but now I want to make a input field with how many minutes the countdown should countdown from. What I have is a pretty basic countdown but what I don't have is that a user puts the amount of minutes into the input field, click the button, and it counts down the minutes. And I hope someone can help me with this.
This is what I got so far:
(()=> {
let countdownEnded = false;
start(3600); // seconds
})();
function start(inputTime){
let startTime = Date.now();
intervalSeconds = setInterval(() => {
let currentTime = Date.now() - startTime;
if(inputTime < 1) {
stop();
} else {
updateDisplay(inputTime, currentTime);
updateMillis();
}
}, 1000);
}
function stop(){
let countDivElement = document.getElementById("countdown"); /*** Updated***/
countDivElement.innerHTML = 'countdown done';
countdownEnded = true; /*** Updated***/
}
function updateDisplay(seconds, currentTime){
let timeIncrement = Math.floor(currentTime / 1000);
updateTime(seconds - timeIncrement);
}
/**
* #method - updatesecondsond
* #summary - This updates the timer every seconds
*/
function updateTime(seconds) {
let countDivElement = document.getElementById("timer");
let minutes = Math.floor(seconds / 60);
let remainingSeconds = seconds % 60;
if (remainingSeconds < 10) {
remainingSeconds = '0' + remainingSeconds;
}
if (minutes < 10) {
minutes = '0' + minutes;
}
if (seconds > 0) {
seconds = seconds - 1;
} else {
clearInterval(intervalSeconds);
countdownEnded = true;
countDivElement.innerHTML = 'countdown done';
return null;
}
countDivElement.innerHTML = minutes + ":" + remainingSeconds + ":" ;
};
function updateMillis() {
let countMillsElement = document.getElementById('millis');
let counterMillis = 99;
let millis;
let intervalMillis = setInterval(()=> {
if(counterMillis === 1) {
counterMillis = 99;
} else {
millis = counterMillis < 10 ? '0' + counterMillis : counterMillis;
};
countMillsElement.innerHTML = millis;
counterMillis --;
}, 10);
if(countdownEnded) {
stop(); /*** Updated***/
return clearInterval(intervalMillis);
}
};
<div class="clock" id="model3">
<div id="countdown"> <!-- Updated -->
<span id="timer"></span><span id="millis"></span>
</div>
</div>
<input id="minutes" placeholder="0:00"/>
I think this may help you.
Change the following
<input id="minutes" placeholder="00"/> <button onclick="startTimer()">Start</button>
And in javascript add a new function
function startTimer(){
var x=document.getElementById("minutes").value * 60; //To Change into Seconds
start(x);
}
And remove the start function
Just add a button with click event that takes input value and triggers your 'start' function with that value as parameter. Something like this:
document.getElementById("startBtn").addEventListener("click", startTimer);
function startTimer() {
var numberOfMinutes = Number(document.getElementById("minutes").value) * 60;
start(numberOfMinutes);
}
And remove 'start' function call from the window load to prevent the timer to start immidiately.
Result is something like this:
https://jsfiddle.net/scarabs/6patc9mo/1/

Enable button when counter reaches zero

I have a button its disabled and i want to put a counter inside it, what i want to do is when the counter reaches zero it get enabled, how can i do that? in the code below the counter doesn't appear inside the button and i don't want the reset button i just want the button to be enabled when it reaches zero, here is what i have tried so far:
function Countdown()
{
this.start_time = "00:30";
this.target_id = "#timer";
this.name = "timer";
this.reset_btn = "#reset";
}
Countdown.prototype.init = function()
{
this.reset();
setInterval(this.name + '.tick()',1000)
}
Countdown.prototype.reset = function()
{
$(this.reset_btn).hide();
time = this.start_time.split(":");
//this.minutes = parseInt(time[0]);
this.seconds = parseInt(time[1]);
this.update_target();
}
Countdown.prototype.tick = function()
{
if(this.seconds > 0) //|| this.minutes > 0)
{
if(this.seconds == 0)
{
// this.minutes = this.minutes - 1;
this.seconds = 59
} else {
this.seconds = this.seconds - 1;
}
}
this.update_target()
}
Countdown.prototype.update_target = function()
{
seconds = this.seconds;
if (seconds == 0) $(this.reset_btn).show();
else if(seconds < 10) seconds = "0" + seconds;
$(this.target_id).val(this.seconds)
}
timer = new Countdown();
timer.init();
$(document).ready(function(){
$("#reset").click(function(){
//timer = new Countdown();
timer.reset();
});
});
.hidden {
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button type="text" id="timer" disabled>Counter should be inside me, and enable me when it reaches 0</button>
<button id="reset">Reset</button>
This is much simpler than what you've got. Just use window.setTimeout().
Keep in mind that tracking time to a high precision is not super reliable in a browser. You may want to look at moment.js or use performance.now() for an easier API to handle that.
// Get refreence to span and button
var spn = document.getElementById("count");
var btn = document.getElementById("btnCounter");
var count = 5; // Set count
var timer = null; // For referencing the timer
(function countDown(){
// Display counter and start counting down
spn.textContent = count;
// Run the function again every second if the count is not zero
if(count !== 0){
timer = setTimeout(countDown, 1000);
count--; // decrease the timer
} else {
// Enable the button
btn.removeAttribute("disabled");
}
}());
<button id="btnCounter" disabled>Time left: <span id="count"></span></button>

Button onclick performing multiple actions

I have this code:
var hour = parseInt(js_arr[j].substring(0, 1));
var min = parseInt(js_arr[j].substring(3, 4));
var seconds = parseInt(js_arr[j].substring(6, 7));
var mil_sec = parseInt(js_arr[j].substring(9, 11));
var time = (hour * 3600000) + (min * 60000) + (seconds * 1000) + mil_sec;
function timeout() {
setTimeout(function () {
if (true) {
document.getElementById('subs').innerHTML = js_arr[i];
i = i + 4;
j = j + 4;
hour = parseInt(js_arr[j].substring(0, 1));
min = parseInt(js_arr[j].substring(3, 4));
seconds = parseInt(js_arr[j].substring(6, 7));
mil_sec = parseInt(js_arr[j].substring(9, 11));
time = (hour * 3600000) + (min * 60000) + (seconds * 1000) + mil_sec;
timeout();
} else {
timeout();
}
}, time);
}
Before javascript code I have an onclick="timeout(); button.
This button allows subtitles to play. What I would also like it to do is to stop these subtitles from playing by clicking on that same button. It would be great if someone could help!
Thanks a lot.
Add a variable that indicates whether the timeout is active. In the timeout()-function, this variable is checked and another loop is only initiated when it is true. To Start and Stop you simply set (and call timeout()) or reset the variable.
var hour = parseInt(js_arr[j].substring(0,1));
var min = parseInt(js_arr[j].substring(3,4));
var seconds = parseInt(js_arr[j].substring(6,7));
var mil_sec = parseInt(js_arr[j].substring(9,11));
var time = (hour*3600000)+(min*60000)+(seconds*1000)+mil_sec;
var timeOutRunning = false;
function startTimeOut() {
timeOutRunning = true;
timeout();
}
function stopTimeOut() {
timeOutRunning = false;
}
function timeout() {
if(timeOutRunning) {
setTimeout(function() {
document.getElementById('subs').innerHTML = js_arr[i];
i=i+4;
j=j+4;
hour = parseInt(js_arr[j].substring(0,1));
min = parseInt(js_arr[j].substring(3,4));
seconds = parseInt(js_arr[j].substring(6,7));
mil_sec = parseInt(js_arr[j].substring(9,11));
time = (hour*3600000)+(min*60000)+(seconds*1000)+mil_sec;
timeout();
}, time);
}
}
And then the onclick-function:
onclick="if(timeOutRunning) { stopTimeOut(); } else { startTimeOut(); }"

How to create a stopwatch using JavaScript?

if(stopwatch >= track[song].duration)
track[song].duration finds the duration of a soundcloud track.
I am looking to create a stopwatch function that starts counting milliseconds when you click on the swap ID stopwatch so that when the function has been "clicked" for a certain amount of time the if function will do something. In my case replace an image. And also that the function will reset it itself when clicked again.
so like stopwatch = current time - clicked time How can I set up the clicked time
current time = new Date().getTime(); ? And is this in milliseconds?
$('#swap').click(function()...
You'll see the demo code is just a start/stop/reset millisecond counter. If you want to do fanciful formatting on the time, that's completely up to you. This should be more than enough to get you started.
This was a fun little project to work on. Here's how I'd approach it
var Stopwatch = function(elem, options) {
var timer = createTimer(),
startButton = createButton("start", start),
stopButton = createButton("stop", stop),
resetButton = createButton("reset", reset),
offset,
clock,
interval;
// default options
options = options || {};
options.delay = options.delay || 1;
// append elements
elem.appendChild(timer);
elem.appendChild(startButton);
elem.appendChild(stopButton);
elem.appendChild(resetButton);
// initialize
reset();
// private functions
function createTimer() {
return document.createElement("span");
}
function createButton(action, handler) {
var a = document.createElement("a");
a.href = "#" + action;
a.innerHTML = action;
a.addEventListener("click", function(event) {
handler();
event.preventDefault();
});
return a;
}
function start() {
if (!interval) {
offset = Date.now();
interval = setInterval(update, options.delay);
}
}
function stop() {
if (interval) {
clearInterval(interval);
interval = null;
}
}
function reset() {
clock = 0;
render(0);
}
function update() {
clock += delta();
render();
}
function render() {
timer.innerHTML = clock / 1000;
}
function delta() {
var now = Date.now(),
d = now - offset;
offset = now;
return d;
}
// public API
this.start = start;
this.stop = stop;
this.reset = reset;
};
// basic examples
var elems = document.getElementsByClassName("basic");
for (var i = 0, len = elems.length; i < len; i++) {
new Stopwatch(elems[i]);
}
// programmatic examples
var a = document.getElementById("a-timer");
aTimer = new Stopwatch(a);
aTimer.start();
var b = document.getElementById("b-timer");
bTimer = new Stopwatch(b, {
delay: 100
});
bTimer.start();
var c = document.getElementById("c-timer");
cTimer = new Stopwatch(c, {
delay: 456
});
cTimer.start();
var d = document.getElementById("d-timer");
dTimer = new Stopwatch(d, {
delay: 1000
});
dTimer.start();
.stopwatch {
display: inline-block;
background-color: white;
border: 1px solid #eee;
padding: 5px;
margin: 5px;
}
.stopwatch span {
font-weight: bold;
display: block;
}
.stopwatch a {
padding-right: 5px;
text-decoration: none;
}
<h2>Basic example; update every 1 ms</h2>
<p>click <code>start</code> to start a stopwatch</p>
<pre>
var elems = document.getElementsByClassName("basic");
for (var i=0, len=elems.length; i<len; i++) {
new Stopwatch(elems[i]);
}
</pre>
<div class="basic stopwatch"></div>
<div class="basic stopwatch"></div>
<hr>
<h2>Programmatic example</h2>
<p><strong>Note:</strong> despite the varying <code>delay</code> settings, each stopwatch displays the correct time (in seconds)</p>
<pre>
var a = document.getElementById("a-timer");
aTimer = new Stopwatch(a);
aTimer.start();
</pre>
<div class="stopwatch" id="a-timer"></div>1 ms<br>
<pre>
var b = document.getElementById("b-timer");
bTimer = new Stopwatch(b, {delay: 100});
bTimer.start();
</pre>
<div class="stopwatch" id="b-timer"></div>100 ms<br>
<pre>
var c = document.getElementById("c-timer");
cTimer = new Stopwatch(c, {delay: 456});
cTimer.start();
</pre>
<div class="stopwatch" id="c-timer"></div>456 ms<br>
<pre>
var d = document.getElementById("d-timer");
dTimer = new Stopwatch(d, {delay: 1000});
dTimer.start();
</pre>
<div class="stopwatch" id="d-timer"></div>1000 ms<br>
Get some basic HTML wrappers for it
<!-- create 3 stopwatches -->
<div class="stopwatch"></div>
<div class="stopwatch"></div>
<div class="stopwatch"></div>
Usage is dead simple from there
var elems = document.getElementsByClassName("stopwatch");
for (var i=0, len=elems.length; i<len; i++) {
new Stopwatch(elems[i]);
}
As a bonus, you get a programmable API for the timers as well. Here's a usage example
var elem = document.getElementById("my-stopwatch");
var timer = new Stopwatch(elem, {delay: 10});
// start the timer
timer.start();
// stop the timer
timer.stop();
// reset the timer
timer.reset();
jQuery plugin
As for the jQuery portion, once you have nice code composition as above, writing a jQuery plugin is easy mode
(function($) {
var Stopwatch = function(elem, options) {
// code from above...
};
$.fn.stopwatch = function(options) {
return this.each(function(idx, elem) {
new Stopwatch(elem, options);
});
};
})(jQuery);
jQuery plugin usage:
// all elements with class .stopwatch; default delay (1 ms)
$(".stopwatch").stopwatch();
// a specific element with id #my-stopwatch; custom delay (10 ms)
$("#my-stopwatch").stopwatch({delay: 10});
jsbin.com demo
Two native solutions
performance.now --> Call to ... took 6.414999981643632 milliseconds.
console.time --> Call to ... took 5.815 milliseconds
The difference between both is precision.
For usage and explanation read on.
Performance.now (For microsecond precision use)
var t0 = performance.now();
doSomething();
var t1 = performance.now();
console.log("Call to doSomething took " + (t1 - t0) + " milliseconds.");
function doSomething(){
for(i=0;i<1000000;i++){var x = i*i;}
}
performance.now
Unlike other timing data available to JavaScript (for example
Date.now), the timestamps returned by Performance.now() are not
limited to one-millisecond resolution. Instead, they represent times
as floating-point numbers with up to microsecond precision.
Also unlike Date.now(), the values returned by Performance.now()
always increase at a constant rate, independent of the system clock
(which might be adjusted manually or skewed by software like NTP).
Otherwise, performance.timing.navigationStart + performance.now() will
be approximately equal to Date.now().
console.time
Example: (timeEnd wrapped in setTimeout for simulation)
console.time('Search page');
doSomething();
console.timeEnd('Search page');
function doSomething(){
for(i=0;i<1000000;i++){var x = i*i;}
}
You can change the Timer-Name for different operations.
A simple and easy clock for you and don't forget me ;)
var x;
var startstop = 0;
function startStop() { /* Toggle StartStop */
startstop = startstop + 1;
if (startstop === 1) {
start();
document.getElementById("start").innerHTML = "Stop";
} else if (startstop === 2) {
document.getElementById("start").innerHTML = "Start";
startstop = 0;
stop();
}
}
function start() {
x = setInterval(timer, 10);
} /* Start */
function stop() {
clearInterval(x);
} /* Stop */
var milisec = 0;
var sec = 0; /* holds incrementing value */
var min = 0;
var hour = 0;
/* Contains and outputs returned value of function checkTime */
var miliSecOut = 0;
var secOut = 0;
var minOut = 0;
var hourOut = 0;
/* Output variable End */
function timer() {
/* Main Timer */
miliSecOut = checkTime(milisec);
secOut = checkTime(sec);
minOut = checkTime(min);
hourOut = checkTime(hour);
milisec = ++milisec;
if (milisec === 100) {
milisec = 0;
sec = ++sec;
}
if (sec == 60) {
min = ++min;
sec = 0;
}
if (min == 60) {
min = 0;
hour = ++hour;
}
document.getElementById("milisec").innerHTML = miliSecOut;
document.getElementById("sec").innerHTML = secOut;
document.getElementById("min").innerHTML = minOut;
document.getElementById("hour").innerHTML = hourOut;
}
/* Adds 0 when value is <10 */
function checkTime(i) {
if (i < 10) {
i = "0" + i;
}
return i;
}
function reset() {
/*Reset*/
milisec = 0;
sec = 0;
min = 0
hour = 0;
document.getElementById("milisec").innerHTML = "00";
document.getElementById("sec").innerHTML = "00";
document.getElementById("min").innerHTML = "00";
document.getElementById("hour").innerHTML = "00";
}
<h1>
<span id="hour">00</span> :
<span id="min">00</span> :
<span id="sec">00</span> :
<span id="milisec">00</span>
</h1>
<button onclick="startStop()" id="start">Start</button>
<button onclick="reset()">Reset</button>
This is my simple take on this question, I hope it helps someone out oneday, somewhere...
let output = document.getElementById('stopwatch');
let ms = 0;
let sec = 0;
let min = 0;
function timer() {
ms++;
if(ms >= 100){
sec++
ms = 0
}
if(sec === 60){
min++
sec = 0
}
if(min === 60){
ms, sec, min = 0;
}
//Doing some string interpolation
let milli = ms < 10 ? `0`+ ms : ms;
let seconds = sec < 10 ? `0`+ sec : sec;
let minute = min < 10 ? `0` + min : min;
let timer= `${minute}:${seconds}:${milli}`;
output.innerHTML =timer;
};
//Start timer
function start(){
time = setInterval(timer,10);
}
//stop timer
function stop(){
clearInterval(time)
}
//reset timer
function reset(){
ms = 0;
sec = 0;
min = 0;
output.innerHTML = `00:00:00`
}
const startBtn = document.getElementById('startBtn');
const stopBtn = document.getElementById('stopBtn');
const resetBtn = document.getElementById('resetBtn');
startBtn.addEventListener('click',start,false);
stopBtn.addEventListener('click',stop,false);
resetBtn.addEventListener('click',reset,false);
<p class="stopwatch" id="stopwatch">
<!-- stopwatch goes here -->
</p>
<button class="btn-start" id="startBtn">Start</button>
<button class="btn-stop" id="stopBtn">Stop</button>
<button class="btn-reset" id="resetBtn">Reset</button>
Solution by Mosh Hamedani
Creating a StopWatch function constructor.
Define 4 local variables
startTime
endTime
isRunning
duration set to 0
Next create 3 methods
start
stop
reset
start method
check if isRunning is true if so throw an error that start cannot be called twice.
set isRunning to true
assign the current Date object to startTime.
stop method
check if isRunning is false if so throw an error that stop cannot be called twice.
set isRunning to false
assign the current Date object to endTime.
calculate the seconds by endTime and startTime Date object
increment duration with seconds
reset method:
reset all the local variables.
Read-only property
if you want to access the duration local variable you need to define a property using Object.defineProperty.
It's useful when you want to create a read-only property.
Object.defineProperty takes 3 parameters
the object which to define a property (in this case the current object (this))
the name of the property
the value of the key property.
We want to create a Read-only property so we pass an object as a value.
The object contain a get method that return the duration local variable.
in this way we cannot change the property only get it.
The trick is to use Date() object to calculate the time.
Reference the code below
function StopWatch() {
let startTime,
endTime,
isRunning,
duration = 0;
this.start = function () {
if (isRunning) throw new Error("StopWatch has already been started.");
isRunning = true;
startTime = new Date();
};
this.stop = function () {
if (!isRunning) throw new Error("StopWatch has already been stop.");
isRunning = false;
endTime = new Date();
const seconds = (endTime.getTime() - startTime.getTime()) / 1000;
duration += seconds;
};
this.reset = function () {
duration = 0;
startTime = null;
endTime = null;
isRunning = false;
};
Object.defineProperty(this, "duration", {
get: function () {
return duration;
},
});
}
const sw = new StopWatch();
function StopWatch() {
let startTime, endTime, running, duration = 0
this.start = () => {
if (running) console.log('its already running')
else {
running = true
startTime = Date.now()
}
}
this.stop = () => {
if (!running) console.log('its not running!')
else {
running = false
endTime = Date.now()
const seconds = (endTime - startTime) / 1000
duration += seconds
}
}
this.restart = () => {
startTime = endTime = null
running = false
duration = 0
}
Object.defineProperty(this, 'duration', {
get: () => duration.toFixed(2)
})
}
const sw = new StopWatch()
sw.start()
sw.stop()
sw.duration
well after a few modification of the code provided by mace,i ended up building a stopwatch.
https://codepen.io/truestbyheart/pen/EGELmv
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Stopwatch</title>
<style>
#center {
margin: 30% 30%;
font-family: tahoma;
}
.stopwatch {
border:1px solid #000;
background-color: #eee;
text-align: center;
width:656px;
height: 230px;
overflow: hidden;
}
.stopwatch span{
display: block;
font-size: 100px;
}
.stopwatch p{
display: inline-block;
font-size: 40px;
}
.stopwatch a{
font-size:45px;
}
a:link,
a:visited{
color :#000;
text-decoration: none;
padding: 12px 14px;
border: 1px solid #000;
}
</style>
</head>
<body>
<div id="center">
<div class="timer stopwatch"></div>
</div>
<script>
const Stopwatch = function(elem, options) {
let timer = createTimer(),
startButton = createButton("start", start),
stopButton = createButton("stop", stop),
resetButton = createButton("reset", reset),
offset,
clock,
interval,
hrs = 0,
min = 0;
// default options
options = options || {};
options.delay = options.delay || 1;
// append elements
elem.appendChild(timer);
elem.appendChild(startButton);
elem.appendChild(stopButton);
elem.appendChild(resetButton);
// initialize
reset();
// private functions
function createTimer() {
return document.createElement("span");
}
function createButton(action, handler) {
if (action !== "reset") {
let a = document.createElement("a");
a.href = "#" + action;
a.innerHTML = action;
a.addEventListener("click", function(event) {
handler();
event.preventDefault();
});
return a;
} else if (action === "reset") {
let a = document.createElement("a");
a.href = "#" + action;
a.innerHTML = action;
a.addEventListener("click", function(event) {
clean();
event.preventDefault();
});
return a;
}
}
function start() {
if (!interval) {
offset = Date.now();
interval = setInterval(update, options.delay);
}
}
function stop() {
if (interval) {
clearInterval(interval);
interval = null;
}
}
function reset() {
clock = 0;
render(0);
}
function clean() {
min = 0;
hrs = 0;
clock = 0;
render(0);
}
function update() {
clock += delta();
render();
}
function render() {
if (Math.floor(clock / 1000) === 60) {
min++;
reset();
if (min === 60) {
min = 0;
hrs++;
}
}
timer.innerHTML =
hrs + "<p>hrs</p>" + min + "<p>min</p>" + Math.floor(clock / 1000)+ "<p>sec</p>";
}
function delta() {
var now = Date.now(),
d = now - offset;
offset = now;
return d;
}
};
// Initiating the Stopwatch
var elems = document.getElementsByClassName("timer");
for (var i = 0, len = elems.length; i < len; i++) {
new Stopwatch(elems[i]);
}
</script>
</body>
</html>

Categories