Displaying one JS countdown after another - javascript

I'm trying to display a second countdown after the first one finishes. I'm using meteor. This is the timer:
sec = 5
#timer = setInterval((->
$('#timer').text sec--
if sec == -1
$('#timer').fadeOut 'fast'
sec=
timer
return
), 1000)
This is how I call it
When the template is rendered I call a setTimeout and a countdown displays
Template.selector.rendered = ->
window.setTimeout(startGame, 5000)
timer
When game starts I need a second countdown. I managed it like this:
sec = 5
sw = 0
#timer = setInterval((->
$('#timer').text sec--
if sec == -1
if sw == 0
sw = 1
sec = 20
else if sw == 1
clearInterval timer
return
), 1000)
But there has to be a better way.

If you plan to use many timers, you could make an object to achieve that. Here is an example taken from here You could adapt it to your case using custom events:
ReactiveTimer = (function () {
// Constructor
function ReactiveTimer(interval) {
this._dependency = new Tracker.Dependency;
this._intervalId = null;
if(_.isFinite(interval))
this.start(interval);
};
ReactiveTimer.prototype.start = function(interval){
var _this = this;
this._intervalId = Meteor.setInterval(function(){
// rerun every "interval"
_this._dependency.changed();
}, 1000 * interval);
};
ReactiveTimer.prototype.stop = function(){
Meteor.clearInterval(this._intervalId);
this._intervalId = null;
};
ReactiveTimer.prototype.tick = function(){
this._dependency.depend();
};
return ReactiveTimer;
})();

Related

How do I setup a "rolling window"?

I'm trying to figure out the way I can set up a rolling window for a variable.
The variable will record a number increasing # amount of times from the minute before.
My basic interval timer
var kp123 = Number('1');
var myInt = setInterval(function () {
kp123 = 1;
}, 60000);
Whenever a specific command is sent, kp123 gets increased by 1:
kp123++;
This variable may increase 20 times every second, or only 2-3 times every second.
Right now how the system is set up, it records the variable # every minute, however, the data gets reset when the interval timer reaches one minute.
var kp123 = Number('1');
var kp123History = []; // The history of kp123 is stored in this variable each minute
var myInt = setInterval(function () {
kp123History.push(kp123);
kp123 = 1;
console.log(kp123History); // You can see the results in the console each minute like this
}, 60000);
or if you only want the previous value, and not the full history, try this
var kp123 = Number('1');
var prevKp123 = null; // The previous value of kp123 is stored in this variable each minute
var myInt = setInterval(function () {
prevKp123 = kp123;
kp123 = 1;
}, 60000);
It sounds like (per the comments) you want a rolling average (wiki). You don't really show enough of your code for me to give a specific answer to you, but in general, you can't deduce a rolling average from just averages, you'll need to know actual values and their timestamps. I.e. you can't summarize your data and throw away the timestmaps.
class RollingAverage {
constructor(windowMs = 1000) {
this.windowMs_ = windowMs;
this.values_ = [];
}
addValue(value = 1) {
let time = Date.now();
this.values_.push({value, time});
}
get average() {
let now = Date.now();
this.values_ = this.values_.filter(({time}) => now - time <= this.windowMs_ * 1000);
return this.values_
.map(({value}) => value)
.reduce((a, b) => a + b)
/ this.values_.length;
}
}
let test = async () => {
let sleep = ms => new Promise(r => setTimeout(r, ms));
let avg = new RollingAverage();
avg.addValue(1);
console.log(avg.average); // 1
await sleep(600);
console.log(avg.average); // 1
avg.addValue(3);
console.log(avg.average); // 2
await sleep(600);
console.log(avg.average); // 3
avg.addValue(5);
console.log(avg.average); // 4
}
test();

setInterval for stopwatch

