Looping Arrays to Change Background Image of Div - javascript

I am trying to create a loop of an array that changes the background of a div only one single loop. The code is as follows;
var ImagesF = [];
ImagesF[0]="images/image1.png";
ImagesF[1]="images/image2.png";
ImagesF[2]="images/image3.png";
var i = 1;
var index = 0;
var iterations = 0;
var interval = setInterval(autoImgB(), 2000);
function autoImgB(arr1, id){
var url = 'url(' + arr1 [i] + ')';
if(index >= arr1.length) {
index = 0;
iterations++;
}
document.getElementById(id).style.backgroundImage = url;
if (iterations >= 2) {
clearInterval(interval);
} else {index++}
}
The code is being called like, onclick="autoImgB(ImagesF, 'DIV')"It seems to be trying to work and it does change the first image, however then it doesn't seem to be passing the arguments to the next iteration, what am I doing wrong?
-- UPDATE --
I have attempted to add the following code to pass the argument as originally passed during the function call autoImgB(ImagesF, 'DIV'), however I get an error that states, "arr1 is undefined".
var index = 0;
var iterations = 0;
var interval = setInterval(function() {
autoImgB(arr1, id);
}, 2000);
function autoImgB(arr1, id){
var url = 'url(' + arr1 [index] + ')';
if(index >= arr1.length) {
index = 0;
iterations++;
}
document.getElementById(id).style.backgroundImage = url;
if (iterations >= 2) {
clearInterval(interval);
} else {index++}
}
-- UPDATE 2 --
#Andy, requested that I post my nested DIV's for further help, the DIV structure within the contain are as depicted;
var ImagesF = [];
ImagesF[0]="image1.png";
ImagesF[1]="image2.png";
ImagesF[2]="image3.png";
var n = 0;
function autoImgB(arr1) {
var url = 'url(' + arr1 [n] + ')';
if (n < arr1.length) {
document.getElementById('DIV3').style.backgroundImage = url;
setTimeout(autoImgB, 2000, arr1, ++n);
console.log(url,n)
}
}
.DIV1{
position:absolute;
top: 0px;
left: 0px;
width:100%;
height:100%;
background-image:url('');
background-color: none;
display: none;
z-index: 2;
}
.DIV2{
position:absolute;
top: 0px;
left: 0px;
width:100%;
height:100%;
background-image:url('');
background-color: none;
display: none;
z-index: 1;
}
.DIV3{
position:absolute;
top: 40px;
left: 417px;
width:105px;
height:130px;
background-image:url('');
background-color: none;
display: block;
z-index: 2;
}
<div class="holder">
<div class="DIV1" id="DIV1"></div>
<div class="DIV2" id="DIV2"></div>
<div class="DIV3" id="DIV3"></div>
</div>
<button style="cursor:pointer" onclick="autoImgB(ImagesF)">Press</button>
What I would like for this to do is be able to call it by ID within the function, eg: autoImgB(ImagesF, 'DIV3').

OK. So the main issue is that you are calling the function immediately rather than passing a reference to the function to setInterval.
var interval = setInterval(autoImgB, 2000);
The other problem is that you aren't passing any arguments to the function. There are two ways to do that. The first is to pass them as additional arguments after the time:
var interval = setInterval(autoImgB, 2000, ImagesF, 0);
The second is to call the function itself within the setInterval callback:
var interval = setInterval(function () {
autoImgB(ImagesF, 0);
}, 2000);
The other issue is that it's not clear what your HTML looks like. You appear to be getting an element with a particular id but are passing in div as the argument. So either you have an element like <div id="div"></div> or something else is going on. You should probably take a closer look at that.
That said you can shorten your code considerably if you use setTimeout instead of setInterval, as you only need to do the minimum of checks, and there's no need to clear the timer at any point. Just check to see if the index is less than the array length and call the function again.
var div = document.querySelector('div');
function autoImgB(arr, i) {
if (i < arr.length) {
div.style.backgroundImage = 'url("' + arr[i] + '")';
setTimeout(autoImgB, 2000, arr, ++i);
}
}
autoImgB(ImagesF, 0);
Here's some working code with setTimeout.

setInterval expects a function as its first parameter
var interval = setInterval(function() {
autoImgB(ImagesF, 'DIV');
}, 2000);

The only thing which is wrong in the code you've created is that you pass the return value of the autoImgB function which is undefined into the setInterval function, but the setInterval function only accepts a function or a code string.
Documentation for setInterval
I've created a example based on your code to show you how it'll work.

Related

