i made this countdown timer (not really perfect), and i'm confused about something.
How can i get minInterval and secInterval datas on min and sec ?
In fact i'm trying to save seconds and minutes in sessionStorage to save datas. If user refresh the page, timer still continue.
I need to do this countdown in OOP.
var myTimer = {
minInterval: 19,
secInterval: 59,
min_: i want data of minInterval
sec_: i want data of secInterval
timerCountDownStart: function () {
if (myTimer.min_ <= -1) {
myTimer.min_ = myTimer.minInterval;
}
document.getElementById("count-timer").innerHTML = myTimer.min_ + " minute(s) et " + myTimer.sec_-- + " seconde(s) avant l\'expiration de votre réservation";
if (myTimer.sec_ <= -1) {
myTimer.min_--;
myTimer.sec_ = myTimer.secInterval;
myTimer.myStopFunction();
$('#title-reservation').text('Votre réservation a expirée');
$('#count-timer').fadeOut(1000);
sessionStorage.clear('nom_station');
}
},
myStopFunction: function () {
clearInterval();
sessionStorage.clear('nom_station');
$('#count-timer').fadeOut(1000)
}
};
Thanks :)
This simplified code shows you the basics of how to create a timer object that counts down in seconds and store the value in a sessionStorage.
It's not really OOP though! You can only have one myTimer and you shouldn't call myTimer.start() twice :)
var myTimer = {
time:10,
intervalID:0,
start: () => {
console.log("starting!!!");
// check if there is a starttime in sessionstorage
let storedTime = sessionStorage.getItem('time');
myTimer.time = (storedTime > 0) ? storedTime : 10;
// start countdown
myTimer.intervalID = setInterval(()=>myTimer.count(), 1000);
},
count: () => {
myTimer.time--;
console.log("time is " + myTimer.time);
// store count in session
sessionStorage.setItem('time', myTimer.time);
// check if below 0
if (myTimer.count < 0) {
myTimer.myStopFunction();
}
document.getElementById("count-timer").innerHTML = myTimer.time + " seconds left";
},
myStopFunction: () => {
clearInterval(myTimer.intervalID);
sessionStorage.clear();
}
};
myTimer.start();
Related
could you please help me how to fix this? I want to send just one command, but to be as accurate as possible (on milliseconds).
This is the part I need to fix:
document.getElementById("arrTime").onclick = function () {
clearInterval(attInterval);
let time = document.getElementsByClassName("relative_time")[0].textContent.slice(-8);
input = prompt("Set Arrival Time", time);
inputMs = parseInt(prompt("Set the milliseconds", "500"));
delay = parseInt(delayTime) + parseInt(inputMs);
let arrivalTime;
arrInterval = setInterval(function () {
arrivalTime = document.getElementsByClassName("relative_time")[0].textContent;
if (arrivalTime.slice(-8) >= input) {
setTimeout(function () { document.getElementById("troop_confirm_submit").click(); }, delay);
}
}, 5);
document.getElementById("showArrTime").innerHTML = input + ":" + inputMs.toString().padStart(3, "0");
document.getElementById("showSendTime").innerHTML = "";
};
Now, there is an "if statement" to perform action at arrivalTime.slice(-8) >= input (so for example 19:24:30), but it is sending requests every 5ms. So over that one second time, it sends 200 requests to the server.
I don´t want to change those 5ms, as I need to have it as accurate as possible, but I want to break the script, freeze it or sleep it for 1 second once the command is performed. So something like: setTimeout(function () { document.getElementById("troop_confirm_submit").click(); Sleep 1 second }, delay);
Anyone who can help, please?
I'd advise to break up the functions as to manage the interval a little easier
document.getElementById("arrTime").onclick = function() {
clearInterval(attInterval);
let time = document.getElementsByClassName("relative_time")[0].textContent.slice(-8);
input = prompt("Set Arrival Time", time);
inputMs = parseInt(prompt("Set the milliseconds", "500"));
delay = parseInt(delayTime) + parseInt(inputMs);
startInterval(input, delay)
document.getElementById("showArrTime").innerHTML = input + ":" + inputMs.toString().padStart(3, "0");
document.getElementById("showSendTime").innerHTML = "";
};
function startInterval(input, delay) {
arrInterval = setInterval(function() {
let arrivalTime = document.querySelector(".relative_time").innerText;
if (+arrivalTime.slice(-8) >= +input) {
clearInterval(arrInterval); // pause the interval
setTimeout(() => {
startInterval(input, delay)
}, 1000 * 60); // restart the interval in 1 minute
setTimeout(() => {
document.querySelector("#troop_confirm_submit").click();
}, delay);
}
}, 5);
}
So basically when I switch tabs, the countdown timer on a specific page just stops counting down and resumes when you return to the tab. Is there anyway to mitigate that so that it counts in the background or it accounts for the time you spend on another tab?
This is basically what I have for js:
document.getElementById('timer').innerHTML =
05 + ":" + 01;
startTimer();
function startTimer() {
var presentTime = document.getElementById('timer').innerHTML;
var timeArray = presentTime.split(/[:]+/);
var m = timeArray[0];
var s = checkSecond((timeArray[1] - 1));
if(s==59){m=m-1}
if(m<0){
return
} else if (m == 0 && s == 0) {
location.reload();
}
document.getElementById('timer').innerHTML =
m + ":" + s;
setTimeout(startTimer, 1000);
}
function checkSecond(sec) {
if (sec < 10 && sec >= 0) {sec = "0" + sec};
if (sec < 0) {sec = "59"};
return sec;
}
Any ideas whether the time could be done server side or something so that it can't be modified client side? If not, then whatever, but mainly just want to figure out how to make the countdown still work (or account for the time spent) when on another tab.
We can store the variable m and s values either globally or use the local storage to set the values after setting the inner HTML and get the stored values back whenever tabs were switched as:
Set values:
window.localStorage.setItem('minutes', m.toString()); //same for the seconds
Get values:
window.localStorage.getItem('minutes'); //same for the seconds
Hope this answers your questions.
Just a simple solution:
Add this piece of code.
<html>
<head>
<script>
(function() {
var $momentum;
function createWorker() {
var containerFunction = function() {
var idMap = {};
self.onmessage = function(e) {
if (e.data.type === 'setInterval') {
idMap[e.data.id] = setInterval(function() {
self.postMessage({
type: 'fire',
id: e.data.id
});
}, e.data.delay);
} else if (e.data.type === 'clearInterval') {
clearInterval(idMap[e.data.id]);
delete idMap[e.data.id];
} else if (e.data.type === 'setTimeout') {
idMap[e.data.id] = setTimeout(function() {
self.postMessage({
type: 'fire',
id: e.data.id
});
// remove reference to this timeout after is finished
delete idMap[e.data.id];
}, e.data.delay);
} else if (e.data.type === 'clearCallback') {
clearTimeout(idMap[e.data.id]);
delete idMap[e.data.id];
}
};
};
return new Worker(URL.createObjectURL(new Blob([
'(',
containerFunction.toString(),
')();'
], {
type: 'application/javascript'
})));
}
$momentum = {
worker: createWorker(),
idToCallback: {},
currentId: 0
};
function generateId() {
return $momentum.currentId++;
}
function patchedSetInterval(callback, delay) {
var intervalId = generateId();
$momentum.idToCallback[intervalId] = callback;
$momentum.worker.postMessage({
type: 'setInterval',
delay: delay,
id: intervalId
});
return intervalId;
}
function patchedClearInterval(intervalId) {
$momentum.worker.postMessage({
type: 'clearInterval',
id: intervalId
});
delete $momentum.idToCallback[intervalId];
}
function patchedSetTimeout(callback, delay) {
var intervalId = generateId();
$momentum.idToCallback[intervalId] = function() {
callback();
delete $momentum.idToCallback[intervalId];
};
$momentum.worker.postMessage({
type: 'setTimeout',
delay: delay,
id: intervalId
});
return intervalId;
}
function patchedClearTimeout(intervalId) {
$momentum.worker.postMessage({
type: 'clearInterval',
id: intervalId
});
delete $momentum.idToCallback[intervalId];
}
$momentum.worker.onmessage = function(e) {
if (e.data.type === 'fire') {
$momentum.idToCallback[e.data.id]();
}
};
window.$momentum = $momentum;
window.setInterval = patchedSetInterval;
window.clearInterval = patchedClearInterval;
window.setTimeout = patchedSetTimeout;
window.clearTimeout = patchedClearTimeout;
})();
</script>
</head>
</html>
I'm trying to write a 3 second countdown function in JavaScript. The start of the countdown is set by the server so I have setInterval function which calls an ajax function which runs a script on the server to see if it is ready to start the countdown. If the countdown is set, the data returned is that the countdown is ready and will start in a specified number of milliseconds.
I've got the following function which, if I step through I can see the screen updating step by step. However, when I simply run the script it updates everything in bulk. I do not understand why?
$.ajax({
url : "/check_countdown/", // the endpoint
type : "GET", // http method
data : { info : info }, // data sent with the post request
// handle a successful response
success : function(json) {
console.log(json);
if (json.ready == 'True') {
// if we have a start_time then we get ready for the count down
console.log("Countdown ready to start!"); // sanity check
// stop pinging the server
clearInterval(countdownInterval);
// clear screen
$('#holdingImage').hide();
// show countdown block
$('#countdownText').show();
startTime = new Date().getTime() + json.milliseconds;
nowTime = new Date().getTime();
console.log("Every ", nowTime, startTime);
while (nowTime < startTime) {
nowTime = new Date().getTime();
}
$('#countdownText').html("<h1>Three</h1>");
startTime = startTime + 1000;
console.log("Second ", nowTime, startTime);
while (nowTime < startTime) {
nowTime = new Date().getTime();
}
$('#countdownText').html("<h1>Two</h1>");
startTime = startTime + 1000;
console.log("Counts ", nowTime, startTime);
while (nowTime < startTime) {
nowTime = new Date().getTime();
}
$('#countdownText').html("<h1>One</h1>");
} else {
console.log("Countdown NOT ready to start!"); // another sanity check
}
},
// handle a non-successful response
error : function(xhr,errmsg,err) {
$('#results').html("<div class='alert-box alert radius' data-alert>Oops! We have encountered an error: "+errmsg+
" <a href='#' class='close'>×</a></div>"); // add the error to the dom
console.log(xhr.status + ": " + xhr.responseText); // provide a bit more info about the error to the console
}
});
I figure a second (1000 milliseconds) between updates should be enough?
$.ajax({
url : "/check_countdown/", // the endpoint
type : "GET", // http method
data : { info : info }, // data sent with the post request
async: false, //<---- Add this
....
only Add (async: false)
This is the solution that I came up with. I'm not convinced by its efficacy but ...
I changed the success function to:
success : function(json) {
console.log(json);
if (json.ready == 'True') {
// if we have a start_time then we get ready for the count down
console.log("Countdown ready to start!"); // sanity check
console.log(json);
// stop pinging the server
clearInterval(countdownInterval);
// clear screen
$('#holdingImage').hide();
// show countdown block
$('#countdownText').show();
startTime = new Date().getTime() + json.milliseconds;
nowTime = new Date().getTime();
while (nowTime < startTime) {
nowTime = new Date().getTime();
}
startCountdown();
}
I added a new function called startCountdown() which is:
function startCountdown () {
var display1 = document.querySelector('#countdownText'),
startTime = 5,
remainingTime = startTime,
timer = new CountDownTimer(startTime);
timer.onTick(format1).start();
function format1(minutes, seconds) {
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
display1.textContent = seconds;
remainingTime = parseInt(minutes) * 60 + parseInt(seconds);
if ((minutes=="00") && (seconds=="00")){
console.log("time expired!"); // sanity check
}
}
}
And then I used this timer.js script which I had from elsewhere (I do not know where I got it so cannot credit the author - sorry)
function CountDownTimer(duration, granularity) {
this.duration = duration;
this.granularity = granularity || 1000;
this.tickFtns = [];
this.running = false;
}
CountDownTimer.prototype.start = function() {
if (this.running) {
return;
}
this.running = true;
var start = Date.now(),
that = this,
diff, obj;
(function timer() {
diff = that.duration - (((Date.now() - start) / 1000) | 0);
if (diff > 0) {
setTimeout(timer, that.granularity);
} else {
diff = 0;
that.running = false;
}
obj = CountDownTimer.parse(diff);
that.tickFtns.forEach(function(ftn) {
ftn.call(this, obj.minutes, obj.seconds);
}, that);
}());
};
CountDownTimer.prototype.onTick = function(ftn) {
if (typeof ftn === 'function') {
this.tickFtns.push(ftn);
}
return this;
};
CountDownTimer.prototype.expired = function() {
return !this.running;
};
CountDownTimer.parse = function(seconds) {
return {
'minutes': (seconds / 60) | 0,
'seconds': (seconds % 60) | 0
};
};
CountDownTimer.prototype.stop = function() {
this.running = false;
};
All in, it gives me my desired result
When I initially call this function:
var session = function(){
console.error(service.get());
if(service.get().session === undefined){
$localStorage.user.session = {
timeLeft: 0, // Time left until a user session ends (in minutes).
start: function(timeLeft) {
$localStorage.user.session.timeLeft = timeLeft;
$localStorage.user.session.interval;
},
stop: function(){
$interval.cancel($localStorage.user.session.interval);
},
interval: $interval(function () {
$localStorage.user.session.timeLeft -= 1;
if($localStorage.user.session.timeLeft <= 0){
$state.go('signin');
}
}, 0.125 * 60000)
};
}
return $localStorage.user.session;
};
from
function sessionRestart(){
session();
};
sessionRestart();
It creates the session object with all its variables, but when I reload the page it doesn't populate the variables which are functions. How can I fix that?
EDIT
The application is AngularJS and I'm using ngStorage for the $localStorage, and the code is meant for a user session which can be found in a factory in my application.
MarcosPérezGude made me think of a solution to the problem. Which were to move the $interval outside of the $localStorage which fixed my problem. Not sure why it wouldn't work thou.
The code now looks like this:
var session,
startSession: function(timeLeft) {
if($localStorage.user.session === undefined){
if(timeLeft === undefined){
timeLeft = 0;
}
$localStorage.user.session = {
timeLeft: timeLeft
};
}
if (session === undefined) {
session = $interval(function () {
$localStorage.user.session.timeLeft -= 1;
if($localStorage.user.session.timeLeft === undefined){
service.stopSession();
}
if($localStorage.user.session.timeLeft <= 0){
$state.go('signin');
}
}, 1 * 60000); // Time in milliseconds. Minutes * milliseconds = total milliseconds before the interval repeats.
}
},
stopSession: function() {
$interval.cancel(session);
session = undefined;
};
I'm working on a little "web app" for a quiz.
Each slide has got a certain amount of time to be answered (or 0 to infinite time).
I find JS here to do the countdown:
function Countdown(options) {
var timer,
instance = this,
seconds = options.seconds || 10,
updateStatus = options.onUpdateStatus || function () {},
counterEnd = options.onCounterEnd || function () {};
function decrementCounter() {
updateStatus(seconds);
if (seconds === 0) {
counterEnd();
instance.stop();
}
seconds--;
}
this.start = function () {
clearInterval(timer);
timer = 0;
seconds = options.seconds;
timer = setInterval(decrementCounter, 1000);
};
this.stop = function () {
clearInterval(timer);
};
}
var myCounter = new Countdown({
seconds: timetogo, // number of seconds to count down
onUpdateStatus: function (sec) {
elapsed = timetogo - sec;
$('.progress-bar').width(((elapsed / timetogo) * 100) + "%");
}, // callback for each second
onCounterEnd: function () {
//alert('counter ended!');
} // final action
});
myCounter.start();
I made a jsfiddle here :
https://jsfiddle.net/mitchum/kz2400cc/2/
But i am having trouble when you go to the next slide, the progress bar "bump".
after looking into "live source panel from chrome" I saw it's like the first "counter" is not stopped and still runs.
Do you have any tips or hint to help me to solve my bug ?
Thanks
You must pay attention to the scope of the variables. I change the "var myCounter" under document ready in "var myCounterFirst". Check the updated JSFiddle.
var timetogoFirst = $('.current').attr("data-time");
var myCounterFirst = new Countdown({
seconds: timetogoFirst, // number of seconds to count down
onUpdateStatus: function (sec) {
elapsed = timetogoFirst - sec;
$('.progress-bar').width(((elapsed / timetogoFirst) * 100) + "%");
}, // callback for each second
onCounterEnd: function () {
alert('counter ended!');
} // final action
});
myCounterFirst.start();