Why does this Increment not work? - javascript

I'm having some problems with this code. My problem is that with the code below, it doesn't plus the detection-ratio text with the 'incr'. It just enters the incr, but doesn't plus.
This is my code.
(function loop() {
var rand = Math.round(Math.random() * (3000 - 500)) + 500;
var incr=Math.floor(Math.random()*6);
setTimeout(function() {
document.getElementById('detection-ratio').innerText = '0 / '+ ++incr;
loop();
}, rand);
}());
The 'detection-ratio' text looks like this as default:
0 / 0
Then, lets say 'incr' generates the number '3', then it should increase the last 0 with 3, so it would look like this:
0 / 3
Then, lets say it's going to generate a new 'incr', lets say '5'. Then it would look like this:
0 / 8
---> But right now, it doesn't do that. It just writes the 'incr' into the 'detection-ratio' without increasing it.

Hope this code would help you to get the expected output, let me know if something breaks. Also stop iteration once it reaches > 26
var incr = 0;
(function loop() {
var rand = Math.round(Math.random() * (3000 - 500)) + 500;
incr += Math.floor(Math.random()*6);
setTimeout(function() {
console.log('0 / '+ incr);
loop();
}, rand);
}());
Thanks for the explanation and patience.

I am assuming you are trying to append text to detection-ratio
if so you need to
document.getElementById('detection-ratio').innerText += '0 / '+ incr;
++ before a variable is a pre-increment operator, since you are generating random numbers i am assuming that is not actually what you want.

Since you're calling the loop recursively anyway, you may want to consider a more functional approach:
(function loop(startctr) {
var rand = Math.round(Math.random() * (3000 - 500)) + 500;
nextctr = startctr + Math.floor(Math.random()*6);
setTimeout(function() {
console.log('0 / '+ nextctr);
loop(nextctr);
}, rand);
}(0));

Related

How to recursively change color of element

I want to create a program that recursively changes the color of text.
I've already created a for(){} loop with the random color code in it in order to attempt to recurse it.
for(var x = 0; x > -1; x++){
document.getElementById("k").style.color = '#'+(0x1000000+
(Math.random())*0xffffff).toString(16).substr(1,6)}
<p id="k">Yeet</p>
The actual result is that the color stays at it's default, black. I would like it to be that every time it runs (infinitely), it will change colors.
You have to use setInterval() method to run asynchronously without blocking the main execution.
setInterval(() => document.getElementById("k").style.color = '#' + (0x1000000 +(Math.random()) * 0xffffff).toString(16).substr(1, 6),500)
<p id="k">Yeet</p>
If you want to stop at some point then use clearInterval() method to clear the interval.
let i = 0;
const inter = setInterval(() => {
document.getElementById("k").style.color = '#' + (0x1000000 + (Math.random()) * 0xffffff).toString(16).substr(1, 6);
// to clear after 10 colors
if (i++ === 10) clearInterval(inter);
}, 500)
<p id="k">Yeet</p>
/** Bad recursive pattern.
*
* All recursive methods should have a base case,
* I assume you want the change to stop at some point,
* if not you have an infinite loop running.
*
* This function can still time out if it takes too long to hit "theLastColor"
*/
function recursiveColorChange(id, currentColor) {
const theLastColor = '#some-value';
if (currentColor === theLastColor) {
return;
}
const randomColor = '#' + (0x1000000 + (Math.random()) * 0xffffff).toString(16).substr(1, 6);
document.getElementById(id).style.color = randomColor;
return recursiveRandomColor(id, randomColor);
}
However, using the pure recursive code prevents controlling color change Z_BEST_SPEED.
As mentioned by #pranav-c-balan, I think it is better to use setTimeout.
You can still have a base case where you stop changing colors by using clearTimeout();
/** Better setTimeOut pattern.
*
* You can pass a lastColor value if you want it to stop if it reaches a color.
* Or you can just pass it an id and a speed (in milliseconds) and it will run forever without breaking your code.
*/
function repeatColorChange(id, speed, lastColor) {
const myTimeOut = setTimeout(() => {
const randomColor = '#' + (0x1000000 + (Math.random()) * 0xffffff).toString(16).substr(1, 6);
document.getElementById(id).style.color = randomColor;
if (randomColor === lastColor) {
clearTimeout(myTimeOut);
}
}, speed);
}

