How to make pause between each for loop iteration in JavaScript - javascript

I'm sorry if there has already been such question, I haven't found.
I wanna make a progress (loading) animation with JS:
<div class = "load">
<div id = "load_fill"></div>
<p id = "percent">0%</p>
</div>
<script>
let percent = document.getElementById("percent");
let load_fill = document.getElementById("load_fill")
let j = 0;
let fill = () => {
j++;
percent.textContent = `${j}%`;
load_fill.style.width = `${j}%`
}
for (let i = 0; i < 100; i++){
setTimeout(fill, 200);
}
</script>
The problem is that the first iteration works with delay but others no;
Is there any way to make delay between each iteration?
Will be thankful for any answer.

new Array(100).map((el, ind) => ind).forEach((cur) => setTimeout(fill, (cur + 1) * 200))
Here, we space out each setTimeout by first creating a range array (the first part) before setting a time out 200 ms between each one.

Related

setInterval / setTimeout for revealing elements one by one

I have a simple for loop inside a rendering function.
for (let i = 0; i < PLAYER.hand.length; i++) {
playerHTML += `<img class='card' src='images/cards/${PLAYER.hand[i]}.svg'>`;
}
I am trying to implement a card draw animation. How can I implement that?
I tried for example:
for (var i = 0; i < PLAYER.hand.length; i++) {
(function(i) {
setInterval(function() {
playerHTML += `<img class='card' src='images/cards/${PLAYER.hand[i]}.svg'>`;
}, 5000)
})(i)}
did not work for me. any ideas?
If you are looping through the player hand like that, your code will create an interval for each of the element and add them to playerHTML every 5000ms.
You can achieve what you want throught the use of setInterval and manually tracking/increasing the current index like this:
let i = 0
let maxLen = 5 // amount of cards on player hand
let interval = 1000
const myInterval = setInterval(() => {
console.log(i) // add to player hand
i++ // go to next card
if (i >= maxLen) { // breaking out of interval condition
clearInterval(myInterval);
}
}, interval)
you are already using interval so probably dont need the for loop
(function() {
let i = 0;
const interval = setInterval(function() {
playerHTML += `<img class='card' src='images/cards/${PLAYER.hand[i]}.svg'>`;
i += 1;
if (i >= PLAYER.hand.length) {
clearInterval(interval);
}
}, 5000)
})()
Another approach could be to initially load all the images but not display them. Then, in a setInterval() loop the existing hidden class could be removed from every element, one by one:
const cont=document.querySelector(".content");
cont.innerHTML=[...Array(5)].map((_,i)=>
`<img src="https://picsum.photos/id/${237+i}/150/100" class="hidden">`).join("<br>");
const intv = setInterval(() => {
const img=cont.querySelector(".hidden");
if(img) img.classList.remove("hidden");
else clearInterval(intv);
},1000)
.hidden {display:none}
<div class="content"></div>

how to make number generator similar to google number generator

Im trying create some type of number generator on webpage. I want to show like five numbers before the generated number show. For better imagine, you can look to google generator. When you click generate, it shows like 3-4 numbers before generated number. I use setInterval or setTimeout but i dont know how it works. My js code:
var button = document.querySelector("button");
button.addEventListener("click",function() {
for (var i = 0; i < 8; i++) {
setInterval(textC,5);
}
});
function textC(){
number.textContent = Math.floor(Math.random() * 1000) + 1;
}
Thanks for every help!
The issue with setInterval() is that it will continue forever unless cleared, causing you to keep generating random numbers. Instead you can use setTimeout(), but set the timeout to change based on the value of i in the for loop. That way, each interval will occur 50 m/s after the other.
See example below:
const button = document.querySelector("button");
const number = document.querySelector("#number");
button.addEventListener("click", function() {
for (let i = 0; i < 5; i++) {
setTimeout(textC, 50 * i);
}
});
function textC() {
number.textContent = Math.floor(Math.random() * 1000) + 1;
}
<p id="number"></p>
<button>Generate</button>
Don't use a loop (why not?). Just nest setTimeout and call it until a predefined threshold is reached. It gives you maximum control.
var button = document.querySelector("button");
var number = document.querySelector("#number");
const nRuns = 12;
const timeout = 100;
let iterator = 0;
button.addEventListener( "click", textC);
function textC(){
number.textContent = `${Math.floor(Math.random() * 1000) + 1}\n`;
iterator += 1;
if (iterator < nRuns) {
setTimeout(textC, timeout)
} else{
iterator = 0;
// you control the loop, so it's time for some extra text after it
number.textContent += ` ... and that concludes this series of random numbers`;
}
}
<p id="number"></p>
<button>Generate</button>

