I am a JavaScript newbie. I am using a template which has the code below. It shows a countdown timer. I can't understand why it does not work. I have provided it the value of 90 days. Please guide. Thanks
// Generated by CoffeeScript 1.4.0
/*
countdown is a simple jquery plugin for countdowns
Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
and GPL-3.0 (http://opensource.org/licenses/GPL-3.0) licenses.
#source: http://github.com/rendro/countdown/
#autor: Robert Fleischmann
#version: 1.0.1
*/
(function () {
(function ($) {
$.countdown = function (el, options) {
var getDateData,
_this = this;
this.el = el;
this.$el = $(el);
this.$el.data("countdown", this);
this.init = function () {
_this.options = $.extend({}, $.countdown.defaultOptions, options);
if (_this.options.refresh) {
_this.interval = setInterval(function () {
return _this.render();
}, _this.options.refresh);
}
_this.render();
return _this;
};
getDateData = function (endDate) {
var dateData, diff;
endDate = Date.parse($.isPlainObject(_this.options.date) ? _this.options.date : new Date(_this.options.date));
diff = (endDate - Date.parse(new Date)) / 1000;
if (diff <= 0) {
diff = 0;
if (_this.interval) {
_this.stop();
}
_this.options.onEnd.apply(_this);
}
dateData = {
years: 90,
days: 90,
hours: 0,
min: 0,
sec: 90,
millisec: 0
};
if (diff >= (365.25 * 86400)) {
dateData.years = Math.floor(diff / (365.25 * 86400));
diff -= dateData.years * 365.25 * 86400;
}
if (diff >= 86400) {
dateData.days = Math.floor(diff / 86400);
diff -= dateData.days * 86400;
}
if (diff >= 3600) {
dateData.hours = Math.floor(diff / 3600);
diff -= dateData.hours * 3600;
}
if (diff >= 60) {
dateData.min = Math.floor(diff / 60);
diff -= dateData.min * 60;
}
dateData.sec = diff;
return dateData;
};
this.leadingZeros = function (num, length) {
if (length == null) {
length = 2;
}
num = String(num);
while (num.length < length) {
num = "0" + num;
}
return num;
};
this.update = function (newDate) {
_this.options.date = newDate;
return _this;
};
this.render = function () {
_this.options.render.apply(_this, [getDateData(_this.options.date)]);
return _this;
};
this.stop = function () {
if (_this.interval) {
clearInterval(_this.interval);
}
_this.interval = null;
return _this;
};
this.start = function (refresh) {
if (refresh == null) {
refresh = _this.options.refresh || $.countdown.defaultOptions.refresh;
}
if (_this.interval) {
clearInterval(_this.interval);
}
_this.render();
_this.options.refresh = refresh;
_this.interval = setInterval(function () {
return _this.render();
}, _this.options.refresh);
return _this;
};
return this.init();
};
$.countdown.defaultOptions = {
date: "June 7, 2087 15:03:25",
refresh: 1000,
onEnd: $.noop,
render: function (date) {
return $(this.el).html("" + date.years + " years, " + date.days + " days, " + (this.leadingZeros(date.hours)) + " hours, " + (this.leadingZeros(date.min)) + " min and " + (this.leadingZeros(date.sec)) + " sec");
}
};
$.fn.countdown = function (options) {
return $.each(this, function (i, el) {
var $el;
$el = $(el);
if (!$el.data('countdown')) {
return $el.data('countdown', new $.countdown(el, options));
}
});
};
return void 0;
})(jQuery);
}).call(this);
Just change
endDate = Date.parse($.isPlainObject(_this.options.date)
? _this.options.date : new Date(_this.options.date));
to
endDate = Date.parse($.isPlainObject(_this.options.date)
? _this.options.date : new Date(year,month,date));
example:
endDate = Date.parse($.isPlainObject(_this.options.date)
? _this.options.date : new Date(2017,02,15));
Related
Why does my class declaration give the error "Uncaught TypeError: timer.getTime is not a function at update"? My other class functions, like "timer.getStop()", does not. Why is that?
class Timer {
constructor() {
this.time = 0;
this.stop = false;
setInterval(update, 1000);
}
setStop(bool) {
this.stop = bool;
}
setTime(t) {
this.time = t;
}
getStop() {
return this.stop;
}
getTime() {
return this.time;
}
}
function update() {
if (timer.getTime() != 60 && !timer.getStop()) {
timer.setTime(timer.getTime += 1)
if (timer.getTime() <= 60) {
clock.innerHTML = 60 - timer.getTime();
}
//Update Stats
grossWPM = (entries / 5) / (time / 60);
netWPM = grossWPM - (wrong / (time / 60));
gross.innerHTML = 'Gross WPM: ' + grossWPM.toFixed(0);
net.innerHTML = 'Net WPM: ' + netWPM.toFixed(0);
}
}
Try to fix this
timer.setTime(timer.getTime += 1)
like that
timer.setTime(timer.getTime() + 1)
I am trying to make timer in javascript using a prototype. Each time a new timer is created, a object of prototype is created. There are methods to increase time and print each second. The whole code snippet is as follows:
function Timer(elem) {
this.interval = null;
this.currentTime = {
sec: 0,
min: 0,
hr: 0
};
this.elem = elem;
};
Timer.prototype.start = function() {
var self = this;
if (!self.interval) {
self.interval = setInterval(update, 1000);
}
function update() {
incrementTime();
render();
}
function render() {
self.elem.innerText = getPrintableTime();
}
function incrementTime() {
self.currentTime["min"] += Math.floor((++self.currentTime["sec"]) / 60);
self.currentTime["hr"] += Math.floor(self.currentTime["min"] / 60);
self.currentTime["sec"] = self.currentTime["sec"] % 60;
self.currentTime["min"] = self.currentTime["min"] % 60;
}
function getPrintableTime() {
var text = getTwoDigitNumber(self.currentTime["hr"]) + ":" + getTwoDigitNumber(self.currentTime["min"]) + ":" + getTwoDigitNumber(self.currentTime["sec"]);
return text;
}
function getTwoDigitNumber(number) {
if (number > 9) {
return "" + number;
} else {
return "0" + number;
}
}
};
module.exports = Timer;
I have all methods in start function. The problem is that for each new object of Timer, new space for each method will be used which is very inefficient. But when I try to put methods outside of start function, they lose access to self variable. You can see that there is setInterval function used which will be calling these methods per second. I cannot use this also as this will be instance of Window in subsequent calls.
How can I solve this situation by only keeping one instance of all the interior methods?
You don't need to have all methods in the start function. Yes, for each new Timer instance, new space for each function will be used, but that is necessary when you want to work with setInterval as you need a function which closes over the instance. However, you need only one such closure, the other methods can be standard prototype methods.
function getTwoDigitNumber(number) {
return (number > 9 ? "" : "0") + number;
}
function Timer(elem) {
this.interval = null;
this.currentTime = {
sec: 0,
min: 0,
hr: 0
};
this.elem = elem;
};
Timer.prototype.start = function() {
var self = this;
if (!this.interval) {
this.interval = setInterval(function update() {
self.incrementTime();
self.render();
}, 1000);
}
};
Timer.prototype.render() {
this.elem.innerText = this.getPrintableTime();
};
Timer.prototype.incrementTime = function() {
this.currentTime.sec += 1;
this.currentTime.min += Math.floor(this.currentTime.sec / 60);
this.currentTime.hr += Math.floor(this.currentTime.min / 60);
this.currentTime.sec = this.currentTime.sec % 60;
this.currentTime.min = this.currentTime.min % 60;
};
Timer.prototype.getPrintableTime = function() {
var text = getTwoDigitNumber(this.currentTime.hr) + ":"
+ getTwoDigitNumber(this.currentTime.min) + ":"
+ getTwoDigitNumber(self.currentTime.sec);
return text;
};
module.exports = Timer;
Btw, regarding your incrementTime pattern, you should have a look at How to create an accurate timer in javascript?.
You can use apply to use functions defined outside of prototype with correct this context.
function Timer(elem) {
this.interval = null;
this.currentTime = {
sec: 0,
min: 0,
hr: 0
};
this.elem = elem;
};
function update() {
incrementTime.apply(this);
render.apply(this);
}
function render() {
this.elem.innerText = getPrintableTime.apply(this);
}
function incrementTime() {
this.currentTime["min"] += Math.floor((++this.currentTime["sec"]) / 60);
this.currentTime["hr"] += Math.floor(this.currentTime["min"] / 60);
this.currentTime["sec"] = this.currentTime["sec"] % 60;
this.currentTime["min"] = this.currentTime["min"] % 60;
}
function getPrintableTime() {
var text = getTwoDigitNumber(this.currentTime["hr"]) + ":" + getTwoDigitNumber(this.currentTime["min"]) + ":" + getTwoDigitNumber(this.currentTime["sec"]);
return text;
}
function getTwoDigitNumber(number) {
if (number > 9) {
return "" + number;
} else {
return "0" + number;
}
}
Timer.prototype.start = function() {
var self = this;
if (!self.interval) {
self.interval = setInterval(function() {
update.apply(self);
}, 1000);
}
};
document.addEventListener('DOMContentLoaded', function() {
var timer = new Timer(document.getElementById('timer'));
timer.start();
}, false);
<div id="timer"></div>
If I understand correctly, you're wanting to only create one interval.
One possible solution would be to create a static method and variable to manage the setInterval. I would note that while this may be more performance friendly, the timers will always start and run on the same count...not from the moment each timer is created. (See example)
Of course, you could capture the current timestamp and calculate the elapsed time from there. But, that's another thread ;)
function Timer(elem) {
this.interval = null;
this.currentTime = {
sec: 0,
min: 0,
hr: 0
};
this.elem = elem;
};
Timer.subscribe = function(timer) {
Timer.subscribers = Timer.subscribers || [];
if (Timer.subscribers.indexOf(timer) === -1) {
Timer.subscribers.push(timer);
timer.update.call(timer);
}
Timer.checkInterval();
};
Timer.unsubscribe = function(timer) {
Timer.subscribers = Timer.subscribers || [];
if (Timer.subscribers.indexOf(timer) !== -1) {
Timer.subscribers.splice(Timer.subscribers.indexOf(timer), 1);
}
Timer.checkInterval();
};
Timer.checkInterval = function() {
if (!Timer.interval && Timer.subscribers.length > 0) {
Timer.interval = setInterval(function() {
Timer.subscribers.forEach(function(item) {
item.update.call(item);
});
}, 1000);
} else if (Timer.interval && Timer.subscribers.length === 0) {
clearInterval(Timer.interval);
Timer.interval = null;
}
};
Timer.prototype = {
start: function() {
Timer.subscribe(this);
},
stop: function() {
Timer.unsubscribe(this);
},
update: function() {
this.incrementTime();
this.render();
},
incrementTime: function() {
this.currentTime["min"] += Math.floor((++this.currentTime["sec"]) / 60);
this.currentTime["hr"] += Math.floor(this.currentTime["min"] / 60);
this.currentTime["sec"] = this.currentTime["sec"] % 60;
this.currentTime["min"] = this.currentTime["min"] % 60;
},
render: function() {
var self = this;
function getPrintableTime() {
var text = getTwoDigitNumber(self.currentTime["hr"]) + ":" + getTwoDigitNumber(self.currentTime["min"]) + ":" + getTwoDigitNumber(self.currentTime["sec"]);
return text;
}
function getTwoDigitNumber(number) {
if (number > 9) {
return "" + number;
} else {
return "0" + number;
}
}
this.elem.innerText = getPrintableTime();
}
};
/**
*
*/
var timers = document.getElementById('timers');
function addTimer() {
var el = document.createElement('div');
var tmr = document.createElement('span');
var btn = document.createElement('button');
var t = new Timer(tmr);
btn.innerText = 'Stop';
btn.onclick = function() {
t.stop();
};
el.appendChild(tmr);
el.appendChild(btn);
timers.appendChild(el);
t.start();
};
<div id="timers"></div>
<button onclick="addTimer()">Add Timer</button>
Below is my JS and then my HTML . I cannot figure out why my countdown clock doesn't automatically count down. You must refresh every second to see the correct amount of time left. Any ideas? BTW this is for a Christmas countdown website I am working on.
var Countdowns = function(end, elements, timer, callback) {
var _seconds = 1000,
_minutes = _seconds * 60,
_hours = _minutes * 60,
_days = _hours * 24,
end = new Date(end)
timer,
calculate = function() {
var now = new Date(),
remaining = end.getTime() - now.getTime(),
data;
if (isNaN(end)) {
console.log('Invalid date/time')
return;
}
if (remaining <= 0) { // clear timer
clearInterval(timer);
// callback
if (typeof callback === 'function') {
callback()
}
} else {
if (!timer) {
timer = setInterval(calculate, _seconds);
}
data = {
'days': Math.floor(remaining / _days),
'hours': Math.floor((remaining % _days) / _hours),
'minutes': Math.floor((remaining % _hours) / _minutes),
'seconds': Math.floor((remaining % _minutes) / _seconds),
}
if (elements.length) {
for (x in elements) {
var x = elements[x];
data[x] = ('00' + data[x]).slice(-2);
document.getElementById(x).innerHTML = data[x];
}
}
}
};
calculate();
}
<!DOCTYPE html>
<html>
<head>
<title>Countdowns</title>
</head>
<body>
<span id="days">00</span>
<span id="hours">00</span>
<span id="minutes">00</span>
<span id="seconds">00</span>
<script src="Countdowns.js"></script>
<script>
var callbackfunction = function() {
console.log('Done!')
}
Countdowns('12/25/2015 00:00:00 AM', ['days', 'hours', 'minutes', 'seconds']);
callbackfunction);
</script>
</body>
</html>
You have a couple of minor errors. Try this:
var Countdowns = function(end, elements, timer, callback) {
var _seconds = 1000,
_minutes = _seconds * 60,
_hours = _minutes * 60,
_days = _hours * 24,
end = new Date(end)
timer,
calculate = function() {
var now = new Date(),
remaining = end.getTime() - now.getTime(),
data;
if (isNaN(end)) {
console.log('Invalid date/time')
return;
}
if (remaining <= 0) { // clear timer
clearInterval(timer);
// callback
if (typeof callback === 'function') {
callback()
}
} else {
if (!timer) {
timer = setInterval(calculate, _seconds);
}
data = {
'days': Math.floor(remaining / _days),
'hours': Math.floor((remaining % _days) / _hours),
'minutes': Math.floor((remaining % _hours) / _minutes),
'seconds': Math.floor((remaining % _minutes) / _seconds),
}
if (elements.length) {
for (x in elements) {
var x = elements[x];
data[x] = ('00' + data[x]).slice(-2);
document.getElementById(x).innerHTML = data[x];
}
}
}
};
calculate();
};
var callbackfunction = function() {
console.log('Done!')
}
Countdowns('12/25/2015 00:00:00 AM', ['days', 'hours', 'minutes', 'seconds']);
callbackfunction();
<!DOCTYPE html>
<html>
<head>
<title>Countdowns</title>
</head>
<body>
<span id="days">00</span>
<span id="hours">00</span>
<span id="minutes">00</span>
<span id="seconds">00</span>
<script src="Countdowns.js"></script>
</body>
</html>
replace callbackfunction); with callbackfunction();
var Countdowns = function(end, elements, timer, callback) {
var _seconds = 1000,
_minutes = _seconds * 60,
_hours = _minutes * 60,
_days = _hours * 24,
end = new Date(end)
timer,
calculate = function() {
var now = new Date(),
remaining = end.getTime() - now.getTime(),
data;
if (isNaN(end)) {
console.log('Invalid date/time')
return;
}
if (remaining <= 0) { // clear timer
clearInterval(timer);
// callback
if (typeof callback === 'function') {
callback()
}
} else {
if (!timer) {
timer = setInterval(calculate, _seconds);
}
data = {
'days': Math.floor(remaining / _days),
'hours': Math.floor((remaining % _days) / _hours),
'minutes': Math.floor((remaining % _hours) / _minutes),
'seconds': Math.floor((remaining % _minutes) / _seconds),
}
if (elements.length) {
for (x in elements) {
var x = elements[x];
data[x] = ('00' + data[x]).slice(-2);
document.getElementById(x).innerHTML = data[x];
}
}
}
};
calculate();
};
var callbackfunction = function() {
console.log('Done!')
};
Countdowns('12/25/2015 00:00:00 AM', ['days', 'hours', 'minutes', 'seconds']);
<span id="days">00</span>
<span id="hours">00</span>
<span id="minutes">00</span>
<span id="seconds">00</span>
I'm creating a simple web browser game. In it there is a clock, it doesn't display the real time, but is supposed to start at 9:00 am and avance 1h every time a button is clicked. The problem is that it only works on the first button click and always stays at 10am when I click a button again. I don't understand why.
Here's the code:
<script role="script" id="twine-user-script" type="text/twine-javascript">
$(document).ready( function() {
var callback = function() {
displayTime.incrementTime();
};
$('#onebutton .link-internal').on('click', callback);
$('#container1 .link-internal').on('click', callback);
$('#container2 .link-internal').on('click', callback);
var displayTime = {
currentTime: new Date(new Date().getUTCFullYear(),
new Date().getUTCMonth(),
new Date().getUTCDay(),
'9',
'0',
'0',
'0'),
hoursVal: null,
hours: function() {
return displayTime.currentTime.getHours();
},
minutesVal: null,
minutes: function() {
return displayTime.currentTime.getMinutes();
},
meridiem: "am",
init: function() {
displayTime.formatDate();
displayTime.display();
},
formatDate: function() {
if (displayTime.hours() > 12) {
displayTime.hoursVal = displayTime.hours() - 12;
displayTime.meridiem = "pm";
}
if (displayTime.hours() === 0) {
displayTime.hoursVal = 12;
}
if(displayTime.hours() < 10) {
displayTime.hoursVal = "0" + displayTime.hours();
}
if(displayTime.minutes() < 10) {
displayTime.minutesVal = "0" + displayTime.minutes();
}
},
resetValues: function() {
displayTime.hoursVal = null;
displayTime.minutesVal = null;
//displayTime.secondsVal = null;
},
display: function() {
var clockDiv = document.getElementById('clock');
clockDiv.innerText = (displayTime.hoursVal === null ? displayTime.hours() : displayTime.hoursVal) + ":" +
(displayTime.minutesVal === null ? displayTime.minutes() : displayTime.minutesVal) + " " +
displayTime.meridiem;
},
incrementTime: function() {
displayTime.currentTime = new Date(displayTime.currentTime.getTime() + (1000 * 60 * 60));
displayTime.resetValues();
displayTime.formatDate();
displayTime.display();
}
};
displayTime.init();
setInterval(displayTime.init, 1000);
});
</script>
Can anyone point out where the error in my code is?
This JSFiddle works better, but I need your HTML too to give you the exact problem you have:
JS:
$(document).ready(function () {
var callback = function () {
displayTime.incrementTime();
};
$('#onebutton').on('click', callback);
$('#container1').on('click', callback);
$('#container2').on('click', callback);
var displayTime = {
currentTime: new Date(new Date().getUTCFullYear(),
new Date().getUTCMonth(),
new Date().getUTCDay(),
'9',
'0',
'0',
'0'),
hoursVal: null,
hours: function () {
return displayTime.currentTime.getHours();
},
minutesVal: null,
minutes: function () {
return displayTime.currentTime.getMinutes();
},
meridiem: "am",
init: function () {
displayTime.formatDate();
displayTime.display();
},
formatDate: function () {
if (displayTime.hours() > 12) {
displayTime.hoursVal = displayTime.hours() - 12;
displayTime.meridiem = "pm";
}
if (displayTime.hours() === 0) {
displayTime.hoursVal = 12;
}
if (displayTime.hours() < 10) {
displayTime.hoursVal = "0" + displayTime.hours();
}
if (displayTime.minutes() < 10) {
displayTime.minutesVal = "0" + displayTime.minutes();
}
},
resetValues: function () {
displayTime.hoursVal = null;
displayTime.minutesVal = null;
//displayTime.secondsVal = null;
},
display: function () {
var clockDiv = document.getElementById('clock');
clockDiv.innerText = (displayTime.hoursVal === null ? displayTime.hours() : displayTime.hoursVal) + ":" + (displayTime.minutesVal === null ? displayTime.minutes() : displayTime.minutesVal) + " " + displayTime.meridiem;
},
incrementTime: function () {
displayTime.currentTime = new Date(displayTime.currentTime.getTime() + (1000 * 60 * 60));
displayTime.resetValues();
displayTime.formatDate();
displayTime.display();
}
};
displayTime.init();
setInterval(displayTime.init, 1000);
});
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