Every 1 second increase the value with a random number using decimal numbers

So I'm trying to increment the value of a number in an interval of 1 second with a decimal number between (0.01 and 0.05) and I can't seem to figure this out.
The only thing that it does is to show me numbers between 0.01 and 0.05 instead of adding them up to be an integer.
setInterval (function myFunction() {
var number = 0;
document.getElementById("computerScore").innerHTML = number +
Math.floor((Math.random() * 5) + 1)/100;
}, 1000)
<b>computer score:</b><p id="computerScore">0</p>
Your problem is that you are setting number to 0 in each execution, while it should be the current value.
You need to assign Number(document.getElementById("computerScore").textContent) to it, so it keeps updating with the added random number.
Note that I used textContent which is recommended here as it holds only the text content of the element avoiding HTML elements.
setInterval (function myFunction() {
var number = Number(document.getElementById("computerScore").textContent);
document.getElementById("computerScore").textContent= number +
Math.floor((Math.random() * 5) + 1)/100;
}, 1000)
Demo:
setInterval (function myFunction() {
var number = Number(document.getElementById("computerScore").textContent);
document.getElementById("computerScore").textContent = number +
Math.floor((Math.random() * 5) + 1)/100;
}, 1000)
<b>computer score:</b><p id="computerScore">0</p>
You need to retrieve the previous value from your score and add your random Number to it :
PS: I added .toFixed(2) to limit your result to two decimals.
let score = document.getElementById("computerScore");
setInterval (function myFunction() {
score.innerHTML = (+score.innerHTML + Math.floor((Math.random() * 5) + 1)/100).toFixed(2);
}, 1000)
<b>computer score:</b><p id="computerScore">0</p>
You set number to 0 every time you call the function, you should define number outside of the interval
var number = 0;
setInterval(function myFunction() {
document.getElementById("computerScore").innerHTML = number +
Math.floor((Math.random() * 5) + 1) / 100;
}, 1000)
You need to declare number outside the setTimeout:
var number = 0;
setInterval (function myFunction() {
number = number +
Math.floor((Math.random() * 5) + 1)/100;
document.getElementById("computerScore").innerHTML = number;
}, 1000)
JSFiddle
you can try something like this. You forgot to set the number to 0. Then you have to increment your number with the random value you're getting.
https://codepen.io/anon/pen/dgJpep
JS :
var number = 0;
function check(){
setInterval(function(){
number = number + Math.floor((Math.random() * 5) + 1)/100;
}, 3000);
}
check();
setInterval(function(){
document.getElementById('computerScore').innerHTML = number;
});
Let me know if it works for you !

how to get delay working with setInterval and clearInterval

I'm writing a snippet where JS displays all elements of an array as a counter, with random delay between beach of the steps in loop. However, clearInterval and setInterval don't seem to be working, as what I observe is that it keeps printing values forever in the browser console.
here's the code
var low = Math.floor(Math.random() * (80 - 65 + 1)) + 65;
var high = Math.floor(Math.random() * (95 - low + 1)) + low;
// generate array between low to high
heartbeats = Array.from( {length: 15}, () => Math.floor(Math.random() * (high - low + 1)) + low );
// sort it
heartbeats = heartbeats.sort((a,b) => a - b);
for (i in heartbeats){
var randomPause = Math.floor(Math.random() * (3000 - 1000 + 1)) + 1000;
theLooper = setInterval( function () {
if (i == (heartbeats.length - 1) ) clearInterval(theLooper);
console.log("Random Pause Is :: " + randomPause);
console.log(heartbeats[i]);
name1.innerHTML = heartbeats[i];
},randomPause);
}
what I get instead of counter is a print of low then high instead of printing all the elements in the array. and console log keeps printing high forever
Problem:
In fact in your actual code you are not printing the values of the array after a respective delay one by one, you are just printing all the elements in a banch after the delay is passed.
And when you use setInterval the display won't stop, it will be displaying for ever.
Solution:
You need to use setTimeout, inside your loop, instead of setInterval, it will delay the instruction once, and make sure to increment the delay of the setTimeout function according to the iterated index use:
setTimeout(function() {
console.log("index: " + i + " & element: " + el);
}, i * 1000);
Demo:
This is a Demo snippet:
var low = Math.floor(Math.random() * (80 - 65 + 1)) + 65;
var high = Math.floor(Math.random() * (95 - low + 1)) + low;
// generate array between low to high
heartbeats = Array.from({
length: 15
}, () => Math.floor(Math.random() * (high - low + 1)) + low);
// sort it
heartbeats = heartbeats.sort((a, b) => a - b);
heartbeats.forEach(function(el, i) {
setTimeout(function() {
console.log("index: " + i + " & element: " + el);
}, i * 1000);
});
Problem
I think your variable scope is causing the problem
Solution
Change for(i in heartbeats) to for (let i in heartbeats), otherwise your i inside the setInterval callback will be always the last index of your array
Detailed doc can be found here
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let

