Search code examples
javascriptjquerygsap

Greensock fading in and out on background image change


I have never used GreenSock before. The background image changes fine, it switches and scales in and out however the issues I am facing are as follows:

  1. The first background image on the sprite to show does not scale in and out but all the others do, how can I fix this?
  2. It seems to change the background then scale in and out. So there is a small delay between the changing of the background image and the start of scale animation. Is there anyway to tighten this up so it scales as its changed to make it a more smoother transition?

JavaScript:

// Avatar animations
var avatarInterval;
var fadePulse           = true; // true: will fade avatar images and pulse in and out once changed
                                // false: will slide the avatars in and out 
var avatarCount         = 11;   // set the amount of avatars in the sprite image
var avatarSpeed         = 1000; // set the avatar transition speed
var avatarHeight        = 250;  // set the height of a single avatar image
var avatarTotalHeight   = 2750; // set the total height of the avatar sprite image

function startAvatarAnimation() {
    var i = 0;
    $(".avatars").show();

    // Loop through avatar background images on sprite
    avatarInterval = setInterval(function(){
        i++;
        if(i > avatarCount){
            i = 0;
        }

        // Let's change the background
        $(".avatars").css({'background-position' : '0 -' + (i*avatarHeight) + 'px' });

        // avatar fading / pulse effect
        if (fadePulse == true) {
            // Now some scaling effects!
            TweenMax.to(avatars, 0.1, {
                css: {
                    // 'background-position': '0 -' + (i*avatarHeight) + 'px',
                    scaleX: 1.1,
                    scaleY: 1.1,
                    transformOrigin: "center center"
                },
                        onComplete: scaleOut,
                    onCompleteParams: [avatars],
                delay: 0.1,
                ease: Power3.easeInOut
            });

            // Bring the scale back to normal
            function scaleOut(el) {
                TweenMax.to(el, 0.1, {
                    css: {
                        scaleX: 1.0,
                        scaleY: 1.0,
                        transformOrigin: "center center",
                        autoAlpha: 1,
                    },
                    ease: Power2.easeOut
                });
            }
        } else {
            // avatar sliding effect
        }

    }, avatarSpeed);

    return false;
}

Solution

  • Take a look at this result.

    Snippet:

    var avatarCount = 6;
    var avatarHeight = 250;
    var avatarTotalHeight = 1500;
    var avatars = $(".avatars");
    var animDuration = 0.1;
    var i = 0;
    var timeline = new TimelineMax({ paused: true, repeat: -1 });
    timeline.to(avatars, animDuration, {
      scaleX: 1.1,
      scaleY: 1.1,
      ease: Power3.easeIn,
      onComplete: onCompleteScaleIn
    });
    timeline.to(avatars, animDuration, {
      scaleX: 1.0,
      scaleY: 1.0,
      ease: Power3.easeOut
    });
    
    function onCompleteScaleIn() {
      i++;
      i = i >= avatarCount ? 0 : i;
      TweenMax.set(avatars, {
        backgroundPosition: '0 -' + (i * avatarHeight) + 'px'
      });
    }
    
    timeline.play();
    #container {} #container,
    .section {
      overflow: hidden;
      position: relative;
    }
    .section {
      position: absolute;
    }
    #container .logo_o2 {
      bottom: 10px;
      right: 20px;
    }
    .section {
      position: relative;
      height: 250px;
      width: 300px;
      display: block;
    }
    .section .abs {
      position: absolute;
    }
    .section h1,
    .section h2,
    .section h3,
    .section h4 {
      font-size: 21px;
      width: 100%;
      text-align: center;
      letter-spacing: 0;
    }
    .section1,
    .section2,
    .section3,
    .section4,
    .section5,
    .section6 {} .avatars {
      background-image: url(http://s1.postimg.org/dwt9yu9b3/test_bg_sprite.png);
      background-repeat: no-repeat;
      background-size: cover;
      display: block;
      height: 250px;
      width: 300px;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <script src="http://cdnjs.cloudflare.com/ajax/libs/gsap/latest/TweenMax.min.js"></script>
    <div class="section section3">
      <div class="abs clouds"></div>
      <div id="avatars" class="abs avatars"></div>
    </div>

    Details:

    • First off, this result could have been achieved in a number of ways, more efficiently. Even within TweenMax there could have been a number of possible solutions. So, this attempt is in no way supposed to be the best.
    • Because you are already using GSAP; I have used TimelineMax, TweenMax's powerful cousin that makes sequencing of animations very easy.
    • So we have a timeline variable which carries an instance of TimelineMax object with default settings of: 1. initially paused and 2. indeterminate loops.
    • We then populate this timeline by using the method .to() which basically will start animation from wherever the object currently is. There are a plethora of methods and properties available for the GSAP platform, you should explore.
    • On the first line of .to() call, we have an onComplete callback pointing to a function.
    • This callback adjusts the backgroundPosition as per the current iteration.
    • Finally, there is another .to() call which does the same i.e. start the animation from whatever attributes avatars object currently possesses (in our case, scaleX & scaleY would be at 1.1 because of the first .to() call).
    • Note: by default, any new .to() (or .from() or .fromTo()) call is appended at the end of a timeline. Read more about the position parameter here.

    Let me know if you have any questions.

    Update: Here is another version using TweenMax only. Much leaner I guess.