I want the color of the box I have created to change every 0.5 seconds, I have stored the colors in an array and I want the color to change every .5 seconds but it changes all at once.
<style type="text/css">
#box{
width: 100px;
height: 100px;
background: green;
}
</style>
</head>
<body>
<div id="box"></div>
<script type="text/javascript">
var colors = ['red','blue','green','violet','purple'];
var box = document.getElementById('box');
setInterval(function(){
for(var i=0; i < colors.length; i++){
box.style.backgroundColor=colors[i];
}
}, 300);
</script>
Depending on whether you want the box to continue changing after it has been through all the colours, there are a number of ways to solve this:
/*
Keeps running
*/
var colors = ['red','blue','green','violet','purple'],
i = 0;
setInterval(function () {
box.style.backgroundColor = colors[i++ % colors.length];
}, 500);
/*
Runs once only
*/
var colorsOnce = colors.slice(),
interval = setInterval(function () {
once.style.backgroundColor = colorsOnce.shift();
if(!colorsOnce.length) clearInterval(interval);
}, 500);
.box{
width: 100px;
height: 100px;
background: green;
}
<div id="box" class="box"></div>
<div id="once" class="box"></div>
Note: Despite these examples, where timing functions are involved best practice is generally to use a timeout as described by #AmmarCSE above.
You are looping inside the interval callback, which means that it will go through all the colors each interval.
Make the interval be the loop instead, i.e. go one step furter for each interval. Example:
var index = 0;
setInterval(function(){
box.style.backgroundColor = colors[index];
index = (index + 1) % colors.length;
},300);
Demo:
var colors = ['red','blue','green','violet','purple'];
var box = document.getElementById('box');
var index = 0;
setInterval(function(){
box.style.backgroundColor = colors[index];
index = (index + 1) % colors.length;
},300);
#box{
width: 100px;
height: 100px;
background: green;
}
<div id="box"></div>
Note: To actually get an interval that runs every 0.5 seconds, you should use 500 instead of 300 in the setInterval call.
Use setTimeout()
var colors = ['red', 'blue', 'green', 'violet', 'purple'];
var box = document.getElementById('box');
for (var i = 0; i < colors.length; i++) {
(function(index) {
setTimeout(function() {
console.log(index);
box.style.backgroundColor = colors[index];
}, 300 * i);
})(i)
}
#box {
width: 100px;
height: 100px;
background: green;
}
<div id="box"></div>
Two key points you missed in your code
Half a second is "500 milliseconds". So you need to change from 300 ms to 500ms in setInteval.
When the timer kicks in, you need to update the background color with the "next color in the array".
So you may try something like:
var color = 0;
var colors = ['red','blue','green','violet','purple'];
function nextColor(){
color ++;
if (color>=colors.length)
color = 0;
return colors[color];
}
setInterval(function(){
box.style.backgroundColor = nextColor();
},500);
This will keep the box changes its color every half a second and cycle through the color array endlessly.
Related
I have a button with a default background color(black). I want to change the background color (from an array) of this button when hovering over it. I have it working at a fundamental level, but I want it to repeat the loop over and over.
this is what i have so far.
var color = ['#3e50a2', '#faa51a', '#ed1c24', '#2a9446'];
var i = -1;
document.querySelector('.customBtn').addEventListener('mouseover', function() {
i = 1 < color.length ? ++i : 0;
document.querySelector('.customBtn').style.background = color[i]
});
document.querySelector('.customBtn').addEventListener('mouseout', function() {
document.querySelector('.customBtn').style.background = '#000';
})
<a class="customBtn">Button</a>
I think you tried to reset the value of i with this i = 1 < color.length ? ++i : 0; but it doesn't. This will continuously increase the value never resetting it because 1 is always less than the length of the array.
I think you meant to increment the value and then reset if it's too big:
i = ++i < color.length ? i : 0;
Here's the complete code. I've refactored the query selector as there's no point to doing it more than once, and changed the mouseout background colour so you can read the button
var color = ['#3e50a2', '#faa51a', '#ed1c24', '#2a9446'];
var i = -1,
btn = document.querySelector('.customBtn');
btn.addEventListener('mouseover', function() {
i = ++i < color.length ? i : 0;
btn.style.background = color[i];
});
btn.addEventListener('mouseout', function() {
// revert to default colour
btn.style.background = '';
})
<input type="button" class="customBtn" value="My button" />
Just replace i = 1 < color.length ? ++i : 0; with i = (i+1 < color.length) ? ++i : 0;. That's all.
var color = ['#3e50a2', '#faa51a', '#ed1c24', '#2a9446'];
var i = -1;
document.querySelector('.customBtn').addEventListener('mouseover', function() {
i = (i+1 < color.length) ? ++i : 0;
document.querySelector('.customBtn').style.background = color[i]
});
document.querySelector('.customBtn').addEventListener('mouseout', function() {
document.querySelector('.customBtn').style.background = '#000';
})
<a class="customBtn">Button</a>
If you must use javascript, take a look at the second example.
Pure CSS solution
You could accomplish this with a CSS animation, which would be both more efficient and less error prone. Unless there's a specific reason you need to use javascript here I'd strongly recommend this approach.
This example could be modified to do hard transitions instead of fading from one color to the next, but here's a quick demo:
button {
background: black;
color: white;
border: none;
padding: 0.5em 1em;
}
button:hover {
animation: buttonhover 1s infinite;
}
#keyframes buttonhover {
0% {
background: #3e50a2;
}
25% {
background: #faa51a;
}
50% {
background: #ed1c24;
}
75% {
background: #2a9446;
}
}
<button>Hello</button>
Javascript Solution
If you must use javascript for whatever reason, you can use the % operator to keep from running off the end of the colors array:
const colors = ['#3e50a2', '#faa51a', '#ed1c24', '#2a9446'];
let index = 0;
let interval;
const hover = (e) => {
interval = setInterval(() => {
e.target.style.backgroundColor = colors[index];
index = (index + 1) % colors.length;
}, 300);
}
document.querySelector('button').addEventListener('mouseover', hover);
document.querySelector('button').addEventListener('mouseout', (e) => {
clearInterval(interval);
e.target.style.backgroundColor = 'black';
});
button {
background: black;
color: white;
border: none;
padding: 0.5em 1em;
}
<button>Hello</button>
(?) I want to change my class name 'box' from opacity '0' to opacity '1.0' like an animation or fade in every sec 1000ms, 2000ms. 3000ms,
(X) But I don't want to do something like this code but appears fade in like this Code on jsfiddle and not fade in at the same time like this Code on jsfiddle.
var DivB = document.getElementsByClassName("box");
setTimeout(function(){DivB[0].style.opacity = "1"}, 1000);
setTimeout(function(){DivB[1].style.opacity = "1"}, 2000);
setTimeout(function(){DivB[2].style.opacity = "1"}, 3000);
(/) I want to make It appears with the delays 1000,2000,3000 with javascript look shorter like using var 'i' to javascript like this .. Code on jsfiddle.
var DivB = document.getElementsByClassName("box");
var i;
function myFade(){
for (var i=0; i<DivB.length; i++){
setTimeout(function(){DivR[i].style.opacity="1"}, i*1000)}
}
myFade();
You're looking for setInterval
var DivB = document.getElementsByClassName("box");
var divIndex = 0;
var interval = setInterval(() => {
DivB[divIndex].style.opacity = "1";
divIndex++;
if (divIndex === divB.length - 1) clearInterval(interval);
} , 1000)
Basically, this will fire every one second, setting the opacity of divB[divIndex] to '1'. divIndex itself increments every interval as well. After all the DivB elements are processed, the interval will be cleared.
You can add transition: all 1s; to the box CSS from one of the code examples you posted:
var DivB = document.getElementsByClassName("box");
setTimeout(function(){DivB[0].style.opacity = "1"}, 1000);
setTimeout(function(){DivB[1].style.opacity = "1"}, 2000);
setTimeout(function(){DivB[2].style.opacity = "1"}, 3000);
.box { display:inline-block; position:relative; opacity:0;
transition: all 1s;}
<div class='box'>1</div><br/>
<div class='box'>2</div><br/>
<div class='box'>3</div><br/>
You can do this :
var DivB = document.getElementsByClassName("box");
function myFade() {
for (let i = 0; i < DivB.length; i++) {
setTimeout(() => {
DivB[i].style.opacity = "1"
}, i * 1000)
}
}
myFade();
.box {
display: inline-block;
position: relative;
opacity: 0;
}
<div class='box'>1</div>
<div class='box'>2</div>
<div class='box'>3</div>
I would suggest you to read the difference between var and let specially when using in loops with setTimeout and setInterval
Hope this helps !
Try it:
function fadeElementsProgressive(className, timePerElement = 1000) {
const divs = document.getElementsByClassName(className);
for(let i = 0; i < divs.length; i++) {
setTimeout(() => {
divs[i].style.opacity = 1;
}, i * timePerElement)
}
}
fadeElementsProgressive('box');
.box { display:inline-block; position:relative; opacity:0; }
<div class='box'>1</div><br/>
<div class='box'>2</div><br/>
<div class='box'>3</div><br/>
This will create a function that get a class name and execute a fade.
I have made a progress bar with decrease from width 100 to 0 using setInterval function. So basically every 20ms my width decrease from 1. Then when the width arrives at 0, I set the width to 100 to run the progress bar again. At every loop, I change the text inside my progress bar. What I'd like to do now is change the time interval (the 20ms) at every loop.
Si in my code, when I increase from one, my 20 is replaced by interval[i]... but I am stack to put setInterval inside a loop...
The code below works to change the text at every loop, but don't know how to improve it to change the time interval at every iteration of i...
function move() {
var message = ['test', 'test2', 'test3'];
var interval = [10, 20, 30]
var elem = document.getElementById("myBar");
var width = 100;
var i = 0;
var id = setInterval(frame, 20);
function frame() {
width = width - 1;
elem.style.width = width + "%";
elem.textContent = message[i];
if (width == 0 && i < 3) {
width = 100;
i++;
}
if (i == 3) {
clearInterval(id);
}
}
}
#myProgress {
width: 100%;
background-color: #ddd;
}
#myBar {
width: 100%;
height: 30px;
background-color: #4CAF50;
}
<h1>JavaScript Progress Bar</h1>
<div id="myProgress">
<div id="myBar"> </div>
</div>
<br>
<button onclick="move()">Click Me</button>
<html>
<style>
#myProgress {
width: 100%;
background-color: #ddd;
}
#myBar {
width: 100%;
height: 30px;
background-color: #4CAF50;
}
</style>
<body>
<h1>JavaScript Progress Bar</h1>
<div id="myProgress">
<div id="myBar"> </div>
</div>
<br>
<button onclick="move()">Click Me</button>
<script>
function move() {
var message = ['test','test2','test3'];
var interval = [10,20,30]
var elem = document.getElementById("myBar");
var width = 100;
var i = 0;
var id = setInterval(frame, interval[i]);
function frame() {
width = width - 1;
elem.style.width = width + "%";
elem.textContent = message[i];
if (width == 0 && i < 3) {
width = 100;
i++;
clearInterval(id);
id = setInterval(frame, interval[i]);
}
if (i == 3) {
clearInterval(id);
}
}
}
</script>
</body>
</html>
You could declare a variable outside function move that holds the iteration time step, like:
let iterationStep = 0;
Then inside
let iterationStep = 0;
function move() {
//...blabla
var id = setInterval(frame, interval[iterationStep]);
function frame() {
// blablabla
if (width == 0 && i < 3) {
width = 100;
i++;
// HERE
iterationStep = i;
}
//blablabla
}
}
So each time you are increasing i you are also increasing the value of iterationStep by i value. And it is the value that will be used to access the postition inside the array of intervals of the iteration once you click in move().
I'm trying to visualize a countdown via a div's width. This could be used for something like a banner system showing when the next banner will slide in, or for a notification system showing how long the notification will be visible.
So in my example below, I have the .outer div emptied after 5 seconds, but the .timer div's width is not reaching width: 0%; at the same time as the setTimeout() kicks in.
The variable len would represent how long the banner or notification would be shown for.
The calculation in the variable offset is what is throwing me off (I think), I cannot seem to get the calculation correct. I would like it to be dynamic, meaning, no matter what len is and what the width of the outer/parent div is, it will always take len time to reach width: 0%;.
I hope my explanation makes sense. Any help would be greatly appreciated.
const len = 5000;
let outer = document.querySelector('.outer');
let timer = document.querySelector('.timer');
let timerWidth = timer.offsetWidth;
let offset = len / timerWidth;
let init = 100;
let interval = setInterval(() => {
init = init - offset;
timer.style.width = init + '%';
}, 1000);
setTimeout(() => {
outer.innerHTML = '';
clearInterval(interval);
}, len);
* {
box-sizing:border-box;
}
body {
padding: 100px 10px 10px;
}
.outer {
width: 100%;
border: 1px solid slategray;
padding: 10px;
}
.timer {
width: 100%;
height: 10px;
background: red;
transition: all 1000ms linear;
}
<div class="outer">
<div class="timer"></div>
<p>Some Message Here!</p>
</div>
Two problems with the code:
interval doesn't start as soon as the page is loaded so the CSS is late in transition.
offset was wrong indeed.
Here's how I fixed it:
let toElapse = 3000; // modify as you like
let tick = 1000; //if you modify this don't forget to replicate
//in CSS transition prop
let countDownEl = document.querySelector('#countdown');
let outer = document.querySelector('.outer');
let timer = document.querySelector('.timer');
let init = 100;
// we calculate the offset based on the tick and time to elapse
let offset = init / (toElapse/tick);
countDownEl.innerHTML = init;
setTimeout(()=>{
// we need to start the first CSS transition ASAP so it is not late.
init = init - offset;
timer.style.width = init.toFixed(2) + '%';
},0)
let interval = setInterval(() => {
// the same interval.
countDownEl.innerHTML = init;
init = init - offset;
timer.style.width = init.toFixed(2) + '%';
}, tick);
setTimeout(() => {
// the same clearance timeout
outer.innerHTML = '';
clearInterval(interval);
}, toElapse);
* {
box-sizing:border-box;
}
body {
padding: 100px 10px 10px;
}
.outer {
width: 100%;
border: 1px solid slategray;
padding: 10px;
}
.timer {
width: 100%;
height: 10px;
background: red;
transition: width 1s linear;
}
<div class="outer">
<div class="timer"></div><span id="countdown"></span>
<p>Some Message Here!</p>
</div>
If you use percentage in width you don't need to know the width of your box.
you just need to substract and add on offset to timeout.
const len = 5000;
let outer = document.querySelector('.outer');
let timer = document.querySelector('.timer');
let timerWidth = timer.offsetWidth;
let offset = 100 * 1000 / 5000;
let interval = setInterval(() => {
init = init - 20;
timer.style.width = init + '%';
}, 1000);
setTimeout(() => {
outer.innerHTML = '';
clearInterval(interval);
}, len + 1000);
I have sample code:
<div></div>
<button>
Go
</button>
div {
width: 50px;
height: 50px;
border: 1px solid #ccc;
}
var bgs = ['red', 'blue', 'yellow', 'green', 'black'];
$('button').click(function() {
for (var i = 0; i < bgs.length; i++) {
$('div').css('background-color', bgs[i]);
}
});
https://jsfiddle.net/e4jhwtyc/2/
What I want to achieve is that when users click the Go button, users will be able to see the background very quickly changing from red, blue, yellow, green, and then black.
But what I got was just black color when the Go button was clicked.
Am I missing something?
You need to set some timeout to see change in color otherwise it will happen too quickly.
var bgs = ['red', 'blue', 'yellow', 'green', 'black'];
$('button').click(function() {
for (var i = 0; i < bgs.length; i++) {
setTimeout(function(){
$('div').css('background-color','').css('background-color', bgs[i]);
}, 1000);
}
});
You can use setInterval() to change color on some period of time (0.3s for example) otherwise it will change instantly with your code. And when it reaches last element of array you can clearInterval() and reset counter i
var bgs = ['red', 'blue', 'yellow', 'green', 'black'];
var i = 0;
$('button').click(function() {
var x = setInterval(function() {
if (i < bgs.length) {
$('div').css('background-color', bgs[i++]);
} else {
clearInterval(x);
i = 0;
}
}, 300)
});
div {
width: 50px;
height: 50px;
border: 1px solid #ccc;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div></div>
<button>
Go
</button>
Every time there is a click event the for ends at black color. So it gets black!!!. The for is to fast if you compare that with browser rendering so the other colors don't get rendered.
Try the setTimeout() function with a different offset for each color
This version does not deal with "setTimeout" and "setInterval"
var bgs = ['red', 'blue', 'yellow', 'green', 'black'];
function *getBgs(){
for(let v of bgs) {
yield v;
}
}
$('button').click(function() {
let iter = getBgs();
let $div = $('div');
var delay = 150;
var prev = 0;
(function nextColor(){
requestAnimationFrame(function(t){
if(prev && t - prev < delay) {
return nextColor();
}
prev = t;
let next = iter.next();
if(next.done) return;
$div.css('background-color', next.value);
nextColor();
});
})();
});
div {
width: 50px;
height: 50px;
border: 1px solid #ccc;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div></div>
<button>
Go
</button>