JS Image Transition Not Working - javascript

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.

Related

Looping Arrays to Change Background Image of Div

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.

If else statements to check and see if a certain img tag is appended to div wont execute

I need to check if a div called 'ContainterTwo' has either an image with the class 'hd' or 'tl' appended to it, but my if else block never get executed. The images are html img tags inside an array called 'image'. I use a random generator to stimulate a coin flip.
$(document).ready(function(){
var image = ['<img src="heads.jpg" class="hd" height="50" width="50">', '<img src="tails.jpg" class="tl" height="50" width="50">'];
$('#flip').on('click', function(){
var heads = 0;
var tails = 0;
var numToFlip = parseInt($('#number').val().trim());
for(var x = 0; x < numToFlip; x++)
{
var ran = Math.round(Math.random() * (1)) + 0;
$('.ContainerTwo').append(image[ran]);
if($('.ContainerTwo').hasClass('hd'))
{
heads++;
$('.spOne').html(heads);
$('.ContainerTwo').empty();
}
else if($('.ContainerTwo').hasClass('tl'))
{
tails++;
$('spTwo').html(tails);
$('.ContainerTwo').empty();
}
}
})
})
try this,
if($('.ContainerTwo').find('img').hasClass('hd'))
{
heads++;
$('.spOne').html(heads);
$('.ContainerTwo').empty();
}
else if($('.ContainerTwo').find('img').hasClass('tl'))
{
tails++;
$('spTwo').html(tails);
$('.ContainerTwo').empty();
}
You can check the random value of variable ran.
I have added some code refactor and removed unnecessary variables and moved jQuery variable declarations out of the loop to improve performance.
Code:
$(document).ready(function () {
$('#flip').on('click', function () {
var heads = 0,
tails = 0,
numToFlip = parseInt($('#number').val().trim()),
$spOne = $('.spOne'),
$spTwo = $('spTwo');
for (var x = 0; x < numToFlip; x++) {
var ran = Math.round(Math.random() * (1)) + 0;
(ran === 0) ? $spOne.html(++heads): $spTwo.html(++tails);
}
});
});
Notice that have been removed the image variable because you are doing: $('.ContainerTwo').append(image[ran]); and after that you are doing $('.ContainerTwo').empty();
You can check if multiple class exists with the is() function. You can check all your .ContainerTwo class with each() and compare with your own variable. Try below
var containerTwo = $('.ContainerTwo img'); //All img in your element
containerTwo.each(function(i,e){ //Check all img in all containerTwo element in page
if($(this).is('.hd, .tl')){ // If .hd or tl found
console.log($(this).attr("class"))
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="ContainerTwo">
<img class="hd" src="http://img.freepik.com/icones-gratuites/instagram-logo_318-84939.jpg?size=338c&ext=jpg"/>
<img class="tl" src="http://img.freepik.com/icones-gratuites/facebook-logo-bouton_318-84980.jpg?size=338c&ext=jpg"/>
<div>
<div class="ContainerTwo">
<img class="hd" src="http://img.freepik.com/icones-gratuites/instagram-logo_318-84939.jpg?size=338c&ext=jpg"/>
<img class="tl" src="http://img.freepik.com/icones-gratuites/facebook-logo-bouton_318-84980.jpg?size=338c&ext=jpg"/>
<div>

How to set up "stop" after setInterval() method?

i have image gallery ant i set up setinterval, now i want that it should be stopped after two or tree circle.
This is my html Code:
<div id="slider">
<img src="http://imgsrc.hubblesite.org/hu/gallery/db/spacecraft/24/formats/24_web.jpg">
<img src="http://imgsrc.hubblesite.org/hu/gallery/db/spacecraft/27/formats/27_web.jpg">
<img src="http://imgsrc.hubblesite.org/hu/gallery/db/spacecraft/32/formats/32_web.jpg">
<img src="http://imgsrc.hubblesite.org/hu/gallery/db/spacecraft/33/formats/33_web.jpg">
</div>
css:
#slider {
width: 400px;
height: 300px;
position: relative;
overflow: hidden
}
#slider img {
position: absolute;
top: 0;
left: 0;
opacity: 0;
transition: 0.25s
}
and Javascript:
var pics;
var current = 0; // first next() moves to pics[0], the first image
window.addEventListener("load", function() {
pics = document.querySelectorAll("#slider img");
});
setInterval(function() {
var nextImage = (current + 1) % pics.length;
pics[current].style.opacity = 0;
pics[nextImage].style.opacity = 1;
current = nextImage;
}, 3000);
Here's your answer: Stop setInterval call in JavaScript
Save the interval ID when you create it, keep track of the number of times your slides have rotated, and then cancel the interval.
Use a counter variable to track the number of cycles & clear the timer based on that limit value.
JS Code:
var counter = 0;
var limit = 3 ;
var timer;
timer =setInterval(function () {
if(counter === 3){
clearInterval(timer);
return;
}
counter++;
//do some stuff here after 1 second delay
},1000);
You could use setTimeout instead.
var pics;
var current = 0; // first next() moves to pics[0], the first image
var stop = 3; //define when you want to stop
window.addEventListener("load", function() {
pics = document.querySelectorAll("#slider img");
});
function switchImage()
{
var nextImage = (current + 1) % pics.length;
pics[current].style.opacity = 0;
pics[nextImage].style.opacity = 1;
current = nextImage;
stop--;
if(stop != 0)
setTimeout(switchImage,3000);
}
setTimeout(switchImage,3000);
You can do like this.
var refreshIntervalId = setInterval(function() {
var nextImage = (current + 1) % pics.length;
pics[current].style.opacity = 0;
pics[nextImage].style.opacity = 1;
current = nextImage;
}, 3000);
clearInterval(refreshIntervalId);

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!

Clear a non-global timeout launched in jQuery plug-in

I try to set a timeout on an element, fired with a jQuery plugin. This timeout is set again in the function depending on conditions. But, I want to clear this element's timeout before set another (if I relaunch the plug-in), or clear this manually.
<div id="aaa" style="top: 0; width: 100px; height: 100px; background-color: #ff0000;"></div>
Here's my code (now on http://jsfiddle.net/Ppvf9/)
$(function() {
$('#aaa').myPlugin(0);
});
(function($) {
$.fn.myPlugin = function(loops) {
loops = loops === undefined ? 0 : loops;
this.each(function() {
var el = $(this),
loop = loops,
i = 0;
if (loops === false) {
clearTimeout(el.timer);
return;
}
var animate = function() {
var hPos = 0;
hPos = (i * 10) + 'px';
el.css('margin-top', hPos);
if (i < 25) {
i++;
} else {
if (loops === 0) {
i = 0;
} else {
loop--;
if (loop === 0) {
return;
} else {
i = 0;
}
}
}
el.timer = window.setTimeout(function () {
animate();
}, 1000/25);
};
clearTimeout(el.timer);
//$('<img/>').load(function() {
// there's more here but it's not very important
animate();
//});
});
return this;
};
})(jQuery);
If I make $('#element').myPlugin();, it's launched. If I make it a second time, there's two timeout on it (see it by doing $('#aaa').myPlugin(0);
in console). And I want to be able to clear this with $('#element').myPlugin(false);.
What am I doing wrong?
EDIT :
SOLVED by setting two var to access this and $(this) here : http://jsfiddle.net/Ppvf9/2/
try saving the timeout handle as a property of the element. Or maintain a static lookup table that maps elements to their timeout handles.
Something like this:
el.timer = window.setTimeout(...);
I assume you need one timer per element. Not a single timer for all elements.

Categories