Below is the functions I use to run a function periodically. I use the function to change the background of the body. but it doesn't get fired for some reason. Please help me with this code.
setInterval(uiImageChanger(),1);
function uiImageChanger(){
var currentTime = new Date().getHours();
var images = ['image1.jpg','image2.jpg'];
if( currentTime > 00 && currentTime <= 12){
$('body').css('background-image', "url(" + randomImagePicker(images ,'breakfast') + ")");
}else if( currentTime > 12 && currentTime <= 16){
$('body').css('background-image', "url(" + randomImagePicker(images ,'lunch') + ")");
}else if( currentTime > 16 && currentTime <= 00){
$('body').css('background-image', "url(" + randomImagePicker(images ,'dinner') + ")");
}
}
function randomImagePicker(imgArray,time){
if(time == 'breakfast'){
return "../images/main_image/breakfast/" + imgArray[Math.floor(Math.random() * imgArray.length)];
}else if(time == 'lunch'){
return "../images/main_image/lunch/" + imgArray[Math.floor(Math.random() * imgArray.length)];
}else if(time == 'dinner'){
return "../images/main_image/dinner/" + imgArray[Math.floor(Math.random() * imgArray.length)];
}
}
Thank you.
Remove parens from the setInterval function argument. Now, this will invoke the function and set the return value of the function as the reference to setInterval which here is undefined as you don't return anything. So basically you are setting interval on nothing, so nothing happens except the first execution while setting up the setInterval.
Change
setInterval(uiImageChanger(),1); // This will invoke the function immediately.
to
setInterval(uiImageChanger,1); // You want to set the reference of the function to setInterval.
You have to pass a pointer to a function and not execute the function.
setInterval(uiImageChanger,1);
There are multiple ways of defining the function to be executed using setInterval.
One of the method is using the function reference for which the example is given by #mohkhan.
However you can do the following as well
setInterval(function(){
// code comes here.
}, time_in_mills);
Also I see that you have mentioned the value for the function execution as 1. This means every 1 millisecond the function will be executed, which is not a good practice at all. Give a realistic time in millisecond so that you have given sufficient time for the code to execute.
You've gotten several answers about the setInterval() problem. I'd like to point out a couple of other problems in the code.
First, this test will always fail:
else if( currentTime > 16 && currentTime <= 00)
After all, if a number is > 16 it cannot also be <= 0.
Also, you may get a warning about 00 being an octal constant which is deprecated. Of course, octal zero is the same value as decimal zero, but watch out for inadvertent octal constants: avoid using a leading zero.
And there is a lot of repetition in the code. You can easily remove all of this repetition to make the code more maintainable. Consider this approach:
// Return a random integer >= 0 and < n
function randomInt( n ) {
return Math.floor( Math.random() * n );
}
// Return a random element from an array
function randomElement( array ) {
return array[ randomInt(array.length) ];
}
function uiImageChanger(){
var hour = new Date().getHours();
var meal =
hour <= 12 ? 'breakfast' :
hour <= 16 ? 'lunch' :
'dinner';
var images = [ 'image1.jpg', 'image2.jpg' ];
$('body').css(
'background-image',
'url(../images/main_image/' + meal +
'/' + randomElement(images) + ')'
);
}
Related
I am looking to increment the value of "time" with 0.01 each 10 miliseconds until it gets to the desired value. Right now it just increases it instantly to the conditioned value.
var time = 0;
function animate() {
decreaseIncrement = -0.78;
increaseIncrement = 0.78;
if (
(document.getElementById("but5").onclick = function () {
if (time < increaseIncrement) {
do {
time += 0.01;
} while (time < increaseIncrement);
}
})
)
if (
(document.getElementById("but3").onclick = function () {
if (decreaseIncrement < time) {
do {
time -= 0.01;
} while (decreaseIncrement < time);
}
})
)
increaseIncrement = time + increaseIncrement;
decreaseIncrement = time + decreaseIncrement;
}
https://jsfiddle.net/2epqg1wc/1/
You can solve that problem using setInterval which repeatedly runs a task every x milliseconds until you cancel it. Below code reduces the value to 0 in 0.01 steps with a step performed every 10 milliseconds.
var value = 1.0;
var decrement = 0.01;
function decreaseAnimation() {
var interval = setInterval(() => {
value -= decrement;
console.log(value);
if (value <= 0) {
clearInterval(interval);
}
}, 10);
}
decreaseAnimation();
You have 3 options:
requestAnimationFrame (rAF)
setTimeout/setInterval (sTo)
messageChannel
The first 2 options are more straightforward but they will lack the precision, because rAF fires every 17 milliseconds (assuming 60Hz) and sTO will fire at most 4ms after 4 successive recursions. Usually rAF is preferred over sTo because of better reliability in timing of firing these callbacks. Use sTO as a fallback if rAF is not supported.
Here is an implementation from a library for similar purposes:
var rafx = require("rafx");
rafx.async({ //create a ledger object to store values
curr_time:0,
desired:Math.random(),
frames:0
}).animate(function(obj){
//obj is the ledger above
//increment obj.frames here if you want to
return obj;
},).until(function(obj){
obj.frames++;
obj.curr_time = obj.frames * 17 / 10 * 0.01;
return obj.curr_time >= obj.desired;
}).then(function(obj){
console.log("sequence ended with values:" + JSON.stringify(obj));
});
You can copy paste the code above here and test it.
The last option uses MessageChannel to post message between ports, which gives extremely high precision because it is fired at the next event loop. You can combine this with performance.now to determine whether to increment your time or not.
Disclosure: I am the author of the aforementioned lib.
I am trying to get my countdown to stop at zero however it resets rather than stops.
I've added a conditional statement at the end of the runTimer function but nothing happens. It just resets.
I'm going off of an exercise where it counts up. I'm modifying it a bit and having it countdown.
function runTimer() {
let currentTime = leadingZero(timer[1]) + ":" + leadingZero(timer[2]);
theTimer.innerHTML = currentTime;
timer[3]--;
timer[0] = Math.floor((timer[3]/100)/60); //minutes
timer[1] = Math.floor((timer[3]/100) - (timer[0] * 60)); //seconds
timer[2] = Math.floor(timer[3] - (timer[1] * 100) - (timer[0] * 6000)); //hundredths
if (currentTime = 0) {
clearInterval(interval);
}
}
I expected it to stop at zero but it just resets back to 59:00... and I want it to stop at 00:00.
The problem is this part:
if (currentTime = 0)
Since you're checking if the value is 0, you don't want to assign a value of 0, instead you want to compare currentTime with 0. This is done with the === operator. So to summarize:
= is to assign a value to a variable. ( left is variable and right is the assignment)
== or === is to compare the two values.(Difference between == and === in JavaScript)
Your line should be:
if (currentTime == 0)
Hope it helped. :)
Two points.
1) As already mentioned, your if clause will not work because you are using "=" (a single equal sign). A single equal sign in JavaScript does assign values, not compare values. You however want to compare values and need to use double or triple equals.
2) Even if you change that, currentTime will probably never evaluate to zero, since you have assigned a string to currentTime before. So even if currentTime is "00:00", the string will not evaluate to 0 (see image)
I guess you more want to do something like this:
if (timer[2] === 0 && timer [1] === 0 && timer[0] === 0) {
clearInterval(interval);
}
Or most probably this will suffice:
if (timer[3] <= 0) {
clearInterval(interval);
}
I have a long loop that takes maybe 10 mins or more, and I want to set always a new time to avoid it to continue. But it dosen't works.
function problem3(){
var img = document.getElementById('p_3');
img.style.display = img.style.display === 'block' ? 'none' : 'block';
var number=600851475143;
var t = new Date();
for(var i=3;i*i<=number;i+=2){
if(isPrime(i) && number%i==0){
var maxPrime = i;
}
setInterval(function(){time(t)},5000);
}
document.getElementById("p3").innerHTML = 'Il più grande divisiore primo di <span>'+number+"</span> è <span>" + maxPrime+"</span>";
}
function time(t){
return console.log(Date() - t);
}
If I put console.log(Date() - t);in the problem3() function it works, but I can't do Date()-t every 5 seconds, something like setInterval(Date()-t,5000)
This is a case where you might consider using the workers API. Instead of freezing the browser, let the job be done in the background and call back to the main thread when it's done.
https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API
JavaScript is not multithreaded. So we think of setInterval() as running a piece of code every n ms (5000 in your example). But that's not quite true. If there's already script running when the interval elapses, the best that can happen is the bit of code gets added to a queue to be executed - but nothing from that queue is going to run until the already-running script finishes.
So in rough terms that's why it's not working, but what to do? Well, if you want anything to happen before problem3() returns, then problem3() is going to have to make it happen in a synchronous way.
For example, you could create a lastOutputTime variable, initialize it to the current time, and on each iteration through the for loop compare the current time to the stored value. If 5 seconds have passed, output to console and update lastOutputTime.
Your algorithm should be improved to something like this:
function maxPrimeFactor(number) {
if (number == 0 || !Number.isInteger(number) ||
number > Number.MAX_SAFE_INTEGER) return NaN;
number = Math.abs(number);
while(number % 2 == 0) number /= 2;
for (var i = 3; i * i <= number; i += 2) {
while(number % i == 0) number /= i;
}
return number;
}
var number = 600851475143;
console.log('maxPrimeFactor(' + number + ') == ' + maxPrimeFactor(number));
If for some numbers you need too much time, then break the loop into smaller chunks and asynchronize. But never use setInterval for this, and especially never use setInterval inside a long loop. setInterval schedules some task to run every n milliseconds, so if you use it in a loop, after i iterations, the task will run i every n milliseconds! And setInterval is so problematic because it can freeze the browser if the task takes more than n milliseconds. You should use setTimeout instead.
However, this would be useless in this case. The algorithm above can detect that 304250263527209 (15 digits) is a prime almost instantly. Given that the maximum safe integer is 9007199254740991 (16 digits), I don't think you will have problems for any number.
If you say the algorithm takes so long, it may be because you are trying it with bigger numbers. But be aware JS numbers are 64-bit floating point numbers, and thus integers can't be represented accurately above Number.MAX_SAFE_INTEGER. You will get a wrong result anyways, so do not even try to calculate that.
In the case of the Project Euler #551, a brute-force approach would be
function sumOfDigits(n) {
var sum = 0;
while(n != 0) {
sum += n % 10;
n = Math.floor(n/10);
}
return sum;
}
function sumDigitsSeq(n) {
return new Promise(function(resolve) {
var i = 1;
var chunkSize = 1e5;
var sum = 1;
(function chunk() {
chunkSize = Math.min(chunkSize, n-i);
for (var j=0; j<chunkSize; ++j, ++i) {
sum += sumOfDigits(sum);
}
if (i >= n) return resolve(sum);
console.log('Please wait. sumDigitsSeq(' + i + ') == ' + sum);
setTimeout(chunk, 60);
})();
});
}
var number = 1e6;
sumDigitsSeq(number).then(function(result) {
console.log('Done! sumDigitsSeq(' + number + ') == ' + result);
});
Of course brute-force is not the appropriate way to solve the problem.
This is probably basic math that I don't seem to remember.
I'm trying to get from 0 to 5,000,000 in 10 seconds while having all the numbers ticking. I don't have to have the number reach exactly 5,000,000 because I can just do a conditional for it to stop when it's over.
Right now I have this:
count+= 123456
if (count > 5000000) {
count = 5000000;
}
It gives the sense of number moving you know? But It really starts off too high. I wanted to gradually climb up.
You could do something like this:
function timedCounter(finalValue, seconds, callback){
var startTime = (new Date).getTime();
var milliseconds = seconds*1000;
(function update(){
var currentTime = (new Date).getTime();
var value = finalValue*(currentTime - startTime)/milliseconds;
if(value >= finalValue)
value = finalValue;
else
setTimeout(update, 0);
callback && callback(value);
})();
}
timedCounter(5000000, 10, function(value){
// Do something with value
});
Demo
Note that with a number as big as 5000000 you won't see the last couple digits change. You would only see that with a small number like 5000. You could fix that; perhaps by adding in some randomness:
value += Math.floor(Math.random()*(finalValue/10000 + 1));
Demo with randomness
You can tween:
import fl.transitions.Tween;
import fl.transitions.easing.Regular;
var count = 0;
var tween:Tween = new Tween(this, "count", Regular.easeInOut,0,5000000,10, true);
This will tween you variable count from 0 to 5000000 in 10 seconds. Read about these classes if you want to expand on this code.
Tween
TweenEvent
Good luck!
How would you program this more efficiently?
if( randomYear%4==0 ) {
if( randomYear%100==0 ) {
if( randomYear%400==0 ) {
randomDay = 1 + Math.floor(Math.random()*29);
}
else {
randomDay = 1 + Math.floor(Math.random()*28);
}
else{
randomDay = 1 + Math.floor(Math.random()*29);
}
else{
randomDay = 1 + Math.floor(Math.random()*28);
}
First off, i''m using math.floor because it includes 0 and excludes 1, which is what i'm looking for. The purpose of this is to determine if the variable 'randomYear' is a leap year and have the appropriate days in February.
I'm mainly concerned about all the if and else statements. BTW, i'm using Javascript.
Thank YOU SO much!!
You don't even need the math:
var tmp = new Date(year,1,29); // attempt to get February 29th
isleapyear = (tmp.getMonth() == 1);
How about this?
var maxDays = 28;
if (randomYear%4 == 0 && (randomYear%100 != 0 || randomYear%400 == 0)) {
maxDays = 29;
}
randomDay = 1 + Math.floor(Math.random() * maxDays);
If you are ok with including a third party library, try this library:
http://momentjs.com/
And you can just do:
moment([2000]).isLeapYear()
to check if 2000 is a leap year and then you can do appropriate logic. Also you can check if 29th of Feb of a certain year exists or not using its validation api.
You can do it as given below.
function isLeapYear(year){
return !(year%400) || ((year%100 > 0) && !(year%4)) ;
}
function getRandomDay(year){
return 1 + Math.floor(Math.random()* (isLeapYear(year)?29:28))
}
var day = getRandomDay(2000);
Performance wise it might not make big changes. But this is the way to write organized re-usable code in less number of lines.