I found a neat timer but I need to customize it a bit to work for my project, I tried to change javascript code so it would be a countdown until the weekend and start again from ex: 6days:23hours:59minutes, but I failed miserably
I also would like to know how possible could I add a third row called days
http://codepen.io/anon/pen/ZYEBjP
JS code
var Clock = (function(){
var exports = function(element) {
this._element = element;
var html = '';
for (var i=0;i<6;i++) {
html += '<span> </span>';
}
this._element.innerHTML = html;
this._slots = this._element.getElementsByTagName('span');
this._tick();
};
exports.prototype = {
_tick:function() {
var time = new Date();
this._update(this._pad(time.getHours()) + this._pad(time.getMinutes()) + this._pad(time.getSeconds()));
var self = this;
setTimeout(function(){
self._tick();
},1000);
},
_pad:function(value) {
return ('0' + value).slice(-2);
},
_update:function(timeString) {
var i=0,l=this._slots.length,value,slot,now;
for (;i<l;i++) {
value = timeString.charAt(i);
slot = this._slots[i];
now = slot.dataset.now;
if (!now) {
slot.dataset.now = value;
slot.dataset.old = value;
continue;
}
if (now !== value) {
this._flip(slot,value);
}
}
},
_flip:function(slot,value) {
// setup new state
slot.classList.remove('flip');
slot.dataset.old = slot.dataset.now;
slot.dataset.now = value;
// force dom reflow
slot.offsetLeft;
// start flippin
slot.classList.add('flip');
}
};
return exports;
}());
var i=0,clocks = document.querySelectorAll('.clock'),l=clocks.length;
for (;i<l;i++) {
new Clock(clocks[i]);
}
I would create a helper:
var TimeHelper = function(days, hours, minutes, callback) {
this.subtractMinute = function() {
minutes = (minutes + 60 - 1) % 60;
if (minutes === 0) {
hours = (hours + 60 - 1) % 60;
if (hours === 0) {
days = (days + 24 - 1) % 24;
if (days === 0) {
days = 24;
hours = 0;
minutes = 0;
}
}
}
callback(days, hours, minutes);
}
}
function refreshUI(days, hours, minutes) {
//refresh my ui elements
}
var timeHelper = new TimeHelper(24, 0, 0);
And then you can call timeHelper.subtractMinute once/minute this on every minute
Related
I am working on a countdown for my website. We provide same day dispatch before 16:00 each day. I need a counter that will display a countdown to 16:00 each day.
Eventually, I will modify the code so that it doesn't display at all on the weekends but for now, all I need is something that can countdown everyday. Disappear after 16:00 and start fresh and countdown again from 00:00
Below is the code I have so far.
<?php
if (new DateTime() < new DateTime("16:00:00")) {
?>
<script type="text/javascript">
var CDown = function() {
this.state=0;// if initialized
this.counts=[];// array holding countdown date objects and id to print to {d:new Date(2013,11,18,18,54,36), id:"countbox1"}
this.interval=null;// setInterval object
}
CDown.prototype = {
init: function(){
this.state=1;
var self=this;
this.interval=window.setInterval(function(){self.tick();}, 1000);
},
add: function(date,id){
this.counts.push({d:date,id:id});
this.tick();
if(this.state==0) this.init();
},
expire: function(idxs){
for(var x in idxs) {
this.display(this.counts[idxs[x]], "Now!");
this.counts.splice(idxs[x], 1);
}
},
format: function(r){
var out="";
if(r.d != 0){out += r.d +" "+((r.d==1)?"day":"days")+", ";}
if(r.h != 0){out += r.h +" "+((r.h==1)?"hour":"hours")+", ";}
out += r.m +" "+((r.m==1)?"min":"mins")+", ";
out += r.s +" "+((r.s==1)?"sec":"secs")+", ";
return out.substr(0,out.length-2);
},
math: function(work){
var y=w=d=h=m=s=ms=0;
ms=(""+((work%1000)+1000)).substr(1,3);
work=Math.floor(work/1000);//kill the "milliseconds" so just secs
y=Math.floor(work/31536000);//years (no leapyear support)
w=Math.floor(work/604800);//weeks
d=Math.floor(work/86400);//days
work=work%86400;
h=Math.floor(work/3600);//hours
work=work%3600;
m=Math.floor(work/60);//minutes
work=work%60;
s=Math.floor(work);//seconds
return {y:y,w:w,d:d,h:h,m:m,s:s,ms:ms};
},
tick: function(){
var now=(new Date()).getTime(),
expired=[],cnt=0,amount=0;
if(this.counts)
for(var idx=0,n=this.counts.length; idx<n; ++idx){
cnt=this.counts[idx];
amount=cnt.d.getTime()-now;//calc milliseconds between dates
// if time is already past
if(amount<0){
expired.push(idx);
}
// date is still good
else{
this.display(cnt, this.format(this.math(amount)));
}
}
// deal with any expired
if(expired.length>0) this.expire(expired);
// if no active counts, stop updating
if(this.counts.length==0) window.clearTimeout(this.interval);
},
display: function(cnt,msg){
document.getElementById(cnt.id).innerHTML=msg;
}
};
window.onload=function(){
var cdown = new CDown();
cdown.add(new Date(2015,9,16,16,00,00), "countbox1");
};
</script>
<span style="font-size:30px;"><div id="countbox1"></div></span>
<?php } ?>
concept here testing
change the variable countDownTo to the current hour on line 8, 103 and 109
change the variable minute on line 133
<?php if (new DateTime() < new DateTime( "16:00:00")) { ?>
<script type="text/javascript">
var check = 0;
/*set the countdown hour*/
var countDownTo = 16;
var CDown = function() {
this.state = 0; // if initialized
this.counts = []; // array holding countdown date objects and id to print to {d:new Date(2013,11,18,18,54,36), id:"countbox1"}
this.interval = null; // setInterval object
}
CDown.prototype = {
init: function() {
this.state = 1;
var self = this;
this.interval = window.setInterval(function() {
self.tick();
}, 1000);
},
add: function(date, id) {
this.counts.push({
d: date,
id: id
});
this.tick();
if (this.state == 0) this.init();
},
expire: function(idxs) {
for (var x in idxs) {
this.display(this.counts[idxs[x]], "Now!");
this.counts.splice(idxs[x], 1);
}
},
format: function(r) {
var out = "";
if (r.d != 0) {
out += r.d + " " + ((r.d == 1) ? "day" : "days") + ", ";
}
if (r.h != 0) {
out += r.h + " " + ((r.h == 1) ? "hour" : "hours") + ", ";
}
out += r.m + " " + ((r.m == 1) ? "min" : "mins") + ", ";
out += r.s + " " + ((r.s == 1) ? "sec" : "secs") + ", ";
return out.substr(0, out.length - 2);
},
math: function(work) {
var y = w = d = h = m = s = ms = 0;
ms = ("" + ((work % 1000) + 1000)).substr(1, 3);
work = Math.floor(work / 1000); //kill the "milliseconds" so just secs
y = Math.floor(work / 31536000); //years (no leapyear support)
w = Math.floor(work / 604800); //weeks
d = Math.floor(work / 86400); //days
work = work % 86400;
h = Math.floor(work / 3600); //hours
work = work % 3600;
m = Math.floor(work / 60); //minutes
work = work % 60;
s = Math.floor(work); //seconds
return {
y: y,
w: w,
d: d,
h: h,
m: m,
s: s,
ms: ms
};
},
tick: function() {
var now = (new Date()).getTime(),
expired = [],
cnt = 0,
amount = 0;
if (this.counts)
for (var idx = 0, n = this.counts.length; idx < n; ++idx) {
cnt = this.counts[idx];
amount = cnt.d.getTime() - now; //calc milliseconds between dates
// if time is already past
if (amount < 0) {
expired.push(idx);
}
// date is still good
else {
this.display(cnt, this.format(this.math(amount)));
}
}
// deal with any expired
if (expired.length > 0) this.expire(expired);
// if no active counts, stop updating
if (this.counts.length == 0) window.clearTimeout(this.interval);
},
display: function(cnt, msg) {
if (msg == `Now!`) {
check = 1;
msg = ``;
var cdown = new CDown();
var currentdate = new Date();
var year = currentdate.getFullYear();
var month = currentdate.getMonth();
var day = currentdate.getDate() + 1;
var currenthour = currentdate.getHours();
/*perform check here*/
if (countDownTo == 16) {
countDownTo = 0;
} else {
countDownTo = 16;
}
var hour = countDownTo;
var minute = 0;
var second = 0;
cdown.add(new Date(year, month, day, hour, minute, second), "countbox1");
} else {
check = 0;
}
if (countDownTo == 0) msg = ``;
document.getElementById(cnt.id).innerHTML = msg;
}
};
window.onload = function() {
var cdown = new CDown();
var currentdate = new Date();
var year = currentdate.getFullYear();
var month = currentdate.getMonth();
var day = currentdate.getDate();
var hour = countDownTo;
var minute = 0;
var second = 0;
cdown.add(new Date(year, month, day, hour, minute, second), "countbox1");
};
</script>
<span style="font-size:30px;"><div id="countbox1"></div></span>
<?php } ?>
You can use a cron job that will reset a variable once every 24 hours.
I cant figuret how set cookie for my countdownt timeer, that if i refresh page it vill not disapear but vill counting.
i be glad if eny can help. i use jquery 2.1.4 and this java countdown script, but when i refresh page all my coundown timers are lost!
/**
* Created by op on 18.07.2015.
*/
function leadZero (n)
{
n = parseInt(n);
return (n < 10 ? '0' : '') + n;
}
function startTimer(timer_id) {
var timer = $(timer_id);
var time = timer.html();
var arr = time.split(":");
var h = arr[0];
h = h.split(" / ");
h = h[1];
var m = arr[1];
var s = arr[2];
if (s == 0)
{
if (m == 0)
{
if (h == 0)
{
timer.html('')
return;
}
h--;
m = 60;
}
m--;
s = 59;
}
else
{
s--;
}
timer.html(' / '+leadZero(h)+":"+leadZero(m)+":"+leadZero(s));
setTimeout(function(){startTimer(timer_id)}, 1000);
}
function timer (name, time)
{
var timer_name = name;
var timer = $(timer_name);
var time_left = time;
timer.html(' / '+ time);
startTimer(timer_name);
}
$(document).ready(function(){
$('.fid').click(function (e)
{
var timer_name = '.timer_'+$(this).data('fid');
var timer = $(timer_name);
if (timer.html() == '')
{
var time_left = timer.data('timer');
var hours = leadZero(Math.floor(time_left / 60));
var minutes = leadZero(time_left % 60);
var seconds = '00';
timer.html(' / '+hours+':'+minutes+':'+seconds);
startTimer(timer_name);
}
});
$.each($('.tab'), function () {
$(this).click(function () {
$.each($('.tab'), function() {
$(this).removeClass('active');
});
$(this).addClass('active');
$('.list').hide();
$('#content-'+$(this).attr('id')).show();
});
});
if (window.location.hash != '')
{
var tab = window.location.hash.split('-');
tab = tab[0];
$(tab).click();
}
console.log(window.location.hash)
});
It would help if you actually set a cookie.
Setting the cookie would go like:
document.cookie="timer=" + time;
And then call it at the beginning of your code
var time = getCookie("timer");
The getCookie() function is outlined in that link, as well as a base knowledge about them.
I am new in javascript, I want to create a countdown timer with localStorage which starts from given time and end to 00:00:00, but it's not working,
When I am running my code it is showing value "1506".
Here is my code
<script type="text/javascript">
if (localStorage.getItem("counter")) {
var CurrentTime = localStorage.getItem("counter");
}
else {
var Hour = 3;
var Minute = 25;
var Second = 60;
var CurrentTime = Hour.toString() + ":" + Minute.toString() + ":" + Second.toString();
}
function CountDown() {
document.getElementById('lblDuration').innerHTML = CurrentTime;
Second--;
if (Second == -1) {
Second = 59;
Minute--;
}
if (Minute == -1) {
Minute = 59;
Hour--;
}
localStorage.setItem("counter", CurrentTime);
}
var interval = setInterval(function () { CountDown(); }, 1000);
</script>
you need to declare variables Hour, Minute, Second, CurrentTime out side if else block. In this case they are not in function CountDown() scope.
you are not setting CurrentTime = Hour.toString() + ":" + Minute.toString() + ":" + Second.toString(); after localStorage.setItem("counter", CurrentTime);
var Hour = 3;
var Minute = 25;
var Second = 60;
var CurrentTime = Hour.toString() + ":" + Minute.toString() + ":" + Second.toString();
function CountDown() {
document.getElementById('lblDuration').innerHTML = CurrentTime;
Second--;
if (Second == -1) {
Second = 59;
Minute--;
}
if (Minute == -1) {
Minute = 59;
Hour--;
}
CurrentTime = Hour.toString() + ":" + Minute.toString() + ":" + Second.toString();
}
setInterval(function () {
CountDown();
}, 1000);
<div id="lblDuration"></div>
When localStorage is available you don set the values for Hour, Minute and Second. So when the countdown function executed it finds Second to be undefined and the statement Second-- converts Second to NaN.
To fix it just initialize the Hour, Minute and Second Variable.
I 've refactored your code a little bit hope it helps:
function CountDown() {
var currentTime = getCurrentTime();
printCurrentTime(currentTime)
currentTime.second--;
if (currentTime.second == -1) {
currentTime.second = 59;
currentTime.minute--;
}
if (currentTime.minute == -1) {
currentTime.minute = 59;
currentTime.hour--;
}
setCurrentTime(currentTime);
}
function setCurrentTime(newCurrentTime){
if(localStorage) localStorage.setItem("counter", JSON.stringify(newCurrentTime));
else setCurrentTime.storage = newCurrentTime;
}
function getCurrentTime(){
var result = localStorage ? localStorage.getItem("counter") : setCurrentTime.storage;
result = result || {hour:3, minute:25, second:60};
if (typeof(result) === "string")result = JSON.parse(result);
result.toString = function(){
return result.hour + ":" + result.minute + ":" + result.second;
}
return result;
}
function printCurrentTime(currentime){
var domTag = document.getElementById('lblDuration');
if(domTag) domTag.innerHTML = currentime.toString();
else console.log(currentime);
}
setInterval(function () { CountDown(); }, 1000);
I am using a javascript timer on a page, which redirects the user after a finite time. The code is doing exactly what I want it to but it continues to throw errors in the console. The error message I get is
Uncaught TypeError: Cannot set property 'textContent' of null
//Countdown Timer
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
};
};
window.onload = function() {
var display = document.querySelector(".cdtimer"),
s6timer = new CountDownTimer(20);
s6timer.onTick(format).onTick(redirect).start();
function redirect() {
if (s6timer.expired()) {
window.location.replace("../assessmentportal/sectiontimeout.php");
}
};
function format(minutes, seconds) {
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
display.textContent = minutes + ':' + seconds;
};
};
});
This happens because this call document.querySelector(".cdtimer") returns null. There are 2 possible reasons:
There are no element with class name cdtimer
You are running your script before DOM loaded
Is your assignment of display actually returning a DOM element? If it can't find anything (typo, perhaps?) it will return null.
Am having a stopwatch with different titles, when I start a watch it runs and after 10 seconds it pops an alert.I can filter the watch on top of title, when I reset the filter the running watch is not displaying the time but it pops an alert at 10 seconds. Why the binding is not working after filter?What am doing wrong here?How can I fix it?
Find the plunker here Complete code and HTML is in plunker.
Clicking play will start the watch, pause will pause it and stop - stops the watch.
< script type = "text/javascript" > angular.module('App', [])
.controller('MainCtrl', function ($scope, $interval) {
$interval(function () {
$scope.sharedTime = new Date();
}, 500);
})
.directive('stopwatch', function () {
return {
restrict: 'AE',
templateUrl: 'stopwatch.html',
scope: {
// Set title in the isolate scope from the title attribute on the directive's element.
title: '#title',
// Set up a bi-directional binding between currentTime on the local scope and the parent
// scope's variable containing the current time that's the value of the time attribute.
currentTime: '=time'
},
link: function (scope, element, attrs, ctrl) {},
controllerAs: 'swctrl',
controller: function ($scope, $interval) {
var self = this;
var time = 0;
var mode = 1;
var status = 0;
var timer_id;
self.play = 1;
self.start = function (interval) {
self.play = 0;
var timeRet;
interval = 1000;
if (status == 0) {
status = 1;
function timeRun() {
if (time < 86400) {
time++;
timeRet = self.getElapsedMs();
if (time == 10) {
alert("Its 10 seconds")
}
if (typeof (callback) === 'function') callback(timeRet);
}
};
return timer_id = setInterval(timeRun, interval);
}
};
self.pause = function () {
self.play = 1;
if (status == 1) {
status = 0;
clearInterval(timer_id);
}
};
self.stop = function () {
self.play = 1;
sec = (typeof (sec) !== 'undefined') ? sec : 0;
time = sec;
if (status == 1) {
status = 0;
clearInterval(timer_id);
}
};
self.getTime = function () {
return time;
};
self.getElapsedMs = function () {
var second = time % 60;
var minute = Math.floor(time / 60) % 60;
var hour = Math.floor(time / 3600) % 60;
second = (second < 10) ? '0' + second : second;
minute = (minute < 10) ? '0' + minute : minute;
hour = (hour < 10) ? '0' + hour : hour;
var timeObj = hour + ":" + minute + ":" + second
return timeObj;
};
}
}
}); < /script>
How to reproduce: Activate one, then type in "two" in the textbox, then erase it. You'll see that the one timer is showing 00:00:00
Filter in ng-repeat applies your filtering keyword on the array and returns a new subset, thus destroying previously created directives.
From the docs:
Selects a subset of items from array and returns it as a new array.
If you place inside the link function:
scope.$on("$destroy", function () {
console.log("destroying");
});
You'll see that it logs for every stopwatch that is eliminated due to the filtering.
Therefore, I'd just hide the entire div of the stopwatch instead of using the filter:
<div ng-show="!filter || title.indexOf(filter) > -1">
<div class="timer" >{{title}}<br>
{{swctrl.getElapsedMs() | limitTo:6}}<span class="sec">
{{swctrl.getElapsedMs() | limitTo:-2}}</span>
</div>
Play
Pause
<a href="" id="timerStop" class="stop" ng-click="swctrl.stop();" >Stop</a>
</div>
And your usage becomes:
<div ng-repeat="item in arr">
<div stopwatch title="{{item}}" filter="filters" time="sharedTime">
</div>
Plunker
Omri Aharon explained what the issue is. Personally I'd move the stopwatch functionality into a factory and pass instances of this into your directive.
.factory('StopWatch', function() {
function StopWatch(name) {
this.name = name;
this.time = 0;
this.mode = 1;
this.status = 0;
this.play = 1;
}
StopWatch.prototype.start = function(interval) {
var self = this;
self.play = 0;
var timeRet;
interval = 1000;
if(self.status == 0)
{
self.status = 1;
function timeRun()
{
if(self.time < 86400)
{
self.time++;
timeRet = self.getElapsedMs();
if(self.time == 10)
{
alert("Its 10 seconds")
}
if(typeof(callback) === 'function') callback(timeRet);
}
};
return self.timer_id = setInterval(timeRun, interval);
}
};
StopWatch.prototype.pause = function() {
this.play = 1;
if(this.status == 1)
{
this.status = 0;
clearInterval(this.timer_id);
}
};
StopWatch.prototype.stop = function() {
this.play = 1;
var sec = (typeof(sec) !== 'undefined') ? sec : 0;
this.time = sec;
if(this.status == 1)
{
this.status = 0;
clearInterval(this.timer_id);
}
};
StopWatch.prototype.getTime = function() {
return this.time;
};
StopWatch.prototype.getElapsedMs = function() {
var second = this.time % 60;
var minute = Math.floor(this.time / 60) % 60;
var hour = Math.floor(this.time / 3600) % 60;
second = (second < 10) ? '0'+second : second;
minute = (minute < 10) ? '0'+minute : minute;
hour = (hour < 10) ? '0'+hour : hour;
var timeObj = hour+":"+minute+":"+second
return timeObj;
};
return StopWatch;
})
So you'd create the stopwatches:
$scope.timers = [
new StopWatch('one'),
new StopWatch('two'),
new StopWatch('three'),
new StopWatch('four')
];
Then repeat and pass into the directive:
<div ng-repeat="item in timers | filter:filter_">
{{item.name}}
<div stopwatch="item"></div>
</div>
Plunker