Variable doesn't influence speed of setInterval loop - javascript

I want the speed of my loop to be influenced by a variable (x). This will influence how fast a value (t) is increased, when a button is clicked. I wrote my code, and it should work but it doesn't. Help.
var timeCounter = document.getElementById("time");
var x;
var t;
function timeOnLoad(){
time = 0;
x = 1000;
}
setInterval(function(){
t++;
timeCounter.innerHTML = t;
},x)
function changeSpeed(){
x = 2000;
}
function valueSpeed(){
alert(x);
}
body{
background-color:white;
}
<div onload="timeOnLoad()" id="time"></div>
<button onclick="changeSpeed()">Change x by 1 sec</button>
<button onclick="valueSpeed()">Get value of x</button>

That happens because interval uses x variable only on initialization. It's not dynamic. You have to stop the timer and reinstantiate it in order for it to work. Here's an example:
var timeCounter = document.getElementById("time");
var t = 0, x = 1000, interval;
function changeSpeed(){
x = x + 1000;
restartInterval();
}
function valueSpeed(){
alert(x);
}
function restartInterval() {
clearInterval(interval);
interval = setInterval(function(){
t++;
timeCounter.innerHTML = t;
}, x);
}
restartInterval();
body{
background-color:white;
}
<div id="time"></div>
<button onclick="changeSpeed()">Change x by 1 sec</button>
<button onclick="valueSpeed()">Get value of x</button>
Also, div doesn't have an onLoad event. You have to put this code elsewhere.

You need to cancel and re-instantiate the setInterval when you want to update it. The value set is not dynamic and once it is set it remains at that value.
var timeCounter = document.getElementById("time");
var x = 1;
var t = 0;
function timeOnLoad(){
time = 0;
x = 1000;
}
// Create a function to init the timer. Additionally, create a var to track the actual timeout.
var timer = null;
function setTimer() {
console.log("Setting time to: " + x);
timer = setInterval(function(){
t++;
timeCounter.innerHTML = t;
},x);
}
// Clear the timeout and update the value. Then call your timeout again.
function changeSpeed(){
clearTimeout(timer);
x = Math.floor(Math.random() * 5000);
setTimer();
}
function valueSpeed(){
alert(x);
}
setTimer();
<p id="time"></p>
<button id="updatetime" onclick="changeSpeed()">Cickme</button>
So basically what I did above was create an actual variable to track the timeout obj and then create a function to call it.
Next, inside of your changeSpeed function, clear the timeout to stop it from running and then set your new value. Finally call your setTimer again to restart it with the new value.
I made the x value a random number so you could more easily see the change multiple times.

Related

How do I make a number decrease by 5 every 20 seconds, and then display this number live?