Curve speed down using Math.PI

I am trying to create a countdown that starts at 100 and ends at 30.
I want the beginning of the countdown to be really fast and then slow down and stop at 30. At the moment though the "path" of the countdown is linear.
Also to make you aware, the start number and end number may change, but still require a curved time effect.
https://jsfiddle.net/ygnvav7c/
$(document).ready(function() {
var timer;
var count=100;
var ms = 1;
var step = 5;
var counter = setTimeout(timer, ms);
Countdown();
function Countdown() {
count=count - 1;
if (count >= 30) {
$('#countdown-display').html(count);
ms = ms + step;
counter = setTimeout(Countdown, ms);
}
}
});
How can I use Math.PI to make the time "curve"?
Parameterize your count variable with some number 0 <= t <= 1. Increment this with a regular interval (say 0.01)
e.g. for a quadratic decay:
count = count_start + (count_end - count_start) * (1 - t) ^ 2
For a sine-curve decay:
count = count_start + (count_end - count_start) * sin(pi * t / 2)
For an exponential decay:
count = count_start + (count_end - count_start) * (1 - k ^ t) / (1 - 1 / k)
where k > 1
As much as I appreciate the solutions of my dear collegues but the requirement was that it stops at the end. So the time must go to infinite or at least close enough.
Taking 10^6 as "close enough" and the tangent function as the means to reach infinity (but not to go beyond) together with a bit of simple algebra and taking the liberty to change the counting function from decreasing to increasing we get the following to play with-not to to forget the complete ignorance of teh good ol' Chicago Manual of Style by using an infamously long and winded run-on sentence, that is additionally peppered with a lot of redundant additions.
tl;dr: We need to get the x in tan(x) as close to PI/2 as possible but not bigger to reach that goal.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Counter</title>
<script type="text/javascript">
var timer;
var counter = setTimeout(timer, ms);
var ms = 1;
var count_start = 30;
var count_end = 100;
var count = count_start;
// roughly (atan(10^6) - .02) / 68
var step = 0.0228058;
// to avoid zero
var start = 0.02;
var brk = document.createElement("br");
function Countdown() {
var out = document.getElementById("output");
var text;
if (++count < count_end) {
start += step;
ms = Math.tan(start) * count;
counter = setTimeout(Countdown, ms);
text = count.toString() + " - " + ms.toString();
text = document.createTextNode(text);
out.appendChild(text);
out.appendChild(brk.cloneNode());
}
}
</script>
</head>
<body onload="Countdown()">
<p id="output" > </p>
</body>
</html>
Reducing the value in step makes the curve end earlier (you kind of "zoom in"), e.g.: step = 0.02 lets the final step last about half a second and about 85ms with step = 0.01.

Kind of custom animation - delay doesn't work

It is custom animation attempt, which works with background-position.
var i = 5;
while(i !== 0) {
setTimeout(function() {
$("#feedback-toad").css("height","+=50");
$("#feedback-toad").css("background-position", "50% "+i*(-20)+"%");
}, 1000);
i = i - 1;
}
It works in terms of final result - finally element looks like I want.
But it doesn't look like animation, it happens instantly - looks like delay (timeout) doesn't work.
Why? How I can fix that?
P.S. I don't need plugin suggestion - I would like to do it with my own code. Thanks.
You are setting all callbacks to run at the same time (1000 ms from now).
It should be something like this so it happens 1 animation per second:
var i = 5;
while (i !== 0) {
setTimeout(function () {
$("#feedback-toad").css("height", "+=50");
$("#feedback-toad").css("background-position", "50% " + i * (-20) + "%");
}, i * 1000);
i = i - 1;
}

Categories