I create a countdown function but it works just at the begining and then stops.
var rek_inter = setInterval(cnt(s_, d), 1000);
function cnt(deg, deg2) {
deg--;
while (deg < 0) {
deg = 59;
deg2--;
}
if (deg2 < 0) {
$('#s_').html("ok");
} else if (deg2 >= 0) {
var d_sn = fixd(deg2);
var s_sn = fixd(deg);
$('#s_').html(d_sn + ":" + s_sn);
}
}
function fixd(g) {
if (g < 10) {
return '0' + g;
}
return g;
}
I tried that, too;
var rek_inter = setInterval(function() {cnt(s_, d);}, 1000);
But result was same.
If I put the function into the interval function like that:
var rek_inter = setInterval(function () {
s_--;
while (s_ < 0) {
s_ = 59;
d--;
}
if (d < 0) {
$('#s_').html("ok");
} else if (d >= 0) {
var d_sn = fixd(d);
var s_sn = fixd(s_);
$('#s_').html(d_sn + ":" + s_sn);
}
}, 1000);
function fixd(g) {
if (g < 10) {
return '0' + g;
}
return g;
}
It works. But I need that as I wrote first at the top. What could be the problem and solution here?
"I have lot of s_, s_2, s_3.... and d, d1, d2... values and I want to use them in single setInterval, this is why I am tryng to use cnt(s_, d); if that will work I will write cnt(s_2, d2), cnt(s_3, d3).."
You could just use closures to your advantage here.
var rek_inter1 = setInterval(cnt(s_2, d2), 1000),
rek_inter2 = setInterval(cnt(s_3, d3), 1000);
function cnt(deg, deg2) {
return function () {
deg--;
while (deg < 0) {
deg = 59;
deg2--;
}
if (deg2 < 0) {
$('#s_').html("ok");
} else if (deg2 >= 0) {
var d_sn = fixd(deg2);
var s_sn = fixd(deg);
$('#s_').html(d_sn + ":" + s_sn);
}
};
}
The first attempt is the same as :
setInterval ( value, time) ;
Here value = cnt(s_, d), the result of the call of the cnt function.
This cannot work, since setInterval expects a function. Too bad it silently fails in javascript.
In the second attempt, the issue is that you modify only function var, so no change can occur : you change deg, deg2, when in fact you would like to change s_ and d.
The third attempt is right, since you both invoke a function and change the globals s_ and d.
I would rather write it this way :
var rek_inter = setInterval( iterate , 1000);
function iterate () {
s_--;
while (s_ < 0) {
s_ = 59;
d--;
}
if (d < 0) {
$('#s_').html("ok");
} else if (d >= 0) {
var d_sn = fixd(d);
var s_sn = fixd(s_);
$('#s_').html(d_sn + ":" + s_sn);
}
}
Edit :
The O.P. mentionned that he wants to handle a set of (s_, d ) parameters.
I suggest you create an array of object which contains such parameters :
var sdParameters = [];
sdParameters.push( { s : some value , d: some other value} );
sdParameters.push( { s : some value 2, d: some other value 2 } );
... // (or using a for loop to grab the ds and ss if possible)
Then after each s/d object is defined by its index, so with :
function iterate (ind) {
var s_ = --sdParameters[ind].s ;
while (s_ < 0) {
s_ = 59;
sdParameters[ind].d--;
}
var d = sdParameters[ind].d;
if (d < 0) {
$('#s_').html("ok");
} else if (d >= 0) {
var d_sn = fixd(d);
var s_sn = fixd(s_);
$('#s_').html(d_sn + ":" + s_sn);
}
}
you can have all your intervals running on one single global array with :
var rek_inter = setInterval( iterate.bind(null,0) , 1000);
var rek_inter1 = setInterval( iterate.bind(null,1) , 1000);
(obviously you can/should store the intervals in an array, you might store them within sdParameters.
One last remark : i couldn't use relevant variable names, since i couldn't guess the use. Using significant names in your code can be of great help when things gets more complex.
Related
I have four screens that I want to display in the following order.
Screen1(2 seconds) -> Screen2 (2 seconds) -> Screen3 (2 Seconds)
I also have a fourth screen which should only show when the time is between 05:55-06:05 and 17:55-18:05
In order to accomplish this my code looks like this till now:
function timecondition() {
var hours = new Date();
var minutes = new Date();
var h = hours.getHours();
var m = minutes.getMinutes();
var timecondition;
if((h == 5 && m >= 55) || (h == 6 && m <= 5) || (h == 17 && m >= 55) || (h == 18 && m <= 5)) {
timecondition = true;
}
else {
timecondition = false;
}
return timecondition;
}
$(document).ready(
function() {
setInterval(function() {
setTimeout(function() {
if(timecondition()) {
$('#show').load("http://localhost:8084/test/screen4");
}
else {
$('#show').load("http://localhost:8084/test/screen1");
}
}, 2000);
setTimeout(function() {
if(timecondition()) {
$('#show').load("http://localhost:8084/test/screen4");
}
else {
$('#show').load("http://localhost:8084/test/screen2");
}
}, 4000);
setTimeout(function() {
if(timecondition()) {
$('#show').load("http://localhost:8084/test/screen4");
}
else {
$('#show').load("http://localhost:8084/test/screen3");
}
}, 6000);
}, 6000);
}
);
Unfortunately it doesnt work like I want it to be.
When I start the webapplication at 05:54 the sequence(screen1->screen2->screen3)
But once the clock hits 05:55 it won't display the fourth screen, like it was in my intention.
When I start the application within the timecondition eg. at 05:56 it shows the fourth screen, but won't leave screen4 when the timecondition is not true anymore a few minutes later.
Is it because I need dynamic functions?
Couple of potential bugs there.
1. You are taking the time twice
Every time you call new Date() you are taking a snapshot of an instant. In this case they are only milliseconds away from each other, but it's a bug nonetheless.
var hours = new Date();
var minutes = new Date();
One object should be enough:
var now = new Date();
var h = now.getHours();
var m = now.getMinutes()
2. Your time condition is wrong
var timecondition;
if((h == 5 || h == 6 || h == 17 || h == 18) && (m >= 55 || m <= 05)) {
timecondition = true;
}
else {
timecondition = false;
}
return timecondition;
There is two problems with this:
a) It is hiding the function name from within. This is just a minor bug and doesn't affect the functionality here yet.
b) You are checking for hours and minutes independently. This IS a serious bug because it doesn't comply with your business logic.
That whole code above can be smarter rewritten as:
h = h % 12
return (h == 5 && m >= 55) || (h == 6 && m <= 5)
3. You reload the page every few seconds
The second argument to setInterval and setTimeout respectively is in milliseconds. So you are issuing a load every 2 seconds.
4. You are nesting timeouts within intervals
This basically means that every six seconds you are setting a timer for the next 2, 4 and 6 seconds. This is not really a bug, but unnecessarily complex. Why not set one interval for running every two seconds?
Here's some refactored and hopefully fixed code. Didn't try it out yet, though.
function slideshow() {
var screens = [
"http://localhost:8084/test/screen1",
"http://localhost:8084/test/screen2",
"http://localhost:8084/test/screen3"
];
var specialScreen = "http://localhost:8084/test/screen4";
// Contains the index of currently shown screen or -1
// when the special screen is shown
var currentScreen = 0;
// Cache the element here so we don't need to search for it every two seconds
var show = $('#show');
function timecondition() {
var now = new Date();
var h = now.getHours();
var m = now.getMinutes();
h = h % 12;
return (h == 5 && m >= 55) || (h == 6 && m <= 5);
}
function update() {
if (timecondition()) {
if (currentScreen != -1) {
show.load(specialScreen);
currentScreen = -1;
}
return;
}
currentScreen = (currentScreen + 1) % screens.length;
show.load(screens[currentScreen]);
}
setInterval(update, 2000);
}
$(document).ready(slideshow);
If you wanted different durations for the screens, you could do it roughly like this:
function slideshow() {
var screens = [
{url: "http://localhost:8084/test/screen1", t: 2000},
{url: "http://localhost:8084/test/screen2", t: 3000},
{url: "http://localhost:8084/test/screen3", t: 10000}
];
var specialScreen = "http://localhost:8084/test/screen4";
// Contains the index of currently shown screen or -1
// when the special screen is shown
var currentScreen = 0;
// Cache the element here so we don't need to search for it every two seconds
var show = $('#show');
function timecondition() {
var now = new Date();
var h = now.getHours();
var m = now.getMinutes();
h = h % 12;
return (h == 5 && m >= 55) || (h == 6 && m <= 5);
}
var step = 1000;
var screenTimer = 0;
function update() {
if (timecondition()) {
if (currentScreen != -1) {
show.load(specialScreen);
currentScreen = -1;
}
return;
}
if ((screenTimer += step) >= screeens[currentScreen].t) {
currentScreen = (currentScreen + 1) % screens.length;
show.load(screens[currentScreen].url);
screenTimer = 0;
}
}
setInterval(update, step);
}
$(document).ready(slideshow);
I have an array with 3 types of values in which I wish to sort them.
If I only use one variable it goes all pretty well, but it all goes wrong when i want to use 3 types of variables to determine sorting order.
First variable condition: if obj.sortorder == 999999 send it to the end of the line(there is only one of this one);
if not true then
if (date < other date) put it in front of the one before
if(date > other date) put it behind the other one
if dates are equal look to sortorder to determine the order in which to apppear.
Then loop over array, reset all sortorder variables to be properly ascending in the new order.
Then splice in a new value(15th), but then it doesn't appear next to the other one, even though they have duplicate values.
My head hurts from trying to figure this one out, I just can't seem to get them in the right order.
Basically the way they are created here they should come out in the first sort. But yet the first sort is messed up with values all over the place except where I want them.
The second sort puts them miraculously in the right order but puts the 16 between the two fifteens whilst the fifteens should be next to eachother. and somehow the 24th ends up as the 9999 after the reassignment whilst the 29th should have remained as the last one.
Who can help me with this?
If you press run code snippet you get the garbled output I currently get.
The first set is what all the others should look like, except for the last one where the 15's should be hugging eachother.f
elements = [];
for (var c = 0; c < 30; c++) {
elements[c] = {
sortorder: c,
getDate: function () {
return new Date(2015, 06, this.sortorder)
}
};
}
function log(what) {
var elem = document.getElementById('sortorder');
elem.appendChild(document.createTextNode(what + "\n"));
}
for (c = 1; c < elements.length; c++) {
log(c + " = " + elements[c].getDate() + " - " + elements[c].sortorder)
}
log('--------------------------------');
elements[elements.length - 1].sortorder = 9999999;
this.elements.sort(function (one, two) {
/**
* Failsafe to prevent the last element to be placed in the middle
*/
if (one.sortorder >= 9999998) {
return 1;
}
if (two.sortorder >= 9999998) {
return -1;
}
if (one.getDate() < two.getDate()) {
return -1
}
if (two.getDate() > one.getDate()) {
return 1;
}
if (one.sortorder < two.sortorder) {
return -1;
}
if (one.sortOrder > two.sortorder) {
return 1;
}
return 0;
});
function log(what) {
var elem = document.getElementById('sortorder');
elem.appendChild(document.createTextNode(what + "\n"));
}
for (c = 1; c < elements.length; c++) {
log(c + " = " + elements[c].getDate() + " - " + elements[c].sortorder)
}
log('--------------------------------------------------------------');
elements.splice(17, 0, {
sortorder: 15,
getDate: function () {
return new Date(2015, 06, 15)
}
});
for (var c = 1; c < this.elements.length; c++) {
if (c < this.elements.length - 1) {
this.elements[c].sortorder = c;
} else {
this.elements[c].sortorder = 9999999;
}
}
for (c = 1; c < elements.length; c++) {
log(c + " = " + elements[c].getDate() + " - " + elements[c].sortorder)
}
<pre id="sortorder">
</pre>
After some experimenting, fiddling, swearing, googling, the normal process in a situation like this I finally got the solution.
I guess I was overthinking things once again.
Thanks for helping out and thinking along.
elements.sort(function(one,two)
{
var ret = 0;
/**
* Failsafe to prevent the last element to be placed in the middle
*/
if(one.sortorder >= 9999998) {
ret = 1;
}
else {
if(two.sortorder >= 9999998) {
ret = -1;
}
else {
if(one.getDate() - two.getDate() !== 0) {
ret = one.getDate() - two.getDate();
}
else {
ret = one.sortorder - two.sortorder;
}
}
}
console.log(ret);
return ret;
});
Not quite sure what you mean by "Then splice in a new value(15th), but then it doesn't appear next to the other one, even though they have duplicate values."
This does everything but that.
var last;
var newArray = [];
for(var obj in array){
obj = array[obj];
if(obj.sortorder === 999999)
last = obj;
else {
for(var item in newArray){
if(obj.date.getTime() < newArray[item].date.getTime()){
newArray.splice(item, 0, obj);
break;
}
if(obj.date.getTime() === newArray[item].date.getTime()){
if(obj.sortorder > newArray[item].sortorder){
newArray.splice(item, 0, obj);
break;
}
else{
newArray.splice(item + 1, 0, obj);
break;
}
}
}
}
}
newArray.push(last);
var sortorder = 1;
for(var item in newArray){
if(newArray[item].date.getTime() > newArray[item - 1].date.getTime())
newArray[item].sortorder = ++sortorder;
}
I tried to rewrite this indexOf MDN example to practice recursion
var str = 'To be, or not to be, that is the question.';
var count = 0;
var pos = str.indexOf('e');
while (pos !== -1) {
count++;
pos = str.indexOf('e', pos + 1);
}
console.log(count); // displays 4
This was my solution:
var count = 0;
function countLetters(str, p) {
var pos = str.indexOf(p);
if (pos == -1) {
return count;
}
else {
count ++;
return countLetters(str.substr(pos + 1), p)
}
}
console.log(countLetters('To be, or not to be, that is the question.', 'e'));
It works, but is there anyway to get the count variable inside the function itself? Is it not really a true recursion if I have a count variable outside the function?
In a recursive function, if you want to keep a variable around from one "iteration" to the next, then you need to pass it as an argument:
function countLetters(str, p, count) {
count = count || 0;
var pos = str.indexOf(p);
if (pos == -1) {
return count;
}
else {
return countLetters(str.substr(pos + 1), p, count + 1);
}
}
console.log(countLetters('To be, or not to be, that is the question.', 'e'));
// => 4
However, this is not always necessary, as Arun P Johny's answer illustrates.
What you can do is to return the count value form the method, so if the item is not found you return 0, else you return 1 + value-of-recursive-call
function countLetters(str, p) {
var pos = str.indexOf(p);
if (pos == -1) {
return 0;
} else {
return 1 + countLetters(str.substr(pos + 1), p)
}
}
console.log(countLetters('To be, or not to be, that is the question.', 'e'));
Demo: Fiddle
I need to create a function or use if is possible an already made library to auto increment an index. For example if it starts with 'A' it has to be incremented to 'Z' and after 'Z' it has to start from 'A1' and as soon as . . .'B1','C1', ... 'Z1', 'A2','B2',... . Does exist something like this already made ?
My idea is this, but start from 'A' and don't add number . . .
function nextChar(cont,letter) {
if (cont === 0){return letter;}
else {
letter=letter.charCodeAt(0) + 1;
return String.fromCharCode(letter);
}
}
One of many options:
function nextIndex(idx) {
var m = idx.match(/^([A-Z])(\d*)$/)
if(!m)
return 'A';
if(m[1] == 'Z')
return 'A' + (Number(m[2] || 0) + 1);
return String.fromCharCode(m[1].charCodeAt(0) + 1) + m[2];
}
var a = "";
for(i = 0; i < 100; i++) {
a = nextIndex(a)
document.write(a + ", ")
}
This one's less efficient than georg's but maybe easier to understand at first glance:
for (var count = 0, countlen = 5; count < countlen; count++) {
for (var i = 65, l = i + 26; i < l; i++) {
console.log(String.fromCharCode(i) + (count !== 0 ? count : ''));
}
}
DEMO
Allow me to propose a solution more object-oriented:
function Index(start_with) {
this.reset = function(reset_to) {
reset_to = reset_to || 'A';
this.i = reset_to.length > 1 ? reset_to[1] : 0; // needs more input checking
this.c = reset_to[0].toUpperCase(); // needs more input checking
return this;
};
this.inc = function(steps) {
steps = steps || 1;
while(steps--) {
if (this.c === 'Z') {
this.i++;
this.c = 'A';
} else {
this.c = String.fromCharCode(this.c.charCodeAt(0) + 1);
}
}
return this;
};
this.toString = function() {
if (this.i === 0) return this.c;
return this.c + '' + this.i;
};
this.reset(start_with);
}
var a = new Index(); // A
console.log('a = ' + a.inc(24).inc().inc()); // Y, Z, A1
var b = new Index('B8'); // B8
console.log('a = ' + a.reset('Y').inc()); // Y, Z
console.log('b = ' + b); // B8
Another way to think about this is that your "A1" index is just the custom rendering of an integer: 0='A',1='B',26='A1',etc.
So you can also overload the Number object to render your index. The big bonus is that all the math operations still work since your are always dealing with numbers:
Number.prototype.asIndex = function() {
var n = this;
var i = Math.floor(n / 26);
var c = String.fromCharCode('A'.charCodeAt(0) + n % 26);
return '' + c + (i ? i : '');
}
Number.parseIndex = function(index) {
var m;
if (!index) return 0;
m = index.toUpperCase().match(/^([A-Z])(\d*)$/);
if (!m || !m[1]) return 0;
return Number((m[1].charCodeAt(0) - 'A'.charCodeAt(0)) + 26 * (m[2] ? m[2] : 0));
};
var c = 52;
var ic = c.asIndex();
var nc = Number.parseIndex(ic);
console.log(c+' = '+ic+' = '+nc); // 52 = A2 = 52
If you go this way I would try to check if the new methods don't already exist first...
I have a found a number of solutions on here for a counter, animating from one total to another.
Here's my what I'm using now:
jQuery.fn.extend({
ts : function (from, to, time) {
var steps = 1,
self = this,
counter;
if (from - to > 0) {
steps = -1;
};
from -= steps;
function step() {
self.text(from += steps);
if ((steps < 0 && to >= from) || (steps > 0 && from >= to)) {
clearInterval(counter);
};
};
counter = setInterval(step, time || 5);
}
});
var total = $('.total').ts(56000,56941);
It works well. However, I would like to add a comma to the total, something like 56,941. Is this possible?
I guess this will do it:
jQuery.fn.extend({
ts: function(from, to, time) {
var steps = 1, self = this, counter;
if (from - to > 0) steps = -1;
from -= steps;
function step() {
var x = (from += steps).toString().replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,");
self.text(x);
if ((steps < 0 && to >= from) || (steps > 0 && from >= to)) {
clearInterval(counter);
};
};
counter = setInterval(step, time || 5);
}
});
FIDDLE
From somewhere on the web...
function formatComma(x){
return (x+'').replace( /\B(?=(\d{3})+(?!\d))/g, ',');
}
I like my own solution of reversing the string better as it is easier to understand the logic...
function formatComma(x){
// prepare the input as a string ready for manipulating and returning
return (x+'')
// reverse the string (by converting to array)
.split("").reverse().join("")
// replace 3 digits in a row, with themselves and a comma
// so long as the digits are followed by a non-word boundary
.replace(/(\d{3})\B/g,'$1,')
// reverse it all again
.split("").reverse().join("")
}
This will work. The function is taken from http://ntt.cc/2008/04/25/6-very-basic-but-very-useful-javascript-number-format-functions-for-web-developers.html. Very handy
jQuery.fn.extend({
ts : function (from, to, time) {
var steps = 1,
self = this,
counter;
if (from - to > 0) {
steps = -1;
};
from -= steps;
function step() {
self.text(addCommas(from += steps));
if ((steps < 0 && to >= from) || (steps > 0 && from >= to)) {
clearInterval(counter);
};
};
counter = setInterval(step, time || 5);
}
});
var total = $('.total').ts(56000,56941);
function addCommas(nStr)
{
nStr += '';
x = nStr.split('.');
x1 = x[0];
x2 = x.length > 1 ? '.' + x[1] : '';
var rgx = /(\d+)(\d{3})/;
while (rgx.test(x1)) {
x1 = x1.replace(rgx, '$1' + ',' + '$2');
}
return x1 + x2;
}
Sure it is! You can check this plugin (http://code.google.com/p/jquery-numberformatter/) and implement it in yours :-)