Search code examples
javascriptjqueryanimationtimelinegsap

GSAP timeline animation


I am trying do clock animation using gsap. the thing is that my actual script is not precise. What i need is:

  • pressbutton
  • start animation (full hour spin)
  • than pressbutton again stop it wait 2 sec and keep doing that
  • simply start -> spin -> stop (2 sec delay) -> repeat

My actual solution not working because after some time its not stopping minute hand on 12 hour (probably its desynchronising itself because setInterval or setTimeout is not so accurate.

How i can solve this with proper solution. Maybe timeline inside timeline somehow?

Link to CodePen

Actual script:

var gsapClock = (function ($) {
var s;
return {
settings:      {
  $minuteHand: $('#minute-hand'),
  $hourHand:   $('#hour-hand'),
  $buttonTop:   $('#button-top')
},
init:function () {
  s = this.settings;
  this.bindUIActions();
},
bindUIActions: function () {

  var tl = new TimelineMax();
  function buttonPress(){
    TweenMax.to(s.$buttonTop, .1, {
      y: 4
    });
    TweenMax.to(s.$buttonTop, .1, {
      y: 0,
      delay: .1
    })
  }


  tl.add(
    TweenMax.to(s.$minuteHand, 2, {rotation: "360", repeat: -1, ease: Power0.easeNone, transformOrigin: '50% 100%'}),
    TweenMax.to(s.$hourHand, 48, {rotation: "360", repeat: -1, ease: Power0.easeNone, transformOrigin: '0% 50%'})
  );
  tl.pause();

  function animationControll() {
    buttonPress();
    tl.resume();
    setTimeout(function() {
      buttonPress();
      tl.pause();
    }, 2000);
  }

  animationControll();
  setInterval(function() {
    animationControll();
  }, 3500);
}
}
})(jQuery);

gsapClock.init();

Solution

  • Here's how I'd probably do it (there are many ways):

    var gsapClock = (function ($) {
      var s;
      return {
        settings:      {
          $minuteHand: $('#minute-hand'),
          $hourHand:   $('#hour-hand'),
          $buttonTop:   $('#button-top')
        },
        init:function () {
          s = this.settings;
          this.bindUIActions();
        },
        bindUIActions: function () {
    
          var tl = new TimelineMax();
    
          //make it easier to play with the timing:
          var durations = {press:0.1, minute:2, hour:48, pause:2};
    
          //since we want to stop the hour hand motion each time the minute hand goes around, it's easiest to just put it in its own tween so we can pause()/resume(). This could easily be a timeline if you prefer. 
          var hour = TweenMax.to(s.$hourHand, durations.hour, {rotation: 360, repeat: -1, ease: Power0.easeNone, transformOrigin: '0% 50%'});
    
          //put the button press into its own repeating timeline
          var buttonPress = new TimelineMax({repeat:-1, repeatDelay:durations.minute - (durations.press * 2)});
          //when the button is fully depressed, pause the "hour" tween. We do a repeat:1, yoyo:true as a simple way to make the button return to its original position rather than using two tweens (down, then up)
          buttonPress.to(s.$buttonTop, durations.press, {y:4, repeat:1, yoyo:true, onRepeat:function() {hour.pause();}});
    
          //the 2nd time the button is depressed, resume() the hour timeline. 
          buttonPress.to(s.$buttonTop, durations.press, {y:4, repeat:1, yoyo:true, onRepeat:function() {hour.resume();}}, durations.pause);
    
          //main timeline - do the repeating minute hand animation that's repeated. Notice the repeatDelay is used for the appearance of pausing. 
          tl.to(s.$minuteHand, durations.minute, {rotation: "360", repeat: -1, repeatDelay:durations.pause, ease: Power0.easeNone, transformOrigin: '50% 100%'});
    
          //nest the buttonPress timeline at exactly the right spot.
          tl.add(buttonPress, durations.minute - durations.press);
        }
      }
    })(jQuery);
    
    gsapClock.init();
    

    Codepen: http://codepen.io/GreenSock/pen/GWqddB?editors=0010

    Is that the effect you were after?