I have a JavaScript stopwatch on my website that my authors have to use it when they are doing some actions. This actions are depend on using another pages/tabs on my website but currently when my authors going to another tab, the stopwatch will pause and when they return to the page, stopwatch will continue. It is supposed to continue even if they change tabs.
Here is my code:
let startBtn = document.getElementById('start');
let stopBtn = document.getElementById('stop');
let resetBtn = document.getElementById('reset');
let timeY = document.getElementById('timey');
let minute = 00;
let second = 00;
let count = 00;
window.onload = function() {
document.getElementById('stop').style.display = 'none';
};
startBtn.addEventListener('click', function () {
timer = true;
stopWatch();
document.getElementById('stop').style.display = 'inline';
document.getElementById('start').style.display = 'none';
});
stopBtn.addEventListener('click', function () {
timer = false;
document.getElementById('start').innerHTML = "Continue";
document.getElementById('stop').style.display = 'none';
document.getElementById('start').style.display = 'inline';
});
resetBtn.addEventListener('click', function () {
timer = false;
minute = 0;
second = 0;
count = 0;
document.getElementById('min').innerHTML = "00";
document.getElementById('sec').innerHTML = "00";
document.getElementById('count').innerHTML = "00";
document.getElementById('acf-field_651d01208c082').value = "00:00:00";
});
function stopWatch() {
if (timer) {
count++;
if (count == 100) {
second++;
count = 0;
}
if (second == 60) {
minute++;
second = 0;
}
let minString = minute;
let secString = second;
let countString = count;
if (minute < 10) {
minString = "0" + minString;
}
if (second < 10) {
secString = "0" + secString;
}
if (count < 10) {
countString = "0" + countString;
}
document.getElementById('min').innerHTML = minString;
document.getElementById('sec').innerHTML = secString;
document.getElementById('count').innerHTML = countString;
document.getElementById('acf-field_651d01208c082').value = minString+":"+secString+":"+countString;
setTimeout(stopWatch, 10);
}
}
jQuery('#acf-group_651d0120348fc').insertAfter('#submitdiv');
#acf-field_651d01208c082 {cursor: help;text-align: center;font-family: Vazirmatn UI, sans-serif !important;border: 0px;font-size: 19px;letter-spacing: 4px;background: transparent !important;background: #fff0 !important;}
#buttons #start {background: #4CAF50;color: #FFF;border: 1px solid #4CAF50;}
#buttons #start:hover {background: #409743;color: #FFF;border: 1px solid #4CAF50;}
#buttons #stop {display:none;background: #e73e77;color: #FFF;border: 1px solid #e73e77;}
#buttons #stop:hover {background: #c13b68;color: #FFF;border: 1px solid #e73e77;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="timey" style="text-align: center;direction: ltr !important;font-size: 0px !important;font-size: 0.01px !important;visibility: hidden;">
<span class="digit" id="min">
00</span>
<span class="txt">:</span>
<span class="digit" id="sec">
00</span>
<span class="txt">:</span>
<span class="digit" id="count">
00</span>
</div>
<div id="buttons" style="text-align: center;">
<button type="button" class="button" id="start">start</button>
<button type="button" class="button" id="stop" style="display: none;">stop</button>
<button type="button" class="button" id="reset">reset</button>
</div>
<input type="text" id="acf-field_651d01208c082" name="acf[field_651d01208c082]" placeholder="00:00:00" readonly="">
2
Answers
To add the ability to make the stopwatch appear to continue progressing rather than pausing even if the user moves to a different tab, you can leverage the web browser’s visibilitychange event.
This is the code adding the visibilitychange event to the code:
Here is a rudimentary example.
past
accumulate all the past measured interval (the one for which we have, in the past, since last reset, started and then stopped the watch).startTime
is the starting time of the current measurement (the date at which we hit ‘start’ button the last timeSo start button just keeps the value of startTime.
And stop button (same, when running) add
now-startTime
to thepast
accumulator.That’s all that is actively done to measure time. Rest (the set interval) is unnecessary and just for rendering (time is measured whether we show it or not).
So, what that
setIterval
function does is just display thepast
accumulator, plus, if needed, the current interval as it would be if we were hitting stop now.As for "why 70" for the interval… Well, I could have used 10. But, I want to illustrate that this is just rendering. And you don’t really need a 100 fps rendering for a stop watch. You eyes are not that accurate. 100 ms, that is 10 fps would be enough. But since we show 2 decimal places, that would lead, to the decimal place to be almost constant (almost, because setInterval is not exactly accurate).
We don’t really want that last decimal place to increase every 1/100th of second. We just want it to keep moving really fast, so our eye just see it moving. But we don’t want it to appear fixed neither. So not a factor of 100ms. Hence any interval small enough to create running feeling (70 is almost 15 fps) and that does not end by 00 (7 is prime. So last decimal place will show all digits). Well that are some overthinking probably. But my point is: this is only about rendering the time. Whatever interval you choose will not impact how time is measured. If you put ‘86400000’ in there, well, time is still measured as accurately, even if the display is updated only once a day. If you put ’10’, you are probably spending too much of your cpu time (or rather, your users cpu time) in rendering digits that nobody can possibly read that fast, but still, it doesn’t impact how time is measured.