Jump to content
Search Community

Stopping And restarting timeline onclick

Chromium test
Moderator Tag

Go to solution Solved by OSUblake,

Recommended Posts

Yes, I have looked at the https://greensock.com/mistakes which illustrates my exact problem in the CodePen. I've also looked at many related forum posts... but you know what? I just don't get it at this point. I don't get how something that seems so simple can be so daunting to achieve.

 

As can be seen in the CodePen, there's a button which triggers an animation onclick. Spam the button 3 times in a couple seconds however, and the whole thing gets stuck! The article mentioned above makes it sound like the simple solution to this is to do a "fromTo" as opposed to a "from" or a "to" for the timeline's tweens (and by the way, what about "set" in this case?)... and I changed my timeline's tweens to exactly that... but alas, the problem still occurs.

 

I know there are a bunch of ways to solve this particular problem; even though I can't seem to get even one working for me... Ideally, I'd like to achieve the following:

  1. The timeline should immediately stop and restart from the very first tween whenever the button is clicked. Yes, that means I don't care where it has reached at that point, I'd like it to restart.
  2. If I have clicked the button 3 times, the first and second animations should be overwritten by the 3rd. In other words, I expect to only see one full timeline animation after my last button click.
  3. Most of the solutions I've read in the other forum posts, approached the problem by setting the timeline to a variable outside of the onclick handler. Well if this is the only way to achieve what I like, then I can accept it. But ideally, I'd like to keep all the handling inside of the onclick handler so if we can do this while still keeping the timeline variable accessible only by the handler, that would be great.

 

That being said, the closest I've gotten to at least stop the freezing animation from happening is when I simply moved everything that is currently inside of the click handler outside of it, and then only added t1.restart() inside the click handler. However, this resulted in unexpected behavior... when I spam clicked the button 3 times, while it successfully broke out of the first and second timeline animations, it actually still played all 3 timeline animations consecutively. In other words, after I stopped clicking the button, I still got to watch the animation 3 times when I only expected to see one animation for my last click. I think I'm close to getting it to behave as I want it to in this setup but this wouldn't achieve objective #3 from my list above. So if there's a better way that would allow me to keep everything to the click handler, I'd rather do that.

See the Pen mdpzJrB by fuad-zeyad-tareq (@fuad-zeyad-tareq) on CodePen

Link to comment
Share on other sites

Hi Chromium,

 

Creating your animations outside of the handler is usually the best idea. Every time you click on that button, you are creating a brand new SplitText instance and also a timeline. Animations from the previous click's timeline could still be running because you didn't kill them, so you're going to create conflicts, and that includes that onComplete which reverts the SplitText.

 

 

See the Pen VwyqOaZ by GreenSock (@GreenSock) on CodePen

 

Another variation of what you were trying, but I'm forcing the previous to completion.

 

See the Pen eYybazj by GreenSock (@GreenSock) on CodePen

 

  • Like 3
Link to comment
Share on other sites

Right on Blake! Thanks for the quick response and the examples!

 

It actually seems like my entire problem is resolved once I initialize the timelines outside of the click handler like you suggested. It doesn't even seem necessary to force .progress(1) for some reason.

 

However, this doesn't really address the main problem I'm truly trying to wrap my head around. What I'd ideally like to achieve is some component isolation... is it simply impossible to reference a gsap timeline from a jQuery object/DOM element?

 

For example, I have a function, let's call it animateFunc(). This function gets called twice, once on page load, and the second time inside the onclick of a button. In the first call, the function initializes the timeline (let's call it t1) and its tweens in a paused state. When animateFunc() is called via the onclick (it knows this via a special parameter), it will trigger only a t1.restart() and return. The main problem I'm running into here (as you can probably guess) is that the timeline is undefined when the animateFunc() is called via the onclick.

 

Now there are multiple ways to solve this, such as:

  1. Initializing the t1 variable outside of the animateFunc(). However, I'd rather avoid this due to my previously mentioned reasons.
  2. Making animateFunc() return the t1 variable and then providing that t1 variable back to the animateFunc() when it is called through the onclick. Again, I'd like to avoid this because I'd like to keep the animateFunc() uncoupled from any dependencies from the main JS.