Simon Game, Javascript settimeout and animation

Can anybody help me to simulate animation of four div tags?
Simply for loop should wait until opacity of div tags change in 1 second.
function animateDiv(ar) { // ar contains div tag indexes. ex:[0,3,2,3,1,0,1,2,3]
for (var i = 0; i < ar.length; i++) {
var ind = "";
if (ar[i] == 0) ind = ".red";
else if (ar[i] == 1) ind = ".blue";
else if (ar[i] == 2) ind = ".yellow";
else if (ar[i] = 3) ind = ".green";
var ok = false;
setTimeout(function () {
$(ind).css('opacity', 1);
console.log("waiting " + " index: " + i);
ok = true;
}, 1000);
if (ok == true) {
$(ind).css('opacity', 0.7);
console.log("Done!");
}
}
}
https://jsfiddle.net/z8y2v5u1/
A for loop can't wait for a timeout to finish, because the function you supply to setTimeout() is run asynchronously after the current function (and whatever called the current function) finishes. So the whole loop will run before the timeout happens.
You need to use a "pseudo-loop" that relies on setTimeout() to trigger the next iteration. Something like the following will work:
function animateDivs(ar, cb) {
var $divs = $(".red,.green,.blue,.yellow"),
i = 0;
(function next() {
if (i === ar.length) {
if (cb) cb();
} else {
var $div = $divs.eq(ar[i]).css('opacity', 1);
setTimeout(function() {
$div.css('opacity', 0.7);
i++;
next();
}, 1000);
}
})();
}
animateDivs([0,3,2,3,1,0,1,2,3], function() { console.log("Finished")});
div { width: 40px; height: 40px; display: inline-block; opacity: 0.7;}
.red { background-color: red;}
.green { background-color: green;}
.blue { background-color: blue;}
.yellow { background-color: yellow;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="red"></div><div class="green"></div>
<br/>
<div class="blue"></div><div class="yellow"></div>
The next() function changes the appropriate div to an opacity of 1, then uses setTimeout() to wait a second before changing the opacity back and then call next() again for the next index in the array.
I figured you might like some way to know when the animation had ended, so I've added a callback argument (cb) to animateDivs() that will be called after the whole array has been processed - in my example all it does is log something to the console, but you could use it to do something more interesting.

fadeIn and fadeOut in javascript

I'm trying to write my own animations using JavaScript.
I wrote a function for fadeIn() as below, it changes the display property followed by a change in value of opacity. But it doesn't seem to be working.
What am I doing wrong?
function fadeIn(obj, defDisp) {
obj.style.opacity = 0;
obj.style.display = defDisp;
var opVal = 0;
while (opVal < 1) {
obj.style.opacity = opVal;
opVal += 0.1;
}
}
defDisp = Default value for display property
Without a timing interval, this will likely execute too fast for you to see it. The while loop, without a timeout feature, will execute in far less than a second, and you won't see it happen. It's like asking a computer to count to 10, it will do it in less than a millisecond.
Try using a setTimeout
http://www.w3schools.com/jsref/met_win_settimeout.asp
while(opVal < 1) {
setTimeout(function(){
obj.style.opacity = opVal;
opVal += 0.1;
}, 3000);
}
Alter the timer (3000 in this case) to something that makes your fade work for you. Every 1000 is a one second and your loop runs 10 times, so in this case it would be 30 seconds, likely too slow.
I would probably stick with a CSS transition however, as they tend to render better on all browsers.
var el = document.getElementById('fadein');
fadeIn(el);
function fadeIn(ele, defDisp) {
ele.style.opacity = 0;
ele.style.display = defDisp;
var opVal = 0;
var t = setInterval(function(){
if(opVal >= 1){
clearInterval(t);
}
ele.style.opacity = opVal;
opVal += 0.1;
}, 100);
}
#fadein{ background: #ccc; border:1px solid #ddd; padding: 10px }
<div id="fadein">Hello</div>
Use a function that calls itself after a delay.
function fadeIn(obj, defDisp) {
obj.style.opacity = 0;
obj.style.display = defDisp;
var last = +new Date(); // Keep track of the time to calculate the opacity
var fadeStep = function () {
obj.style.opacity = +obj.style.opacity + (new Date() - last) / 800;
last = +new Date();
if (+obj.style.opacity < 1) {
setTimeout(fadeStep, 16);
}
};
fadeStep();
}
var el = document.getElementById('box');
fadeIn(el, 'block');
#box{ padding: 1em; background: #009afd; color: #ffffff; display: none; }
<div id="box">Hello</div>
If you want the fade to be faster, replace 800 by anything lower and vice-versa.
Because html render and for loop use the same thread, so when you doing the for-loop,you can't see any changes until the function complete. You have to use a setTimeout or setInterval (or requestAnimationFrame which is introduced from html5) so you browser can have the control to change the properties on the page:
You can see a example from the snippet, although the second that use a setTimeout is faster than the first one, which use for loop, the first one will not change its color as browser not able to change color during for-loop.
And if you choose to use requestAnimationFrame like I do in the snippets, you can have a smooth animation while the time can also be controlled precisely.
function fadeIn() {
this.style.opacity = 0;
this.style.display = 'block';
var opVal = 0;
console.time("count");
while(opVal < 1) {
this.style.opacity = opVal;
opVal += 0.000001;
}
console.timeEnd("count");
}
// Accept target as the target to apply anim, time is total anim time in ms.
function fadeInAlt(target, time) {
var opacity = 0;
var last = window.performance.now();
console.time("count2");
target.style.opacity = opacity;
target.style.display = 'block';
var fadeInFunc = function(timeStamp) {
if (opacity < 1) {
// Define the change by passed time.
var timePassed = timeStamp - last;
opacity += timePassed / time;
target.style.opacity = opacity;
last = timeStamp;
requestAnimationFrame(fadeInFunc);
} else {
console.timeEnd("count2");
return;
}
};
requestAnimationFrame(fadeInFunc);
}
var div = document.getElementById('test');
div.onclick = fadeIn;
var div2 = document.getElementById('test2');
div2.onclick = function() {
fadeInAlt(this, 3000);
};
#test {
background-color: red;
width: 30px;
height:30px;
}
#test2 {
background-color: blue;
width: 30px;
height:30px;
}
<div id="test"></div>
<div id="test2"></div>