Shuffle array automatically 5 times

I have written JavaScript function, to shuffle an array of divs onClick.
// Function to shuffle 3 divs
shuffle = () => {
const shuffled = this.state.divs.sort(() => Math.random() - .50);
this.setState([...shuffled]);
};
// Button as an FYI
<button onClick={this.shuffle} className="has-text-black">shuffle hats</button>
This works absolutely fine, and randomises every time I click the button.
However, I want the divs to sort/shuffle 5 times automatically, onClick.
(IE = I don't want to have to click 5 times, to shuffle 5 times).
What's the best approach to do this?
(I've searched but haven't found anything to repeat shuffling on elements).
I thought about using async await/settimeout, to repeat this.state.divs.sort(() => Math.random() - .50) 5 times?
UPDATE:
To add context, here is a codesandbox...
https://codesandbox.io/s/distracted-shape-ifsiv
When I click the shuffle button, you can see the hats only swap positions once. Not 5 times.
Here is a posible way to do it, with javascript.
hats object get shuffled 5 times, with 200ms second transition.
Of course it's very simple, the object is meant to be extended!
let hats = [
{content: `<h6>1🎩</h6>`},
{content: `<h3>2🎩</h3>`},
{content: `<h1>3🎩</h1>`},
{content: `<h2>4🎩</h2>`},
{content: `<h4>5🎩</h4>`}
];
let timer;
function loop5(){
let i = 0
clearInterval(timer)
timer = setInterval(function(){
shuffle()
if (i >= 5){
clearInterval(timer)
}
i++
}, 200)
}
function shuffle(){
hats.sort(() => Math.random() - 0.5)
out.innerHTML = hats.map(e => e.content).join("")
}
div {display: flex; font-size: xx-large }
<button onclick="loop5()">shuffle hats</button>
<div id="out"></div>
I don't see why shuffling 5 times is better or any different than shuffling 5 times. Anyway you can do it in a naive way like this:
// Function to shuffle 3 divs
shuffle = () => {
const shuffled = this.state.divs.sort(() => Math.random() - .50);
this.setState([...shuffled]);
};
shuffleTimesFive = () => {
for(var i = 0; i < 5; i++)
this.shuffle();
}
// Button as an FYI
<button onClick={this.shuffleTimesFive} className="has-text-black">shuffle hats</button>
Or maybe a smarter way is to have a shuffleNTimes function that takes a parameter, like so:
// Function to shuffle 3 divs
shuffle = () => {
const shuffled = this.state.divs.sort(() => Math.random() - .50);
this.setState([...shuffled]);
};
shuffleNTimes = (n) => {
for(var i = 0; i < n; i++)
this.shuffle();
}
// Button as an FYI
<button onClick={this.shuffleNTimes.bind(this, 5)} className="has-text-black">shuffle hats</button>
I think shuffling one time and five times has the same effect, and Fisher-Yates is more efficient but keeping your way:
shuffle = () => {
let shuffled = [];
for(let i=0; i<5; i++)
shuffled = this.state.divs.sort(() => Math.random() - .50);
this.setState([...shuffled]);
};
If you decide to use "Fisher-Yates" algorithm, you can implement it like:
const shuffle = () => {
let array = this.state.divs;
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
this.setState([...array]);
}
As I understood from your comment, you want to do animation, in this case you don't need a loop rather you can use setInterval() and reset it ones executed five times. I have written a demo on both shuffling ways, as you can see the method that uses sort() sometimes returns the same result while the "Fisher–Yates" always reshuffled.
<button onclick="shuffle()">Click To Shuffle</button>
<div id="1">div1</div>
<div id="2">div2</div>
<div id="3">div3</div>
<div id="4">div4</div>
<script>
//This one uses Fisher–Yates shuffle algorithm:
const divs = [...document.querySelectorAll('div')];
const shuffle = () => {
let count = 0;
const intervalId = setInterval( function() {
for (let i = divs.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[divs[i], divs[j]] = [divs[j], divs[i]];
}
divs.forEach( div => document.body.appendChild(div) );
count++;
if(count === 5)
clearInterval(intervalId);
} ,1000)
}
</script>
<button onclick="shuffle()">Click To Shuffle</button>
<div id="1">div1</div>
<div id="2">div2</div>
<div id="3">div3</div>
<div id="4">div4</div>
<script>
const divs = [...document.querySelectorAll('div')];
shuffle = () => {
let shuffled = [];
let count = 0;
const intervalId = setInterval( function() {
shuffled = divs.sort(() => Math.random() - .50);
shuffled.forEach( div => document.body.appendChild(div) );
count++;
if(count === 5)
clearInterval(intervalId);
}, 1000 )
};
</script>
For your case, it would be like:
let divs = this.state.divs;
const shuffle = () => {
let count = 0;
const intervalId = setInterval( function() {
for (let i = divs.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[divs[i], divs[j]] = [divs[j], divs[i]];
}
this.setState([...divs]);
count++;
if(count === 5)
clearInterval(intervalId);
} ,1000)
}

How do I get Javascript to remember a variable that is reset in my function, yet initially defined outside of my function?

I'm creating a game where the computer tries to guess the user's number based on user feedback like too high or too low. I'm using a binary search. The functions work properly, however, every time the buttons are pressed, the code resets to make the original list from 1 to 100 making the guess 50 instead of remembering the new list and guess defined inside my functions.
var list = new Array();
for (i = 0; i <= 100; i++) {
list.push(i)
}
//console.log(list)
// List is intially an empty array (list). The
// for loop generates integers from
// 0 to 100 and pushes them into the array.
var guess = list[Math.floor((list.length / 2))];
console.log(guess);
var toolow = function(guess) {
while (list.includes(guess) == true) {
list.shift()
};
var guess = list[Math.floor((list.length / 2) - 1)];
console.log(list);
console.log(guess)
}
// toolow(guess)
var toohigh = function(guess) {
var last = parseInt(list.length);
while (list.includes(guess) == true) {
list.pop()
};
var guess = list[Math.round(list.length / 2)];
console.log(list);
console.log(guess)
}
// toohigh(guess)
<h1> Guess Your Number </h1>
<button id="TooLow" onclick="toolow(guess);"> Too Low</button>
<button id="TooHigh" onclick="toohigh(guess);">Too High</button>
your over use of the variable guess is causing all sorts of issues
no need to pass guess from onclick to the function
don't declare a var guess inside the functions
et voila - your code works now
var list = new Array();
for (i = 0; i <= 100; i++) {
list.push(i)
}
//console.log(list)
// List is intially an empty array (list). The
// for loop generates integers from
// 0 to 100 and pushes them into the array.
var guess = list[Math.floor((list.length / 2))];
console.log(guess);
var toolow = function() {
while (list.includes(guess) == true) {
list.shift()
};
guess = list[Math.floor((list.length / 2) - 1)];
console.log(list);
console.log(guess)
}
// toolow(guess)
var toohigh = function() {
var last = parseInt(list.length);
while (list.includes(guess) == true) {
list.pop()
};
guess = list[Math.round(list.length / 2)];
console.log(list);
console.log(guess)
}
// toohigh(guess)
<h1> Guess Your Number </h1>
<button id="TooLow" onclick="toolow();"> Too Low</button>
<button id="TooHigh" onclick="toohigh();">Too High</button>

jQuery/JavaScript delay and display

I want to cycle through an array and display each element individually, and then remove it. Sort of like this fiddle, but I don't want it to go forever.
I tried using jQuery because I thought it would be easier, but I am clearly missing something. Can anyone help?
Here is my attempt, but it just goes straight to the last element in the array.
var list = [1,2,3,4,5,6];
var length = list.length;
for(i = 0; i < length; i++) {
$('#nums').html(list[i]).delay(750);
}
Oh, and I don't care if it's jQuery or vanilla JavaScript. Either is fine by me.
$(document).ready(function(){
var list = [1,2,3,4,5,6];
var length = list.length;
var i = 0;
var ivl = setInterval( function () {
if (i < length) {
$('#nums').html(list[i]).delay(750);
i++;
}
else {
clearInterval(ivl);
}
}, 750);
});
The (pretty clever) example uses the fact that the modulus operator (%) gives you remainder, which is periodic, so you can use it to cycle through your array by taking the remainder of an infinitely increasing number divided by the length of your list.
If you want it to stop, however, you can just do a check to see if you've finished cycling through the list:
var list = [1, 2, 3, 4, 5, 6];
var length = list.length;
var i = 0;
var finished = false;
function repeat() {
if (!finished) {
document.getElementById('nums').innerHTML = list[i % length];
i++;
if (i === length) {
finished = true;
}
} else {
clearInterval(interval);
}
}
var interval = setInterval(repeat, 750);
<div id="nums"></div>
Late to the party but wouldn't it be better to use setTimeout rather than setInterval just in case the code executed on each iteration takes longer than the interval duration? I mean, I know it's not an issue in this instance but it's just a better/safer way to do this sort of thing.
$(document).ready(function(){
var list = [1,2,3,4,5,6];
var length = list.length;
var i = 0;
(function next(){
if (i < length){
$('#nums').html(list[i++]);
setTimeout(next,750);
}
})();
});
http://jsfiddle.net/zLexhdfp/3/

Categories