Which brings me to what I'm looking for as a solution that I can't seem to find, ideally I can think of 2 options:

  1. In the first call to animateFunc(), I'd attach the t1 variable to the jQuery object/DOM element so that I can access it again when the animateFunc() is called via the onclick. I suspect this is not possible as I found no mention of such thing anywhere.
  2. This one is less ideal, but I create some sort of object to keep track of the timelines and attach it to maybe the gsap object somewhere? I'm just spitballing at this point and I have no idea if this is the right way to go about this haha.

 

EDIT: Here's a sample CodePen of what I mean:

See the Pen QWazXMo by fuad-zeyad-tareq (@fuad-zeyad-tareq) on CodePen

Link to comment
Share on other sites

7 minutes ago, Chromium said:

It actually seems like my entire problem is resolved once I initialize the timelines outside of the click handler like you suggested. It doesn't even seem necessary to force .progress(1) for some reason.

 

I'd still keep that in there. Like I said earlier, those previous are still going to be running. So if you spam it 10 times, there are going to 10 unique animations running, even though you're only going to be seeing the effects from the last timeline. 

 

I'm not I understand the rest of your last post. Can you make a demo showing what you're having problems with. Normally if you're trying to make a component, you would use a class or a function that returns an API.

 

Link to comment
Share on other sites

I've edited my previous response with a CodePen demonstrating my example. It will not run because t1 is undefined when the function is called via the onclick handler. I'm looking to solve this problem without resorting to globalizing the t1 variable outside the function or returning it to the main JS code. I'm hoping there is a better way such as the alternative solutions I mentioned in my last response.

Link to comment
Share on other sites

10 minutes ago, OSUblake said:

You can't call the same function like that

JQuery has something called plugins ($.fn.insertCustomPluginHandlerHere()) that gets called that way all the time so I'm not sure I understand why this is a problem?

 

59 minutes ago, Chromium said:
  • In the first call to animateFunc(), I'd attach the t1 variable to the jQuery object/DOM element so that I can access it again when the animateFunc() is called via the onclick. I suspect this is not possible as I found no mention of such thing anywhere.
  • This one is less ideal, but I create some sort of object to keep track of the timelines and attach it to maybe the gsap object somewhere? I'm just spitballing at this point and I have no idea if this is the right way to go about this haha.

Furthermore, I'd still like to know if there are no other alternatives such as the above 2? (i.e. is it not possible to re-access the timeline through the jQuery object / DOM element? And/or can I register the timeline to the gsap object with some sort of label and re-access it again later?)

Link to comment
Share on other sites

  • Solution
8 minutes ago, Chromium said:

JQuery has something called plugins ($.fn.insertCustomPluginHandlerHere()) that gets called that way all the time so I'm not sure I understand why this is a problem?

 

Doing that will behave the same way as your initial demo. $.fn is just a way to add a method to jQuery's prototype.

 

11 minutes ago, Chromium said:

Furthermore, I'd still like to know if there are no other alternatives such as the above 2? (i.e. is it not possible to re-access the timeline through the jQuery object / DOM element? And/or can I register the timeline to the gsap object with some sort of label and re-access it again later?)

 

You can add whatever you want to whatever you want. JavaScript is pretty relax in that regards, so you can add an animation to an element, object, etc.

 

See the Pen dyJwxye by GreenSock (@GreenSock) on CodePen

 

For more help with JavaScript, I would recommend checking out Wes Bos' JavaScript course. Most of your questions are really just general JavaScript scoping questions.

 

https://wesbos.com/javascript/03-the-tricky-bits/scope

 

  • Like 2
Link to comment
Share on other sites

HOLY COW BLAKE!!! You the legend man! I can't believe I've existed for this long without knowing about this!!!

 

I managed to store an object of timelines to the jQuery object but couldn't access it later for some reason. But that don't matter because I discovered something even better... we can store the same information directly to the DOM element using the data API. So now I've got this magical knowledge:

if (defaults.show === 'show' || defaults.show === 'hide') {
	// Get the NOO Animation GSAP timelines for the object.
	let nooAnimations = _this.find('.noo-tooltip').data('nooAnimations'),
	t1 = defaults.show === 'show' ? nooAnimations.tShow : nooAnimations.tHide;
	if (t1)
		t1.progress(1).restart();
	return _this;
}

You've unlocked a whole new dimension for me!!! Thanks doesn't cut it. You in town for a BBQ sometime?!

Seriously though... every now and then I come across something that I'm shocked to not have known about for as long as I've been writing code... this has to top the list!

  • Like 2
  • Haha 1
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...