I am trying to show a random div with setinterval()

I am getting - Uncaught TypeError: Cannot read property 'style' of null
when I try to run the following:
<script type="text/javascript">
function startRotation() {
setInterval(resetAllDivs(), 20000);
}
function resetAllDivs(){
var i;
for(i=1; i<=15; i++) {
document.getElementById("img"+i).style.display = "none";
}
displayRandom();
}
function displayRandom(){
var n=Math.round(Math.random()*3)
document.getElementById("img"+n).style.display = "block";
document.getElementById("img"+n).style.width = "64%";
}
</script>
I am calling startRotation() above my closing using:
document.addEventListener('DOMContentLoaded',function(){startRotation()});
The error points to the line:
document.getElementById("img"+i).style.display = "none";
Any ideas?
A few things to note, some of them have be pointed out in the comments already, but I'll reiterate.
setInterval expects a function reference as its first parameter, you're passing in the return result of a call to resetAllDivs(), which is undefined. Really you've got
setInterval(undefined, 20000);
which won't work. You want
setInterval(resetAllDivs, 20000);
Next, this line will get you a random number between 0 - 3, which I don't think is what you were after. It's why you sometimes you'll try document.getElementById('img0'), which returns null.
Math.round(Math.random()*3)
Instead, this will get you a number between 1 - 15:
Math.floor((Math.random() * 15) + 1);
Here is a working example. Timing reduced to half a second instead of 20.
DEMO
function startRotation() {
resetAllDivs();
setInterval(resetAllDivs, 500);
}
function resetAllDivs(){
for (var i = 1; i <= 15; i++) {
document.getElementById("img" + i).style.display = "none";
}
displayRandom();
}
function displayRandom(){
var n = Math.floor((Math.random() * 15) + 1);
document.getElementById("img" + n).style.display = "block";
document.getElementById("img" + n).style.width = "64%";
}
startRotation();
div {
width: 50px;
height: 50px;
background-color: red;
}
div:nth-child(even) {
background-color: blue;
}
<div id="img1"></div>
<div id="img2"></div>
<div id="img3"></div>
<div id="img4"></div>
<div id="img5"></div>
<div id="img6"></div>
<div id="img7"></div>
<div id="img8"></div>
<div id="img9"></div>
<div id="img10"></div>
<div id="img11"></div>
<div id="img12"></div>
<div id="img13"></div>
<div id="img14"></div>
<div id="img15"></div>
This code could definitely be refactored into something smarter. I'd also advise using setTimeout over setInterval, as you gain more control.
One of your document.getElementById("img"+i) is returning a null value, wich means that the element doesn't exist or wasn't created before your resetAllDvis() functions runs.
You should use:
Math.floor((Math.random() * 15) + 1);
to return a random number between 1 and 15.
Make sure you have images with id's from id="img1" to id="img15".