I'm trying to make a stopwatch. Here's the code:
var min = 0, sec = 0, censec = 0
$("#startBtn").on("click", function() { // when start button is clicked
$(this).hide(); // start is hidden
$("#stopBtn").show(); // stop is shown
setInterval(add, 10); // the censec will be increased every 10 millisecond.
$("#censec").text(censec);
})
function add() {
censec++;
if (censec == 100) {
censec = 0;
sec++;
if (sec == 60) {
sec = 0;
min++;
}
}
}
The problem is that setInterval() happens only at once. The censec only changes from 00 to 1. That's it.
P.S. I'm new to coding, so if there are other mistakes, please don't hesitate to tell me.
The setInterval calls to add will definitely repeat. But your code is only ever showing the value of censec once, when you start the timer.
If you want to update the display every hundredth of a second, put the code showing the value in add.
Separately, the code as it is in the question won't run at all, because it has a ReferenceError on the first line. Those ; should be ,.
Example (this also stores the timer's handle and clears the timer when you click the stop button):
var min = 0, sec = 0, censec = 0;
// Note ---^--------^
function add() {
censec++;
if (censec == 100) {
censec = 0;
sec++;
if (sec == 60) {
sec = 0;
min++;
}
}
$("#censec").text(censec);
}
var timer = 0;
$("#startBtn").on("click", function() { //when start button is clicked
$(this).hide(); //start is hidden
$("#stopBtn").show(); //stop is shown
timer = setInterval(add,10); //the censec will be increased every 10 millisecond.
});
$("#stopBtn").on("click", function() {
clearInterval(timer);
timer = 0;
$(this).hide();
$("#startBtn").show();
});
<input type="button" id="startBtn" value="Start">
<input type="button" id="stopBtn" value="Stop" style="display: none">
<div id="censec"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Note that although it may be mostly fine to use setInterval for displaying, using it to track the elapsed time is a bad idea; it frequently doesn't fire precisely.
Instead, record when you started
var start = Date.now();
...and then when the timer fires, figure out how long it's been since you started
var elapsed = Date.now() - start;
Then use the value (milliseconds) in elapsed to figure out your display.
Your variable declarations have ; instead of , .
Also checking numbers on equality should be done by using === but that is not the problem here.
Your also not updating the view in your timer. So updating of your html should also be in your function that is called by the timer.
If the goal is to use real seconds and milliseconds, I also suggest using the Date type because your timer will be late and not real-time. So still use the timer with the interval you like but in the add function you call the date object. You can replace the 3 vars for one datetime of type Date which will give you the granularity that you like.
var dateTimeStart = null, censecElement = null, timer = null;
$("#startBtn").on("click", function() {//when start button is clicked
$(this).hide(); // start is hidden
$("#stopBtn").show(); // stop is shown
if(timer === null) {
// timer was not started
dateTimeStart = new Date();
timer = setInterval(updateCensec, 10); //the censec will be increased every 10 millisecond.
console.log("Started timer");
}
});
$("#stopBtn").on("click", function() {//when stop button is clicked
$(this).hide(); // stop is hidden
$("#startBtn").show(); // start is shown
if(timer) {
// timer is started/running
clearInterval(timer);
console.log("Stopped timer");
}
timer = null;
});
function updateCensec() {
var sensec = 0, sec = 0, dateTimeNow = new Date(), diffMilliseconds = 0;
diffMilliseconds = dateTimeNow - dateTimeStart;
censec = parseInt((diffMilliseconds % 600 ) / 10); // convert milliseconds to centi seconds
sec = parseInt(diffMilliseconds / 600);
if(censecElement === null) {
censecElement = $("#censec");
}
censecElement.text(sec + ":" + censec);
}
I would like to suggest that you do not update your view every 10 milliseconds even if you want your stopwatch to show time in centiseconds.

Js Timeout Display

I am not sure if this possible using my current method, but I am wondering if it is possible to show the timeout as a counter on page.
I am creating a page to show data entering the database in 15 second intervals however the timeout can be changed.
var counter = 15 * 1000
var autoRefresh = function(){
clearInterval(interval);
interval = setInterval(autoRefresh, counter);
$.pjax.reload({container:"#content",async:false, timeout: 2000});
return false;
}
var interval = setInterval(autoRefresh, counter);
Ideally I need to show a countdown timer till the next refresh. Is it possible or is there an alternate route I can take to achieve this?
The only real way is to run your interval every second, display the countdown and, if 15 seconds have past, do what you want to do.
var counter = 15 * 1000;
var currentCycle = 0;
var autoRefresh = function(){
currentCycle++;
if (currentCycle >= (counter/1000)) {
currentCycle = 0;
$.pjax.reload({container:"#content",async:false, timeout: 2000});
} else {
console.log((counter/1000-currentCycle)+' seconds remaining');
}
return false;
}
var interval = setInterval(autoRefresh, 1000);

Waiting for a method inside an object constructor to complete before continuing

I am building a timer that counts from 25 mins to 0 and then from 5mins to 0 a certain number of times. Right now, I have a CountDownTimer object with a param of 25*60 that counts from 25 to 0. I want to start a new timer that would count from 5 to 0 once the other timer reaches 0. How do I implement this type of asynchronous code and then execute that asynchronous code X number of times?
$(document).ready(function(){
var sessionBreakTimer = new CountDownTimer(25*60);
sessionTimer.start();
if (!sessionTimer.isRunning) {
sessionBreakTimer.start();
}
);
function CountDownTimer(secs) {
var duration = secs;
var running = false;
this.start = function() {
running = true;
var startT = new Date().getTime();
var intervalId = window.setInterval(function() {
var msDelta = new Date().getTime() - startT; // milliseconds elapsed since start
var secsLeft = duration - Math.floor(msDelta / 1000);
if (secsLeft === 0) {
window.clearInterval(intervalId);
console.log("cleared");
running = false;
}
}, 1000); //update about every second
};
this.isRunning = function() {
return running;
}
}
Try utilizing Promise
var intervalId,
// current count
count = 0,
// current stop
stop = 2,
// cycles of `session`
ticks = 0,
// cycles of `session` to call
total = 2,
counter = function counter(session) {
var fn = function fn() {
// call `CountDownTimer.start()`
return new CountDownTimer(session[count]).start()
.then(function(data) {
console.log(data);
// recursively call `counter`
return counter(session)
})
}
return count < stop ? fn() : (function() {
// increment `ticks`
++ticks;
// reset `count` to `0`
count = 0;
return ticks < total
? fn()
// do stuff when `ticks` equal to `total`
: Promise.resolve({
count: count,
ticks: ticks,
total: total
})
}())
}
function CountDownTimer(secs) {
var duration = secs;
var running = false;
countdown = this;
this.start = function() {
// return `Promise` object from `CountDownTimer.start`
return new Promise(function(resolve) {
running = true;
var startT = new Date().getTime();
intervalId = window.setInterval(function() {
// milliseconds elapsed since start
var msDelta = new Date().getTime() - startT;
var secsLeft = duration - Math.floor(msDelta / 1000);
console.log(secsLeft);
if (secsLeft === 0) {
window.clearInterval(intervalId);
// increment `count`
++count;
console.log("cleared");
running = false;
resolve({
count: count,
ticks: ticks,
total: total
})
}
}, 1000); //update about every second
})
};
this.isRunning = function() {
return running;
};
}
// settings for `sessions`
// set to 60 seconds, 30 seconds for stacksnippets
var sessions = [1 * 60, 0.5 * 60];
// var sessions = [25 * 60, 5 * 60];
counter(sessions)
// do stuff when all cycles of `ticks` complete
.then(function(data) {
console.log("complete:", data)
});
You could add a callback method to your countdown and set it so it calls the proper timer when you reach 0 sec. Like this for example:
function CountDownTimer(secs) {
var self = this;
var duration = secs;
var running = false;
this.callback = function(){}; //This will allow you to define this afterwards
this.start = function() {
running = true;
var startT = new Date().getTime();
var intervalId = window.setInterval(function() {
var msDelta = new Date().getTime() - startT; // milliseconds elapsed since start
var secsLeft = duration - Math.floor(msDelta / 1000);
if (secsLeft === 0) {
window.clearInterval(intervalId);
console.log("cleared", secs);
running = false;
self.callback();//your callback is being called here
}
}, 1000); //update about every second
};
this.isRunning = function() {
return running;
}
}
And you define it like this:
$(document).ready(function(){
var sessionBreakTimer = new CountDownTimer(25*60);
var sessionTimer = new CountDownTimer(5*60);
sessionBreakTimer.callback = sessionTimer.start;//sessionTimer will be called when breaktimer is over
sessionTimer.callback = sessionBreakTimer.start;//and vice versa
sessionTimer.start();
});
http://jsfiddle.net/bw0nzw3m/1/
If you want this to be executed only a specific number of times, you'll need a variable to count every time a timer is called, and when it's over, you set your callback to a function with finish behavior or just an empty function depending on your need.

Plain JS countdown with repeat and delay

I keep running into several issues when creating a countdown script
it does not run smoothly
hard to make it repeat (closure)
hard to delay the start and to delay the repeat (closure)
Can someone please help me FIX this code which should work in my opinion but doesn't
the processing I need is
a. counter starts delay number of seconds after the page loads,
b. when counter reaches 0, the countdown RE-starts after delay number of seconds
Here is my Fiddle
Issues:
when it starts, the counter seems to wait an additional second before counting down
it does not pause
the repeat starts after the counter has continued
.
// more accurate timer - https://gist.github.com/1185904
function interval(duration, fn){
this.baseline = undefined
this.run = function(){
if(this.baseline === undefined){
this.baseline = new Date().getTime()
}
fn()
var end = new Date().getTime()
this.baseline += duration
var nextTick = duration - (end - this.baseline)
if(nextTick<0){
nextTick = 0
}
(function(i){
i.timer = setTimeout(function(){
i.run(end)
}, nextTick)
}(this))
}
this.stop = function(){
clearTimeout(this.timer)
}
}
window.onload=function() {
var cnt1 = 10;
var delay1 = 5;
var timer1 = new interval(1000, function(){
document.getElementById('out1').innerHTML=cnt1--
if (cnt1 <= 0) { // trying to reset
timer1.stop(); // does not work
cnt1 = 10;
setTimeout(function() { timer1.run()},delay1*1000)
}
})
setTimeout(function() { timer1.run()},delay1*1000)
}
I've rewritten your code to produce the desired results. Your previous code was very inefficient. See my script comments for usage.
Fiddle: http://jsfiddle.net/RVBDQ/1/
/*
#name timer
#param number startFrom Starts counting down from this number
#param number delay Seconds to wait before repeating the counter
#param number intervalDelay Milliseconds between countdown
#param number runTimes Optional; Limit of counting. The function stops when it has run <runTimes> times. Default 1 (=one countdown)
#param Boolean noFirstRun Optional; If false, the counter starts off immediately. Default false
*/
function timer(startFrom, delay, intervalDelay, runTimes, notFirstRun){
if(typeof runTimes == "undefined") runTimes = 1;
if(runTimes-- < 0) return;
setTimeout(function(){
var ctn = startFrom;
var timer1 = window.setInterval(function(){
document.getElementById('out1').innerHTML = ctn--;
if(ctn <= 0){
clearInterval(timer1);
timer(startFrom, delay, intervalDelay, runTimes, true);
}
}, intervalDelay);
}, notFirstRun?delay*1000:0);
}
window.onload=function() {
timer(10, 5, 1000, 2);
//Runs two times, starts counting from 10 to 1, delays 5 seconds between counters.
}
Object exposing start([delay]) and stop().
http://jsfiddle.net/RVBDQ/3/
function interval(duration, fn, delay){
this.timer = null;
this.duration = duration;
this.fn = fn;
this.start(delay);
}
interval.prototype.start = function(delay){
if (this.timer) {return;}
var self=this;
this.timer = setTimeout(function(){ self.run(); }, delay||0);
};
interval.prototype.run = function(called){
var self = this,
nextTick = called ? this.duration - (new Date - called) : 0;
this.timer = setTimeout(function(){
self.fn();
self.run(new Date);
}, nextTick<0 ? 0 : nextTick);
};
interval.prototype.stop = function(){
clearTimeout(this.timer);
this.timer = null;
};
window.onload = function() {
var cnt1 = 10;
var delay1 = 5;
window.timer1 = new interval(1000, function(){
document.getElementById('out1').innerHTML=cnt1;
cnt1 = cnt1 === 1 ? 10 : cnt1-1;
}, delay1*1000);
};

Categories