Jump to content
Search Community

Best way to cycle images?

garyw test
Moderator Tag

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

Recommended Posts

We're trying to use TimelineLite to create a cycle of images. We want to show one image at a time, fade between them, and at the end, cycle back to the first one and repeat. We are getting various results on different browsers. On some, it works fine. On others (*cough* IE8 *cough*), we occasionally see a cut between images instead of a fade. Other times, the wrong image appears.

 

Our images are set up absolutely positioned at the top left in a <div>; the first image is visible immediately; the rest are styled as visibility:hidden.

 

What's the best algorithm for doing this using GSAP, given an arbitrary number of <img> tags (we're using jQuery, too)? We've tried a couple of ways, but the code for such a seemingly simple task gets complex quickly.

  • Like 1
Link to comment
Share on other sites

Do you mean like this?

 

var images = $('img');
var timeline = new TimelineMax({repeat:-1});
timeline.append(TweenMax.staggerTo(images, 1, {css:{autoAlpha:1}, repeat:1, yoyo:true, repeatDelay:.5}, 2.5))
 

 

Live Demo: http://jsfiddle.net/geekambassador/w8MnU/

 

The meat of that effect is in a single staggerTo() that will fade each image in, pause, and then fade out in sequence.

 

It does that by creating a tween for each image that will fade out and then repeat once in reverse after the repeatDelay has transpired.

 

By appending that staggerTo() to a TimelineMax you can set the entire sequence to repeat any number of times

 

EDIT IN 2017: You should never use append() to get a staggered animation in a timeline. Use TimelineLite or TimelineMax's .staggerTo() and it is also not necessary to use the css {} wrapper object either:

 

timeline..staggerTo(images, 1, {autoAlpha:1, repeat:1, yoyo:true, repeatDelay:0.5}, 2.5)

 

  • Like 1
Link to comment
Share on other sites

Hmm.. I only see the glitch in Chrome 21. Here's the routine I set up:

 

var cycleImages = function(selector, duration) {

var $images = $(selector);

if ($images.length == 0)
	return;

this.timeline = new TimelineMax({repeat:-1, repeatDelay:duration});
this.timeline.append(TweenMax.staggerTo($images, 0.5, {css:{autoAlpha:1}, repeat:1, yoyo:true, repeatDelay:duration}, 0.5 + duration));
this.timeline.play();
};

  • Like 1
Link to comment
Share on other sites

Are you saying the code I provided is causing a glitch? or your implementation is causing a glitch?

 

If you can confirm that my version is glitchy, that gives us a much better starting point for trouble-shooting. Or feel free to post a version that we can test.

 

Either way, I'm using Chrome 21 on Mac and my code does not do anything unexpected. :|

 

Keep in mind you altered your code to do a cross-fade where as my fades ran in sequence.

If you want to cross-fade the last image with the first image it gets trickier.

 

You need to append another tween that fades the first image in while the last image is fading out. You then need to append another tween that has the second image fading in while the previous image is fading out. Then you need to go back to the beginning of the timeline and find the exact point that the first and second image intersect.

 

The point is it is impossible to cross-fade the last item in a sequence with the first item in the sequence as those transitions happen at different points in time. A bit of trickery is involved if in fact you seamlessly want to loop a bunch of images cross-fading with each other.

 

The timeline would have the following tweens (where > means cross-fades to)

 

a: img1 > img2

b: img2 > img3

c: img3 > img4

d: img4 > img1

e: img1 > img2

 

when tween e is halfway through you need to jump back to the halfway point of tween a

 

If you can live with the last image fading completely out before the sequence starts again, its obviously much easier.

 

If you continue to experience odd behavior, let us know.

  • Like 1
Link to comment
Share on other sites

You got to the crux of the problem... we need to have a cross-fade between the last and first items, so that it is a seamless infinite loop. Technically, the outgoing image doesn't need to tween at all... if it's behind the oncoming image, the outgoing image can just pop off once the oncoming image fades on over it. Because of z-index issues, though, the cross-fade may be necessary,

  • Like 1
Link to comment
Share on other sites

  • 3 years later...

Did you find this thread in search results for "cycle" and "gsap"? I did.

 

I know this thread is super old, but I've been working on a similar problem recently that requires a solve for what Carl and garyw were mentioning just above.

 

We are entering the age of HTML5 Banners, and this topic is applicable as a foundation for cycling HTML5 banners.

 

The challenge is to continously loop (crossfading, in this case) through an array of images, and when you reach the end, have the last element crossfade back to the first element seamlessly and then repeat...

 

My solution uses plain javascript to 'cut' the first item from that array (making the rest of the array shift left one space) and then 'paste' that first item at the end of the array.

 

Repeatedly crossfading only the first two items in the array ( 0 and 1 ), then doing the cut/paste to the array results in a continuous cycle that never has to 'restart' between the last item and first items...because it never reaches the end!

 

Setup CSS:

#imgcontainer {
  position:relative;
}

#imgcontainer img {
  position:absolute;
  top: 0;
  left: 0;
  opacity: 0;
}

#imgcontainer img:first-child {
  opacity:1;
}

This css sets up a container (#imgcontainer) to hold all the images, makes the images stack in front of each other, and makes them all transparent except the first one.

 

Javascript:

var imgs = $.makeArray( $('#imgcontainer img') ) 

function crossfade(){
    TweenMax.to(imgs[0], 0.5, {css:{autoAlpha:0}}) 
    TweenMax.to(imgs[1], 0.5, {css:{autoAlpha:1}}) 
    imgs.push( imgs.shift() )
  }

var cycle = setInterval(crossfade,3000)

The first line uses jquery's makeArray to create an array of references to all the images inside the designated container. If you aren't using jquery, this can be done by defining a traditional javascript array of individual document element references for each of the images.

 

Next, we define a crossfade function. Inside the crossfade function, two TweenMax calls are used to fade out the first image (which would be the one that is initally opaque), while fading in the second one. They happen synchronously. You can add a small delay to the fade out call to make sure the new image is almost showing before the old one disappears, or you can adjust the speed of the two animations to your liking.

 

At the end of the crossfade function, the array is cycled left using the javascript push() and shift() methods. The push() method "pastes" something new onto the end of the array. And in this case, that something is the first element of the array which we have "cut" from the beginning using the shift() method. I have found this array push/shift combo to be useful in games where you want to seamlessly cycle through a sequence of elements multiple times.

 

Finally, the 'crossfade' function is set to repeat every 3 seconds using setInterval(). Each call represents an individual 'slide' in the slideshow or 'frame' in the banner.

 

GSAP HTML5 BANNER LOOPING:

Here's how the above Javascript would look if you wanted to limit the number of 'loops' of the whole sequence:

var framesShown = 0
var loops = 3 // limit to three loops of all the frames
var imgs = $.makeArray( $('#imgcontainer img') ) 
var framesLimit = imgs.length * loops

function crossfade(){
    TweenMax.to(imgs[0], 0.5, {css:{autoAlpha:0}}) 
    TweenMax.to(imgs[1], 0.5, {css:{autoAlpha:1}}) 
    imgs.push( imgs.shift() )
    
    framesShown++
    if (frameShown == framesLimit){
        window.clearInterval(cycle)
    }
  }

var cycle = setInterval(crossfade,3000)

NOTE: You could set the framesLimit variable to any number so the banner can 'end' on the first or last or a middle frame. In that case just disregard the line where "loops" is defined.

  • Like 4
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...