Jump to content
Search Community

timeline play(label) skips function added immediately after label

Ben O 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

Below is a snippet of part of a timeline I building using TimelineLite. There are parts before and after this sequence but this one part is giving me some trouble:

 

  timeline.insertMultiple(
   [
	  'discharge',

	  function () {charge.hide();},

	  TweenLite.to(wave, 0.25, {
			 ease: Linear.easeNone,
			 raphael: {
				 r: 1,
				 'fill-opacity': 0,
				 'stroke-width': 1
			   }
		 }),
   ], 0, 'sequence', 0);

 

If I call timeline.play('discharge'), the function is not called - only the tween runs. I have functions in the timeline in other places but they are always after the animation and run as expected.

 

The only way I could get this to work was to move the function to the onStart callback of the animation:

 

  timeline.insertMultiple(
   [

	  'discharge',

	  TweenLite.to(wave, 0.25, {
			 ease: Linear.easeNone,
			 raphael: {
				 r: 1,
				 'fill-opacity': 0,
				 'stroke-width': 1
			   },
			 onStart: function () {charge.hide();}
		 }),

   ], 0, 'sequence', 0);

 

Is there something I'm missing to make this work. My first thought was that I'm adding two 0 duration items to the timeline and the playback is just starting at the first item with a real duration. I don't mind using the onStart callback but I was trying to see how flat I could keep this so I can see the sequencing of the all the processing in a consistent fashion.

 

If anyone has ideas/alternatives, I'd be interested in your thoughts.

 

I can provide a link to the full source and/or working demo if needed.

Link to comment
Share on other sites

Have you tried timeline.play('discharge', false)?

 

Notice the "false" for the suppressEvents parameter. By default, it's true which means any events that would normally get triggered when the playhead moves from wherever it is to the new position. Think of it like a record player whose needle gets picked up and dropped in a new spot rather than getting dragged across the record.

 

Another option would be to use a basic VERY SHORT tween with an onComplete instead of a normal zero-duration callback. For example, TweenLite.to(yourFunction, 0.0001, {onComplete:yourFunction}). That way, when the playhead gets moved to the label, it's not directly on top of the callback, thus the callback doesn't get suppressed. Then, as soon as the playhead starts moving forward from that spot, it hits the tween and calls its onComplete.

 

Make sense now?

 

There are a few other options too, but I don't want to overwhelm you :) I suspect that setting the suppressEvents parameter of play() to false will solve the issue for you.

Link to comment
Share on other sites

I think I might need to add some additional context. Here's the whole timeline array:

 

  timeline.insertMultiple(
   [
	  'charging',
	  function ()
	   {
		  wave
			 .attr('fill', 'white')
			 .attr('fill-opacity', 0.4)
			 .attr('stroke-opacity', 0.3)
			 .show();
	   },
	  TweenLite.fromTo(wave, 0.5, {
			 raphael: {
				 r: 1,
				 'stroke-width': 1
			   }
		 }, {
			 ease: Linear.easeNone,
			 raphael: {
				 r: MAX_R,
				 'stroke-width': 5
			   }
		 }),
	  function () {charge.show();},

	  'charged',
	  TweenLite.fromTo(charge, 0.5, {
			 raphael: {
				 r: 1,
				 'fill-opacity': 0.8
			   }
		 }, {
			 ease: Linear.easeNone,
			 raphael: {
				 r: MAX_R,
				 'fill-opacity': 0.05
			   }
		 }),
	  function () {timeline.play('charged')},
	  'discharge',
	  function () {charge.hide();},
	  TweenLite.to(wave, 0.25, {
			 ease: Linear.easeNone,
			 raphael: {
				 r: 1,
				 'fill-opacity': 0,
				 'stroke-width': 1
			   }
		 }),

	  'pulse',
	  (pulse = TweenLite.fromTo(wave, 0.15, {
			 raphael: {
				 r: 1,
				 'stroke-width': 1,
				 'stroke-opacity': 0.3
			   },
		 }, {
			 ease: Linear.easeNone,
			 raphael: {
				 r: 1000,
				 'stroke-width': 100,
				 'stroke-opacity': 0.1
			   }
		 })),
	  function ()
	   {
		  charge.hide();
		  wave.hide();
		  pulse_x = -1;
		  pulse_y = -1;
	   }
   ], 0, 'sequence', 0);

 

A mouse event starts the animation with timeline.play('charging'). Right after the charging label, there is a function which does execute. The animation continues until the function right before the discharge label. This function loops the animation indefinately until another mouse event runs timeline.play('discharge'). That's where the function call gets skipped.

 

I tried timeline.play('discharge', false), but then the looping part just kept going. I'm going to keep experimenting but wanted to know if there was anything obviously wrong with how I built the timeline that would case the problem I'm experiencing.

Link to comment
Share on other sites

Ah yes, if you think about the record player analogy, it sounds like the needle is dragging across your callback that does the looping when you play('discharge', false), so when you don't suppressEvents, it's getting triggered. See what I mean?

 

So in that case, my second recommendation should work fine. The whole idea is to make the playhead move to a position right before the callback (not exactly on top of it). It could be 0.001 seconds before - as long as it's before, you're golden. So either offset your callback slightly or leave it where it is and make the playhead go to just before the label, like:

 

timeline.play( timeline.getLabelTime('dischage') - 0.001 );

 

Do you see why that would work?

Link to comment
Share on other sites

Well, I got it to work by pushing everything after the discharge label into a nested timeline:

 

 ...
 'discharge',

 new TimelineLite({
   align: 'sequence',
   tweens: [

	  function () {console.log(1); charge.hide();},

	  TweenLite.to(wave, 0.25, {
			 ease: Linear.easeNone,
			 raphael: {
				 r: 1,
				 'fill-opacity': 0,
				 'stroke-width': 1
			   }
		 }),
  ...

 

I considered doing this anyways to group each part, however, it would be nice if the other method worked as expected too.

Link to comment
Share on other sites

Here's the conundrum: a callback has no duration (think of it like a zero-duration tween with an onComplete), and normally it is played as soon as the playhead lands on (or goes past) that particular spot on the timeline, but if you suppressEvents on the play(), then it wouldn't (and shouldn't) get called. Then when the playhead start advancing from that spot, it shouldn't then trigger the callback again otherwise the logic would actually cause it to get called twice during normal operation (when it arrives on that frame AND when it leaves that frame).

 

See the logic issue? I totally understand why you'd expect it to play intuitively in your scenario, it just exposes a logic conundrum that isn't apparent to most people.

Link to comment
Share on other sites

 

timeline.play( timeline.getLabelTime('dischage') - 0.001 );

 

 

When I try that, it got stuck in the looping again.

 

My issue seems to be that there are 3 zero length animation clumped together. Trying to set the playhead just before discharge causes it to be before the function that loops:

 

	  function () {timeline.play('charged')},
	  'discharge',
	  function () {console.log(1); charge.hide();},

 

I found another solution that keeps my original timeline intact. I staggered the whole timeline by 0.001 seconds with the insertMultiple call:

 

...

  ], 0, 'sequence', 0.001);

 

Now, I can call timeline.play('discharge') and the function is getting called.

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...