0👍
✅
When you do calculate the current progress of your timer, you are not taking the pause time into consideration. Hence the jumps: This part of your code is only aware of the startTime and currentTime, it won’t be affected by the pauses.
To circumvent it, you can either accumulate all this pause times in the startTimer function
class Timer {
constructor() {
this.progress = 0;
this.totalPauseDuration = 0;
const d = this.timerFinishesAt = new Date(Date.now() + 10000);
this.timerStarted = new Date();
this.timerPausedAt = new Date();
}
timerStart() {
const pauseDuration = (Date.now() - this.timerPausedAt.getTime())
this.totalPauseDuration += pauseDuration;
// new future date = future date + elapsed time since pausing
this.timerFinishesAt = new Date(this.timerFinishesAt.getTime() + pauseDuration);
// set new timeout
this.timerId = window.setTimeout(this.toggleVisibility.bind(this), (this.timerFinishesAt.getTime() - Date.now()));
// animation start
this.progressId = requestAnimationFrame(this.progressBar.bind(this));
}
timerPause() {
// stop notification from closing
window.clearTimeout(this.timerId);
// set to null so animation won't stay in a loop
this.timerId = null;
// stop loader animation from progressing
cancelAnimationFrame(this.progressId);
this.progressId = null;
this.timerPausedAt = new Date();
}
progressBar() {
if (this.progress < 100) {
let elapsed = (Date.now() - this.timerStarted.getTime()) - this.totalPauseDuration;
let wholeTime = this.timerFinishesAt.getTime() - this.timerStarted.getTime();
this.progress = Math.ceil((elapsed / wholeTime) * 100);
log.textContent = this.progress;
if (this.timerId) {
this.progressId = requestAnimationFrame(this.progressBar.bind(this));
}
} else {
this.progressId = cancelAnimationFrame(this.progressId);
}
}
toggleVisibility() {
console.log("done");
}
};
const timer = new Timer();
btn.onclick = e => {
if (timer.timerId) timer.timerPause();
else timer.timerStart();
};
<pre id="log"></pre>
<button id="btn">toggle</button>
or update the startTime, which seems to be more reliable:
class Timer {
constructor() {
this.progress = 0;
const d = this.timerFinishesAt = new Date(Date.now() + 10000);
this.timerStarted = new Date();
this.timerPausedAt = new Date();
}
timerStart() {
const pauseDuration = (Date.now() - this.timerPausedAt.getTime())
// update timerStarted
this.timerStarted = new Date(this.timerStarted.getTime() + pauseDuration);
// new future date = future date + elapsed time since pausing
this.timerFinishesAt = new Date(this.timerFinishesAt.getTime() + pauseDuration);
// set new timeout
this.timerId = window.setTimeout(this.toggleVisibility.bind(this), (this.timerFinishesAt.getTime() - Date.now()));
// animation start
this.progressId = requestAnimationFrame(this.progressBar.bind(this));
}
timerPause() {
// stop notification from closing
window.clearTimeout(this.timerId);
// set to null so animation won't stay in a loop
this.timerId = null;
// stop loader animation from progressing
cancelAnimationFrame(this.progressId);
this.progressId = null;
this.timerPausedAt = new Date();
}
progressBar() {
if (this.progress < 100) {
let elapsed = Date.now() - this.timerStarted.getTime();
let wholeTime = this.timerFinishesAt.getTime() - this.timerStarted.getTime();
this.progress = Math.ceil((elapsed / wholeTime) * 100);
log.textContent = this.progress;
if (this.timerId) {
this.progressId = requestAnimationFrame(this.progressBar.bind(this));
}
} else {
this.progressId = cancelAnimationFrame(this.progressId);
}
}
toggleVisibility() {
console.log("done");
}
};
const timer = new Timer();
btn.onclick = e => {
if (timer.timerId) timer.timerPause();
else timer.timerStart();
};
<pre id="log"></pre>
<button id="btn">toggle</button>
As to the final gap, not seeing how this code is linked with your UI, it’s hard to tell what happens.
0👍
I think simply using SetInterval is enough :
const progressBar = {
MsgBox : document.querySelector('#Message'),
Info : document.querySelector('#Message h1'),
barr : document.querySelector('#Message progress'),
interV : 0,
DTime : 0,
D_Max : 0,
Init() {
this.MsgBox.onmouseover=_=> { // pause
clearInterval( this.interV )
}
this.MsgBox.onmouseout=_=>{ // restart
this._run()
}
},
Start(t,txt)
{
this.DTime = this.D_Max = t * 1000
this.barr.value = 0
this.barr.max = this.D_Max
this.Info.textContent = txt
this._run()
},
_run()
{
let D_End = new Date(Date.now() + this.DTime )
this.interV = setInterval(_=>{
this.DTime = D_End - (new Date(Date.now()))
if (this.DTime > 0) { this.barr.value = this.D_Max - this.DTime }
else { clearInterval( this.interV ); console.clear(); console.log( "finish" ) }
}, 100);
}
}
progressBar.Init()
progressBar.Start(10, 'Hello!') // 10 seconds
#Message {
box-sizing: border-box;
display: block;
float: right;
width: 200px;
height: 80px;
background-color: darkslategrey;
padding: 0 1em;
color:#e4a8b4;
cursor: pointer;
margin-right:1.5em;
}
#Message h1 { margin: .3em 0 0 0}
#Message progress { height: .1em; margin: 0; width:100%; background-color:black; }
#Message progress::-moz-progress-bar,
#Message progress::-webkit-progress-value { background-color:greenyellow; }
<div id="Message">
<progress value="50" max="100" ></progress>
<h1> </h1>
</div>
Source:stackexchange.com