How do I make a number (var is f) decrease by 5 every 20 seconds, and then display this number live? I am making a Hunger Games simulator to play live with my friends, and I want each tributes hunger to display live for them (all on separate devices). I want the hunger to decrease by 5 every 20 seconds. This is what I have tried:
<h1>Hunger Games Tribute Status:</h1>
<button onclick="startgame()">START GAME</button>
<h5 id="hunger"></h5>
</body>
function startgame(){
var f = 200;
var intervalID = window.setInterval (foodcountdown(), 20000);
document.getElementById("hunger".innerHTML = f; }
function foodcountdown() {
var x=f-5;
var f=x; }
If you want to share you f variable, you should put it in the global scope
var f = 200; //moved
function startgame(){
var intervalID = window.setInterval (foodcountdown(), 20000);
document.getElementById("hunger").innerHTML = f; //corrected
}
function foodcountdown() {
f=f-5; //corrected
document.getElementById("hunger").innerHTML = f; //added
}
setinterval(foodcountdown, 20000); - There should not be (), you need to pass the function to the interval to let it execute it, not execute it yourself
getElementById('hunger').innerHTML - You need a . in front of innerHTML, not a ; as you currently have
By using the keyword var in var f = ... inside your foodcountdown function, you are creating a local variable, and thus not affecting the one you want, declared in startGame. f needs to be accessible by both functions, make it global, or at least in the same upper scope
Your intervalID also needs to be accessible if you ever want to clear it
You're displaying the food count at the start of the game, but never again
Here is a fixed demo:
var f, intervalID;
function startgame() {
f = 200; // Allows you to restart a game from the start
clearInterval(intervalID); // In case a game was already started
intervalID = setInterval(foodcountdown, 200); // changed to 200ms for the demo
displayFoodCount();
}
function foodcountdown() {
f -= 5;
displayFoodCount();
if (f <= 0) {
clearInterval(intervalID);
console.log('Game over!');
}
}
function displayFoodCount() {
document.getElementById("hunger").innerHTML = f;
}
<h1>Hunger Games Tribute Status:</h1>
<button onclick="startgame()">START GAME</button>
<h5 id="hunger"></h5>
You should declare f as a global variable, outside the functions.
You should update the HTML element every time you decrease the value.
You should pass the function to setInterval, and not the result of the function.
You have a ; before innerHTML instead of ..
So (I decreased the interval for the sample):
var f, intervalID;
function startgame() {
f = 200;
intervalID = window.setInterval(foodcountdown, 2000);
}
function foodcountdown() {
f = f - 5;
document.getElementById("hunger").innerHTML = f;
}
<h1>Hunger Games Tribute Status:</h1>
<button onclick="startgame()">START GAME</button>
<h5 id="hunger"></h5>
Here is working example. Move your variables and DOM Selections to the the top. And also you can use innerText instead of innerHTML if you don't going to insert HTML.
const hunger = document.getElementById("hunger");
const f = 200;
hunger.innerText = f;
function foodCountDown() {
setInterval(function() {
f -= 5
hunger.innerText = f
}, 20000)
}
The main problem is that you are invoking your foodcountdown function instead of passing it in. Also you need to make sure that the startgame function is called when the DOM is loaded (maybe call it in the onload of the body).
var f = 200;
var interval;
function startgame() {
interval = setInterval(foodcountdown, 20000);
}
function foodcountdown() {
console.log(f);
if (f <= 0) {
clearInterval(interval);
}
document.getElementById("hunger").innerHTML = f;
f -= 5;
}
<!DOCTYPE html>
<html>
<script src="main.js"></script>
<body onload="startgame()">
<div id="hunger"></div>
</body>
</html>
Move the bulk of the logic inside the setInterval function and make sure to return the function if the timer reaches 0:
function startgame() {
let f = 200;
document.getElementById("hunger").innerHTML = f;
const intervalID = window.setInterval(() => {
if (f === 0) return;
f -= 5;
document.getElementById("hunger").innerHTML = f;
}, 500);
}
<h1>Hunger Games Tribute Status:</h1>
<button onclick="startgame()">START GAME</button>
<h5 id="hunger"></h5>
(Shortened the time for demonstration.)

How do I loop this function?

I am using Odometer to show an animated counter:
setTimeout(function (){
$('.odometer').html(8567);
}, 1000);
</script>
<script>
window.odometerOptions = {
duration: 3000
};
I would like the counter to start over at the value I've defined in my html (which is 1000) and then count back up to 8567 and repeat indefinitely. I've tried:
$(document).ready(function () {
function loop(){
setTimeout(function (){
$('.odometer').html(8567);},1000,loop);
loop();
});
But it breaks the counter. I'm assuming I can't mix the setTimeout while defining the loop, but don't know what else to try. The 1000 in the setTimeout function is just a coincidence and is the delay to start the function after page load.
If you want to repeatedly call a function over time like this you should use setInterval not setTimeout.
You need to keep track of the current value of the loop, yours right now is setting the counter to 8567 every time.
const start = 1000;
const max = 1010;
var c = start;
var el = document.getElementById('counter');
function counter() {
if (c > max) {
c = start;
}
el.innerHTML = c + "";
c++;
}
counter(); // Optional, can exclude if you want to delay starting the timer
setInterval(counter , 1000)
<div id="counter"></div>

I cannot run setInterval and another function at the same time

I have two functions that are supposed to run when I click on a button. The first function is a setInterval function that increments the variable num by 0.01 and displays it in a div id called result. The second function generates an object literal into a json string and displays it in a div id called output. When I click on the button, only the JSON string is outputted, but it seems as though the setInterval doesn't run and I don't know why. Here is the link for example
HTML
<button>
click
</button>
<div id="result">
</div>
<div id="output">
</div>
Javascript
var timer,
result = document.getElementById("result"),
num,
link ={
name:"link",
weapon:"master sword",
mute:true,
race:"hyrulian",
age:16
};
/* ---------- GENERATE JSON OBJECT --*/
function generate(){
var data = {};
for(var prop in link){
data[prop] = link[prop];
}
data = JSON.stringify(data);
document.getElementById("output").innerHTML = data;
}
/* ---------- CLICK BUTTON --*/
document.querySelector("button").onclick = function(){
num = 0;
function callBack(){
num += 0.01;
result.innerHTML = num.toFixed(2);
}
timer = setInterval(callBack,10);
generate();
clearInterval(timer);
}
Updated My Answer: You have to wrap your callBack(); function in the setInterval with an anonymous function. This is because setInterval expects a reference to a Function that should be executed every few milliseconds (the interval you specify). You should use it like this setInterval( function(){ callBack(); }, 10);. This should give you the desired result.
Same code, I just updated the setInterval( function(){ callBack(); }, 10); line:
var timer,
result = document.getElementById("result"),
num,
link ={
name:"link",
weapon:"master sword",
mute:true,
race:"hyrulian",
age:16
};
/* ---------- GENERATE JSON OBJECT --*/
function generate(){
var data = {};
for(var prop in link){
data[prop] = link[prop];
}
data = JSON.stringify(data);
document.getElementById("output").innerHTML = data;
}
/* ---------- CLICK BUTTON --*/
document.querySelector("button").onclick = function(){
num = 0;
function callBack(){
num += 0.01;
result.innerHTML = num.toFixed(2);
}
timer = setInterval( function(){ callBack(); },10); // I modified this line
// timer = setInterval(callBack,10);
generate();
clearInterval(timer);
// setTimeout( function(){ clearInterval(timer); }, 1000); // This can be used to test that the timer has indeed started, you can wait 1 second before you clear the timer
}
It's because you setInterval(callBack,10);, but then you clear the interval using clearInterval(timer);.
remove the clearInterval(timer); and you'll get the timer working.
JavaScript is single threaded. In order for the callBack function which you have set up to run in an interval of 10ms with setInterval(callBack,10) to run, your JavaScript code has to stop running (i.e. complete). Until your code relinquishes the processor, no call back functions (of any type) will execute.
Thus, in your code:
timer = setInterval(callBack,10); //Set up the interval timer
generate(); //generate(): Even if this takes 10 minutes to complete
// the callBack function will not be executed from the interval timer.
clearInterval(timer); //Clear the interval timer. While the interval may have expired
// (depending on how long the generate() function took), the
// the callBack function will have never run because the processor
// has been busy continuing to run the code that came after calling
// setInterval. Clearing the interval timer here results in
// callBack never being executed.
Thus, if you want callBack to execute even once, you need to not call clearInterval(timer) prior to the code you are executing at that time completing.
If you wanted callBack to only be executed once, then you could have used setTimeout().
Timing how long something takes:
If you are attempting to time how long something takes:
Get the current time prior to what you are wanting to time
Use window.performance.now() which is "measured in milliseconds, accurate to one thousandth of a millisecond".
Do the thing you want to time
Get the time after you are done (Use window.performance.now() again).
Compute and display the difference between the two times.
So, modifying your code:
var timer,
result = document.getElementById("result"),
link = {
name: "link",
weapon: "master sword",
mute: true,
race: "hyrulian",
age: 16
};
/* ---------- GENERATE JSON OBJECT --*/
function generate() {
var data = {};
for (var prop in link) {
data[prop] = link[prop];
}
data = JSON.stringify(data);
document.getElementById("output").innerHTML = data;
}
/* ---------- CLICK BUTTON --*/
document.querySelector("button").onclick = function() {
function showResult(time, precision, units) {
result.innerHTML = time.toFixed(precision) + ' ' + units;
}
var startTime = window.performance.now();
generate();
var endTime = window.performance.now();
//These times are floating point numbers in milliseconds
var elapsedMs = endTime - startTime;
showResult(elapsedMs,3,'milliseconds');
//If you want to show the time in microseconds:
//var elapsedUs = elapsedMs * 1000;
//showResult(elapsedUs,0,'microseconds');
}
<button>
click
</button>
<div id="result">
</div>
<div id="output">
</div>
However, if your real goal is to determine how long, on average, it takes to run generate() then you need time how long it takes to run generate a large number of times, not just once.
var result = document.getElementById("result");
var link = {
name: "link",
weapon: "master sword",
mute: true,
race: "hyrulian",
age: 16
};
/* ---------- GENERATE JSON OBJECT --*/
function generate() {
var data = {};
for (var prop in link) {
data[prop] = link[prop];
}
data = JSON.stringify(data);
document.getElementById("output").innerHTML = data;
}
/* ---------- CLICK BUTTON --*/
document.querySelector("button").onclick = function(event) {
//Should not do long things in an event handler.
//Thus, instead of actually performing the tests here, we set
// a timeout which will execute after the event has processed.
this.style.display = 'none'; //Only get to click once
setTimeout(performTimedTests,0,generate,result);
}
/*
* Perform multiple runs of an increasing number of iterations of a specified function.
*
* functionToTest = The function which is being timed
* resultsElement = An element in the DOM, usually a <div>, which will
* have its innerHTML replaced with a table of time results.
* start = The number of iterations to start with. (default = 1)
* end = The number of iterations to not exceed. (default = 1000000)
* multiplier = The amount multiply the current number of iterations to find
* the number of iterations for the next run. (default = 10)
*/
function performTimedTests(functionToTest,resultsElement,start,end,multiplier){
start=start?start:1;
end=end?end:1000000;
multiplier=multiplier?multiplier:10;
var textColors =['red','orange','yellow','green','blue','purple']
function timeAfunction(functionToTest, iterations){
var i, startTime, endTime;
startTime = window.performance.now();
for(i=0;i<iterations;i++){
functionToTest();
}
endTime = window.performance.now();
return (endTime - startTime);
}
function addResultToTable(table, elapsedTime, iterations, precision1, units1
, precision2, units2, scale2, name) {
var perCall = (elapsedTime/iterations)*scale2;
var newRow = table.insertRow(-1);
newRow.insertCell(-1).textContent = iterations;
newRow.insertCell(-1).textContent = elapsedTime.toFixed(precision1) + units1;
newRow.insertCell(-1).textContent = perCall.toFixed(precision2) + units2;
newRow.insertCell(-1).textContent = name;
}
function performNextTest(functionToTest,resultsElement,iterations,maxIterations
,multiplier,isFirstIteration){
var elapsedTime = timeAfunction(functionToTest, iterations);
var processing;
if(isFirstIteration) {
result.innerHTML = '<div></div>'
+'<table><tr><th>Iterations</th><th>Total time</th>'
+'<th>Time per<br/>Iteration</th>'
+'<th>Function<br>Tested</th></tr></table>';
processing = resultsElement.querySelector('div');
processing.textContent = 'Processing';
processing.style.color = textColors[0];
}
processing = resultsElement.querySelector('div');
var table = resultsElement.querySelector('table');
addResultToTable(table,elapsedTime,iterations,3,'ms',3,'us',1000
,functionToTest.name);
processing.textContent += '.';
//Cycle colors of 'Processing..' text
var colorIndex=textColors.indexOf(processing.style.color);
colorIndex++;
colorIndex = colorIndex>=textColors.length?0:colorIndex;
processing.style.color = textColors[colorIndex];
iterations *= multiplier;
if(iterations<=maxIterations) {
//Let the browser redraw
setTimeout(performNextTest,0,functionToTest,resultsElement,iterations
,maxIterations,multiplier,false);
}else{
processing.textContent = '';
processing.style.display = 'none';
}
}
performNextTest(functionToTest,resultsElement,start,end,multiplier,true);
}
<button>Start</button>
<div id="result"></div>
<div id="output"></div>

How to run a javascript function X seconds?

I am using setInterval to run a Javascript function that generates a new, random integer in a div. the timer starts when I click on the div. I am having problems with stopping it form generating new numbers after five seconds.
Using setTimeout, I hide the div after 5 seconds; that stops random numbers, but I lose the div.
How can I efficiently stop the generating of numbers in the div, and not hide it?
HTML:
<div id="div" onmousedown='F();'>Click here</div>
JS:
function F(){
var div = document.getElementById("div");
setInterval(function(){
var number = Math.floor(Math.random()*28) ;
div.innerHTML = number;
}, 1000);
setTimeout(function(){
div.style.display = 'none';
},5000);
};
Just use a counter to keep track of the number of times the interval has ticked and then use clearInterval to stop it:
var count = 0;
var intervalID = setInterval(function() {
// generate your random number
count++;
if (count === 5) {
clearInterval(intervalID);
}
}, 1000);
Something hastily written, but what you want to do is keep track of your interval handle and then clear it. You can do this with a setTimeout
var forXsecs = function(period, func) {
var handle = setInterval(func, 1000);
setTimeout(function() { clearInterval(handle); }, period * 1000);
}
The timing is not perfect. Matt's answer would also work.
Another option is a slight change on Matt's answer that removes setInterval and just uses timeouts.
var count = 0;
var forXsecs = function(period, func) {
if(count < period) {
func();
count++;
setTimeout(function() {forXsecs(period, func);}, 1000);
} else {
count = 0; //need to reset the count for possible future calls
}
}
If you just want to simply let it run once each second and that 5 times you can do it like this:
HTML:
<div id="5seconds"></div>
JS:
var count= 0;
setInterval(function(){
if(count < 5){
document.getElementById('5seconds').innerHTML = Math.random();
count++
}
},1000);
This will generate a random number each second. until 5 seconds have passed
you should use clearInterval to stop the timer.
To do so, you pass in the id(or handle) of a timer returned from the setInterval function (which creates it).
I recommend clearing the interval timer (using clearInterval) from within the function being executed.
var elm = document.querySelector("div.container");
var cnt = 0;
var timerID;
function generateNumber()
{
cnt += 1;
elm.innerText = cnt;
if (cnt >= 5) {
window.clearInterval(timerID);
}
}
timerID = window.setInterval(generateNumber, 1000);
.container {display:block; min-width:5em;line-height:5em;min-height:5em;background-color:whitesmoke;border:0.1em outset whitesmoke;}
<label>1s Interval over 5s</label>
<div class="container"></div>

Change innerHTML color randomly in loop

I am trying to run a loop that will continuously change the color by randomly generating hex codes. I tried to search on here but couldn't find anything doing this.
I can't figure out how to get a loop to run and change the color continuously (until the end of a loop). I am new to JavaScript.
Here's my JSFiddle.
HTML
<body>
<div id="outer">
<div id="test">Generate colors.</div>
</div>
</body>
JS
for ( i = 0; i < 20000; i++ ) {
var t = document.getElementById('test');
var z = '#'+(Math.random()*0xFFFFFF<<0).toString(16);
t.style.color = z
}
You can't change colors in a loop, the color of the element won't change until you exit the code and return control to the browser.
You can use an interval to run code and return the control to the browser each time:
window.setInterval(function(){
var t = document.getElementById('test');
var z = '#'+(Math.random()*0xFFFFFF<<0).toString(16);
t.style.color = z
}, 100);
Demo: http://jsfiddle.net/et3qtr3t/
You were right with the commented setInterval you have on fiddle. It will make the colors change periodically (according to the milliseconds defined).
But you have to remove the for loop, because it will run instantly and you won't even see the changes... You'll have to manage your own variable counter, and clear the interval after it:
http://jsfiddle.net/kkfnjpsh/5/
var i = 0;
var runner = setInterval(function(){
if(i < 20000) {
var t = document.getElementById('test');
var z = '#'+(Math.random()*0xFFFFFF<<0).toString(16);
t.style.color = z;
i++;
}
else {
clearInterval(runner);
}
}, 3000);
I know it's already been answered, but mine includes the cleartimeout to set a timer.
var myVar = setInterval(function(){changeColor()}, 1000);
setTimeout(function(){clearInterval(myVar)}, 5000);
The second argument in the call to setTimeout could serve as your timer, so that the animation stops afterwards, in this case, it's set to 5 seconds.
function changeColor() {
var t = document.getElementById('test');
var z = '#'+(Math.random()*0xFFFFFF<<0).toString(16);
t.style.color = z;
console.log(z);
}
Result: Result
You don't loop - you interval:
var target= document.getElementById('test'),
colorChange = function() {
target.style.color = '#'+(Math.random()*0xFFFFFF<<0).toString(16);
};
// run interval
var d = setInterval(function() {
colorChange();
}, 500);
// clear after 5s
setTimeout(function() {
clearInterval(d);
}, 5000);
Working JSFiddle: http://jsfiddle.net/046q6ohf/

Categories