JS Image Transition Not Working

I am unable to get the CSS opacity transition to work by adding it using JavaScript. Please let me know what is wrong with the code. http://jsfiddle.net/copperspeed/bvWbB
(function () {
var myImgs = document.getElementById('vz0');
var i = 0;
function cycle() {
if (i <= 3) {
var myArray = [
'http://jsrun.it/assets/t/r/U/O/trUOT.jpg',
'http://jsrun.it/assets/6/c/Y/s/6cYsH.jpg',
'http://jsrun.it/assets/w/M/r/i/wMriQ.jpg',
'http://jsrun.it/assets/5/Q/8/f/5Q8fW.jpg'
];
console.log(myArray[0]);
myImgs.setAttribute("src", myArray[i]);
if (myImgs.style.opacity === '0') {
console.log('trans');
myImgs.style.transitionProperty = 'opacity';
myImgs.style.transitionDuration = "1500ms";
}
if (myImgs.style.opacity === '1') {
console.log('opacity-0');
myImgs.style.opacity = '0';
}
i++;
setTimeout(function () {
cycle();
}, 3000);
There are a couple of issues with your script.
the opacity style doesn't exist on the element on initialization. You need to account for that in your logic
On the second pass through, the opacity style does exist and may be 0, so that condition also needs to be accounted for
Your second if statement immediately reverses what you did in the first conditional. That statement should be in an else-if
You are cycling only one image element in/out so your transition from one image to another won't work as expected. You either need to change to two elements or change your transitioning strategy to accommodate the single element.
Demo fiddle - items 1-3 above
Code changed for 1-3 above:
(function () {
var myImgs = document.getElementById('vz0');
var i = 0;
function cycle() {
if (i <= 3) {
var myArray = ['http://jsrun.it/assets/t/r/U/O/trUOT.jpg', 'http://jsrun.it/assets/6/c/Y/s/6cYsH.jpg', 'http://jsrun.it/assets/w/M/r/i/wMriQ.jpg', 'http://jsrun.it/assets/5/Q/8/f/5Q8fW.jpg'];
myImgs.setAttribute("src", myArray[i]);
if (myImgs.style.opacity === '' || myImgs.style.opacity == 0) {
console.log(myImgs.style.opacity + '0');
myImgs.style.transitionProperty = 'opacity';
myImgs.style.transitionDuration = "1500ms";
myImgs.style.opacity = 1;
} else if (myImgs.style.opacity == 1) {
console.log(myImgs.style.opacity + '2');
myImgs.style.opacity = 0;
}
i++;
setTimeout(function () {
cycle();
}, 3000);
if (i === 4) {
i = 0;
}
}
}
cycle();
}());
For item #4 above - here is a refactored version that uses two img elements to help manage the transition in and out:
Demo fiddle for 1-4 above
HTML:
<div class="imgWrapper">
<img src="http://jsrun.it/assets/t/r/U/O/trUOT.jpg" id="vz0" class="vzImage" alt="first" height="300" width="300" />
<img src="http://jsrun.it/assets/t/r/U/O/trUOT.jpg" id="vz1" class="vzImage" alt="first" height="300" width="300" />
</div>
CSS:
.imgWrapper {
position: relative;
height: 300px;
width: 300px;
}
.vzImage {
opacity:0;
position: absolute;
top: 0; left: 0;
bottom: 0; right: 0;
}
Script:
(function () {
var myImgs = document.getElementsByClassName('vzImage');
var myArray = ['http://jsrun.it/assets/t/r/U/O/trUOT.jpg',
'http://jsrun.it/assets/6/c/Y/s/6cYsH.jpg',
'http://jsrun.it/assets/w/M/r/i/wMriQ.jpg',
'http://jsrun.it/assets/5/Q/8/f/5Q8fW.jpg'];
// Consider moving this to .vsImage in stylesheet
for(var j = 0; j < myImgs.length; ++j) {
myImgs[j].style.transitionProperty = 'opacity';
myImgs[j].style.transitionDuration = "1500ms";
}
function cycle(i) {
var myArrayIdx = i % myArray.length;
var imgIdx = i % myImgs.length;
var prevImgIdx = (i-1) % myImgs.length;
myImgs[imgIdx].setAttribute("src", myArray[myArrayIdx]);
myImgs[imgIdx].style.opacity = 1;
if(myImgs[prevImgIdx]) {
myImgs[prevImgIdx].style.opacity = 0;
}
setTimeout(function () {
cycle(i+1);
}, 3000);
}
cycle(0);
}());
First rule of debugging. If something inside IF statement doesn't happen, look at the condition.
You check if myImgs.style.opacity equals 0 or 1. Use console.log(myImgs.style.opacity); and it'll show you that myImgs.style.opacity equals empty string. So none of your conditions ever fire.

Can't change css in Jquery when using a variable to reference an index of an array

var bubble = [$('#bubble1'), $('#bubble2'), $('#bubble3'), $('#bubble4'), $('#bubble5'), $('#bubble6')];
var bubbleFirst = 0;
var visibleBubbles = 3;
var bubbleHeight = 200;
var bubbleTimeDelay = 5000;
var bubbleTimer = setTimeout(function(){animateBubbles();}, bubbleTimeDelay/2);
function animateBubbles(){
clearTimeout(bubbleTimer);//stop from looping before this is finished
for(var i = 0; i < visibleBubbles + 1; i++){
count = i + bubbleFirst;
if ( count >= bubble.length ) count = count - bubble.length;//keep index inside array
bubble[count].animate({top:'-=' + bubbleHeight}, 2000);
}
bubble[bubbleFirst].css('top', '600px');//put elements moving off top to bottom
//resetBubbles();
bubbleFirst++;
if(bubbleFirst >= bubble.length) bubbleFirst = 0;//bubbles have looped
bubbleTimer = setTimeout(function(){animateBubbles();}, bubbleTimeDelay);//start looping again
}
bubble1 starts with top: 0px;
bubble2 starts with top: 200px;
bubble3 starts with top: 400px;
bubble4-6 start with top: 600px;
all are position: absolute in a wrapper div
Apologies for the code dump. My problems are all centered around line 16:
bubble[bubbleFirst].css('top', '600px');
This code is seemingly never executed, there is no error in my console and I have verified that bubble[bubbleFirst] is returning the correct element using console.log. (It's a div)
I'm currently using a workaround, but it is not dynamic:
function resetBubbles(){
/*bubble[bubbleFirst].css('top', '600px');//put elements moving off top to bottom*/
if(bubble[0].css('top') == '-200px') bubble[0].css('top', '600px');
if(bubble[1].css('top') == '-200px') bubble[1].css('top', '600px');
if(bubble[2].css('top') == '-200px') bubble[2].css('top', '600px');
if(bubble[3].css('top') == '-200px') bubble[3].css('top', '600px');
if(bubble[4].css('top') == '-200px') bubble[4].css('top', '600px');
if(bubble[5].css('top') == '-200px') bubble[5].css('top', '600px');
}
I have no idea why this isn't working, it's probably a logical error on my part. But I can't for the life of me find it. Any help would be appreciated. Thanks for your time.
Is it possible that the call to animate conflicts with you custom settings the top property? ie. you set it, but top is immediately altered again by animate. You can pass a callback to animate that will run when the animation has finished. That's when you should reset your bubble position.
function animate_bubble(index) {
bubble[index].animate({ top: "0px" }, 2000 /* 2 seconds */, function () {
bubble[index].css({ top: "600px" });
animate_bubble(index);
}
}
animate_bubble(0);
animate_bubble(1);
// etc .. probably do this in a for-loop
You'll need to find some way to cancel the animation though, shouldn't be too hard.
The problem was that bubbleFirst was incremented before the animation was finished. I changed my function to the following:
function animateBubbles(){
clearTimeout(bubbleTimer);//stop from looping before this is finished
for(var i = 0; i < visibleBubbles + 1; i++){
count = i + bubbleFirst;
if ( count >= bubble.length ) count = count - bubble.length;//keep index inside array
if (count == bubbleFirst)
{
bubble[count].animate({top:'-=' + bubbleHeight, opacity: 0}, bubbleAnimationSpeed, function(){
bubble[bubbleFirst].css('top', displayHeight+'px');
bubble[bubbleFirst].css('opacity', '1');
});
}
else if(i == visibleBubbles)
{
bubble[count].animate({top:'-=' + bubbleHeight}, bubbleAnimationSpeed, function(){
bubbleFirst++;
if(bubbleFirst >= bubble.length) bubbleFirst = 0;//bubbles have looped
bubbleTimer = setTimeout(function(){animateBubbles();}, bubbleTimeDelay);/*start looping again*/
});
}
else bubble[count].animate({top:'-=' + bubbleHeight}, bubbleAnimationSpeed);
}
}
Thanks for your input guys!

Categories