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);
}
Related
So this is the code that I wrote :
var array = [image1, image2, image3, image4, image5];
array.forEach(function(obj, num, arr){
function SH(){var random = Math.ceil(Math.random() * array.length); setTimeout(array[random].style="opacity:1;transition:0.5;", 3600000 * random);
setTimeout( array[random].style="opacity:0; transition:0.5;", 3600000 * random + 1);};
SH();
setInterval(SH(), 3600000 * arr.length )
});
I want to make a random Image visible for an hour and than stop displaying it and make the next one visible. Im getting the "Cannot set property style of undefined" error. How do I fix it?
var random = Math.ceil(Math.random() * Array.length); returns undefined.
It's because Array is a keyword in JS. Rename it to array
Thanks for the comment. There are actually multiple problems in that code. I wanted to give you the next step how to fix it. There is also an incorrectly defined setTimeout callback and you should also use length - 1
If you'd like a fixed version, here you go:
var array = ["image1", "image2", "image3"];
array.forEach(function (obj, num, arr) {
function SH() {
var random = Math.ceil(Math.random() * array.length - 1);
setTimeout(() => {
array[random].style = "opacity:1;transition:0.5;";
}, 3600000 * random);
setTimeout(() => {
array[random].style = "opacity:0; transition:0.5;";
}, 3600000 * random + 1);
}
SH();
setInterval(SH(), 3600000 * array.length );
});
After comments:
var array = ["image1", "image2", "image3"];
function SH() {
var random = Math.ceil(Math.random() * array.length - 1);
array.forEach(function (obj, num, arr) {
// if any other index than randomised one
if (num !== random) {
array[random].style = "opacity:1;transition:0.5;";
} else {
array[num].style = "opacity:0; transition:0";
}
});
}
SH(); // start first
setInterval(() => SH(), 3600000); // set the interval
I'm trying to create a button that when pressed has a 1.04% chance to lead to Page A and a 98.96% chance to lead to Page B. That's my overall goal but the specific aspect I'm having trouble on is the randomization of the results. I'm quite new to javascript so I apologize in advance. Any help is appreciated.
--edit--
I'm incorporating this code into a Wix project and here is the total code I have so far. I started with easy whole numbers 40/60 to make sure I could do it but the smaller percent I'm having trouble incorporating. It's important I have a decimal percentage 1.04 and not 1.00.
import wixLocation from 'wix-location';
let random = 0,counter40 = 0,counter60 = 0;
$w.onReady(function () {
for (var i = 0; i < 10000000; i++) {
random = Math.floor((Math.random() * 100) + 1);
if (random <= 40) {
counter40++;
} else {
counter60++;
}
}
console.log("counter40: " + counter40.toString());
console.log("counter60: " + counter60.toString());
});
export function button1_click(event) {
random = Math.floor((Math.random() * 100) + 1);
if (random <= 40) {
wixLocation.to("/pageB");
} else {
wixLocation.to("/pageC");
}
}
https://jsfiddle.net/ys84pu6a/1/
HTML:
<button id="randomRedirect">
Press me
</button>
JS:
let button = document.getElementById('randomRedirect')
button.addEventListener('click', function() {
let d = Math.random();
if (d < 0.9896)
window.location.href = "pageB.html";
else
window.location.href = "pageA.html";
}, false);
Use the Math.random() function. It returns a random number between 0 and 1.
You could use it this way:
x = Math.random()
if(x < 0.0104){//1.04% chance
window.location.href = [Page A]
}
else{
window.location.href = [Page B]
}
The function that provides pseudo-random values is Math.random().
It returns a floating-point number between 0 and 1.
To get a 1.04% chance, you could simply do this:
let pageAChance = Math.random() <= 0.0104;
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
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));
I'm creating a slider with 6 slides, and I want to randomly move between them, making sure that neither of the previous two slides are shown as the next slide. The functionality doesn't really matter, since what I'm really doing is generating random numbers and keeping track of the previous two. The first slide is always numbered 1, so for the first two iterations that'll be one of the previous numbers that can't be used.
Here's what I have so far, and it works fine for generating the random numbers in the range, but 'caching' the last two values doesn't work reliably:
var rand = Math.floor(Math.random() * 6) + 1;
var prev1 = 1;
var prev2;
function randomSlide() {
// 5 second interval between slides
// Don't show either of previous two slides next
random = setInterval(function() {
prev2 = prev1;
prev1 = rand;
do {
rand = Math.floor(Math.random() * 6) + 1;
} while (rand == prev1 || rand == prev2);
prev1 = rand;
$('#slider').anythingSlider(rand);
//console.log(prev1,prev2);
}, 5000);
}
function firstSlide() {
firstTime = setTimeout(function() {
randomSlide();
}, 5000);
}
firstSlide();
randomSlide();
It's quite simple I think but my brain's getting frazzled trying to parse the values of the two 'cache' variables at the first, and then each subsequent, iteration.
I'm executing a single iteration at the beginning because if randomSlide() executes on load then the first (welcome) slide doesn't get a chance to display.
When you do the prev1 = rand the second time after you've changed the value of rand, you're assigning the new slide's number to it. The next time you enter the loop you do prev2 = prev1, and since prev1 == rand it means that now all three variables prev1, prev2 and rand are the same. Just remove the second prev1 = rand.
Another issue is that you set the interval twice: first you call firstSlide() which executes randomSlide() after a 5 second delay (which sets one interval), then right after you call randomSlide() again which sets another interval.
Here's another (simpler?) approach to getting the result:
<script>
// Return a random number from 1 to 6, exclude
// the last two numbers.
var getRandom = (function() {
var a = [1,2,3,4,5,6];
return function() {
var i = (Math.random() * 4 ) | 0;
a[5] = a.splice(i,1);
return a[5];
}
}());
function writeRandom() {
document.getElementById('d0').innerHTML += getRandom() + '<br>';
}
setInterval(writeRandom, 100)
</script>
<div id="d0"></div>
Not exactly random for the first 2 iterations, but you can fix that by randomising the array when it's initialised. But likely it doesn't matter for a slide show.
It's less code, but the splice part makes it slower in the browsers I tested. My version of the OP is:
var getRandom2 = (function() {
var r0 = r1 = r2 = 1;
return function() {
r0 = r1;
r1 = r2;
do {
r2 = Math.floor(Math.random() * 6) + 1;
} while (r2 == r0 || r2 == r1);
return r1;
}
}());