Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
scottgroovez

Reset Timeline on Complete

Recommended Posts

Hey, I have a timeline tween that repeats a number of times. When it's complete I want it to return to its initial state. I could do this using an onComplete, but I wonder if there's an available prop that does this automatically?

  • Thanks 1
Link to comment
Share on other sites

It sorta depends what you mean by "original state"

 

Option 1:

... onComplete: function() { this.time(0).kill(); }

This retains inline CSS, but returns things visually to the initial state. Basically it just rewinds the animation to its initial state and then kills it.

 

Option 2: 

// in your tween(s)
... clearProps: "all"

Wipes out any inline CSS. Not sure if that's what you want or not.

 

Option 3:

let state = captureState(".class, #id");
let tl = gsap.timeline({ onComplete: () => revertState(state)});

// record the current inline styles of all the elements passed in
function captureState(elements) {
	let state = [];
	gsap.utils.toArray(elements).forEach(element => state.push(element, element.style.cssText));
	return state;
}

// revert the inline styles
function revertState(state) {
	for (let i = 0; i < state.length; i+=2) {
		state[i].style.cssText = state[i+1];
	}
}

This captures the inline styles of the elements before the animation, and then reverts to those afterwards. It's slightly more complicated, but allows you to keep the inline styles that predated the animation. 

 

Does that help? 

  • Like 4
Link to comment
Share on other sites

Yes, very helpful. Option 1 was what I was thinking of initially. Thanks.

  • Like 1
Link to comment
Share on other sites

  • 4 months later...
On 10/14/2020 at 7:28 PM, GreenSock said:

It sorta depends what you mean by "original state"

 

Option 1:


... onComplete: function() { this.time(0).kill(); }

This retains inline CSS, but returns things visually to the initial state. Basically it just rewinds the animation to its initial state and then kills it.

 

Option 2: 


// in your tween(s)
... clearProps: "all"

Wipes out any inline CSS. Not sure if that's what you want or not.

 

Option 3:


let state = captureState(".class, #id");
let tl = gsap.timeline({ onComplete: () => revertState(state)});

// record the current inline styles of all the elements passed in
function captureState(elements) {
	let state = [];
	gsap.utils.toArray(elements).forEach(element => state.push(element, element.style.cssText));
	return state;
}

// revert the inline styles
function revertState(state) {
	for (let i = 0; i < state.length; i+=2) {
		state[i].style.cssText = state[i+1];
	}
}

This captures the inline styles of the elements before the animation, and then reverts to those afterwards. It's slightly more complicated, but allows you to keep the inline styles that predated the animation. 

 

Does that help? 

Is there a way to clear all the values added to an element style (for example div style="right: value 1; top: 1 value 2") by the timeline onComplete?

Link to comment
Share on other sites

7 minutes ago, tomektomczuk said:

Is there a way to clear all the values added to an element style (for example div style="right: value 1; top: 1 value 2") by the timeline onComplete?

I think you're looking for clearProps: true. Usage: gsap.set(myTarget, { clearProps: true });.

  • Like 1
Link to comment
Share on other sites

It is tween related so it should be in defaults.

This will apply it to every single tween in the timeline though. Might be not what you are after.

 

gsap.timeline({ defaults: { clearProps: true } })

 

Link to comment
Share on other sites

19 minutes ago, tomektomczuk said:

yes, it's doing what I need but before timeline is completed

That'll clear all inline CSS properties of each tween's target as soon as each tween is done. That's probably not what you want. If you really want to clear everything at the end of the timeline:

gsap.timeline({ onComplete: () => gsap.set(".all-your-targets", {clearProps: true}) });

That's highly unusual, though. You do realize that'll revert any changes that were made by the animations, right? 

  • Like 4
  • Thanks 1
Link to comment
Share on other sites

  • 4 months later...
On 2/25/2021 at 9:44 PM, GreenSock said:

That'll clear all inline CSS properties of each tween's target as soon as each tween is done. That's probably not what you want. If you really want to clear everything at the end of the timeline:


gsap.timeline({ onComplete: () => gsap.set(".all-your-targets", {clearProps: true}) });

That's highly unusual, though. You do realize that'll revert any changes that were made by the animations, right? 

I found this approach useful for animating a modal in, and then when the closing animation completes to revert the modal element to its original state so it can be opened again.

  • Like 1
Link to comment
Share on other sites

  • 8 months later...

 

 

I also have this question, but slightly different.

I have a game that has several levels, and information displayed at the end. The scoreboard elements that have had a gsap animation (some of them, not all of them) seem to be in the last state that they  were in before the game resets.

 

I have a button that resets the game, but I would also like to include a clearProps() to this button so this modal is blank whenever it is reused. How would I do that? I am just unclear on the syntax.

 

I did put a clearProps in my timeline, but that just makes the modal re-run immediately. I don't want it to do that. If it was an etch-a-sketch, I want to just shake the screen so next time I am there, it is brand new again.

 

I will make a codepen if you need, but the game has to go through a reset and you have to play it twice to see what I am talking about. 

 

See the Pen abVVgNx by sunflair0 (@sunflair0) on CodePen

 

515254987_Screenshot2022-03-26222550.png.e99fee515709d1ae97d8adaed953342b.png

 

This is the worst pen ever. Sorry.

 

on second pass, the scoreCap/quarter[n] does not appear. pScore[n] comes in as it should.

 

on the scoreModal, the time/date is already there, and goes out of phase with the new manifestation of the modal.

 

the button does a slide in with rotation first time, second time it just appears in it's end place. The other gsap targets perform consistently well.

Link to comment
Share on other sites

I don't have time to dig through all your code at the moment, but if you want to clearProps on certain elements, it should be as simple as: 

gsap.set(".targets", {clearProps: true});

Does that help? If you need more general consulting or logic advice, you are welcome to post in the "Jobs & Freelance" forum to see if you can hire someone for that; we try to keep these forums very focused on GSAP-specific questions. Please see the forum guidelines

 

Happy tweening!

  • Like 1
Link to comment
Share on other sites

I did try clearProps and it makes it r7n again immediately. I want to understand where gsap puts the elements in the DOM because this will not be the only time running into this. I watched the video about invalidate, but that was not the right answer, either.

How do you get it to reset as the last tween without it wanting to rerun?

Link to comment
Share on other sites

10 hours ago, Sunflair said:

I want to understand where gsap puts the elements in the DOM because this will not be the only time running into this.

GSAP doesn't put elements in the DOM - think of it like a high-speed property manipulator. It's not a framework like React that forces you to work with a particular ecosystem or let it handle the whole DOM - GSAP merely changes property values (the ones you tell it to animate). 

 

10 hours ago, Sunflair said:

How do you get it to reset as the last tween without it wanting to rerun?

You want to rewind the playhead to the beginning and pause it there? Sure, that's as simple as: 

animation.pause(0); 

If you still need help, it'd be best if you could provide a minimal demo (the one you provided has a lot of code to weed through). You'll significantly increase your chances of getting a solid answer if you provide only the smallest amount of code necessary to see the issue, and then make your GSAP-related question very clear and we'd be happy to help. 

 

  • Like 1
Link to comment
Share on other sites

I really appreciate your follow up. I am struggling with this program and this is literally the LAST thing I need to figure out.

 

What I told you before, I figured out 2/3 of the problem (your previous help helped me a lot! It is all about placement with code lol).

 

What I think I need now is how to invalidate this:   

let fadeDuration = 1,
    stayDuration = 3,
    finalSBPrint2 = gsap.timeline({repeat: -1});

finalSBPrint2.to(".time", {opacity: 0, duration: fadeDuration}, stayDuration)
  .to(".date", {opacity: 1, duration: fadeDuration}, "-=100%")
  .to(".time", {opacity: 1, duration: fadeDuration}, "+=" + stayDuration)
  .to(".date", {opacity: 0, duration: fadeDuration}, "-=100%");

This is how it looks for context (just for info flow so you can see):


    let finalSBPrint = gsap.timeline()
    finalSBPrint
        .to(".roundModal", { opacity: 0, duration: .5, ease: "circ", })
        .to(".roundModal", { y: '-300%' })
        .to(".tsModal", { opacity: 1, duration: 1.3, y: "165%", ease: "bounce", }, "-=.5")
        .to(".scoreCap", { opacity: 1, duration: 1.5, ease: "circ" })

        // /////top part of scoreboard --player score
        .to(".quarter0", { opacity: 0, duration: .5, ease: "circ"})
        .fromTo(".pScore0",{ opacity: 0, scale: 0}, { opacity: 1, scale: 1, y:"-9", duration: .6, ease: "circ"},"<")
        .to(".quarter1", { opacity: 0, duration: .5, ease: "circ"})
        .fromTo(".pScore1", { opacity: 0, scale: 0, y: "-50" },{ opacity: 1, scale: 1, y:"-10", duration: .6, ease: "circ" },"<")
        .to(".quarter2", { opacity: 0, duration: .5, ease: "circ"})
        .fromTo(".pScore2", { opacity: 0, scale: 0, y: "-50" },{ opacity: 1, scale: 1, y:"-10", duration: .6, ease: "circ" },"<")
        .to(".quarter3", { opacity: 0, duration: .5, ease: "circ"})
        .fromTo(".pScore3", { opacity: 0, scale: 0, y: "-50" },{ opacity: 1, scale: 1, y:"-10", duration: .6, ease: "circ" },"<")
        .to(".quarter4", { opacity: 0, duration: .5, ease: "circ"})
        .fromTo(".pScore4",{ opacity: 0, scale: 0, y: "-50" }, { opacity: 1, scale: 1, y:"-10", duration: .6, ease: "circ" },"<")
        .to(".quarter5", { opacity: 0, duration: .5, ease: "circ"})
        .fromTo(".pScore5", { opacity: 0, scale: 0, y: "-50"},{ opacity: 1, scale: 1, y:"-10", duration: .6, ease: "circ" },"<")
        
        // /////bottom part of scoreboard --top ten
        .fromTo(".scoreModal", { opacity: 0 }, { opacity: 1, duration: 1, ease: "circ" }, "+=.5")
        .fromTo(".rank", { opacity: 0 }, { opacity: 1, duration: 2, ease: "circ", stagger: .4 })
        .fromTo(".lvColor", { opacity: 0 }, { opacity: 1, duration: 2, ease: "circ", stagger: .4 }, "<")
        .fromTo(".score", { opacity: 0 }, { opacity: 1, duration: 2, ease: "circ", stagger: .4 }, "<")
        .fromTo(".name", { opacity: 0 }, { opacity: 1, duration: 2, ease: "circ", stagger: .4 }, "<")
        .fromTo(".time", { opacity: 0 }, { opacity: 1, duration: 2, ease: "circ", stagger: .4 }, "<")     
        .fromTo("#message", { opacity: 0, scale: 0, x: "20%", y: "33%" }, { opacity: 1, scale: 1.1, ease: "power2", duration: 1 }, "-=1")
        .fromTo("#restart-button", { opacity: 0,  }, { opacity: 1, x: "650%",  duration: 1, ease: "back", rotation: 720 }, "-=1");

 let fadeDuration = 1,
    stayDuration = 3,
    finalSBPrint2 = gsap.timeline({repeat: -1});

finalSBPrint2.to(".time", {opacity: 0, duration: fadeDuration}, stayDuration)
  .to(".date", {opacity: 1, duration: fadeDuration}, "-=100%")
  .to(".time", {opacity: 1, duration: fadeDuration}, "+=" + stayDuration)
  .to(".date", {opacity: 0, duration: fadeDuration}, "-=100%");
  
  let master = gsap.timeline();
  master
  .add(finalSBPrint)
  .add(finalSBPrint2);

The problem is just the .time and .date targets. If I restart() it, it will run twice. If I clearProps, it just washes the color out of the targets, and the fade overlap persists. I watched the video several times about invalidate and I think this may be the answer. The fade alternates, and keeps running through the game.

 

I think it is because of the finalSBPrint2 = gsap.timeline({repeat: -1})

 

The -1 (I think) is the problem. How do I stop that? That's why I think invalidate is the answer.

 

The codepen is hard because you have to go through the whole game twice to get the effect because the first time it works well. The second time it is already running, and it prints over it so it looks a mess.

 

If you need more, please let me know.

Again, I appreciate all your help and suggestions. If you think that pause will work after all I say to you, then let me know.

I will be trying it until I hear back from you.

Link to comment
Share on other sites

Sorry, I'm having a really hard time understanding you. repeat: -1 simply means "repeat the entire timeline infinitely". 

 

What exactly are you restarting? The "master"? 

 

If you still need help, please just create most minimal demo possible (NOT your real animation/game - just a super-simple version that only animates a couple of <div> elements to illustrate the problem). It's just very hard to try to visualize things and parse through a wall of code and not even see where you're doing a restart() or be able to observe the problem occurring. You'll have a significantly better chance of getting a quality answer if you provide that minimal demo that very clearly illustrates the issue with a fraction of the code you're providing. 

  • Like 1
Link to comment
Share on other sites

I understand and will do that. I gave the pic so you can see the end :)  But, tomorrow I shall make something. I will re-use the same codepen.

 

Muchas gracias

Link to comment
Share on other sites

See the Pen bGaooox by sunflair0 (@sunflair0) on CodePen

 

Here is the codepen. If you push the button once, you can see the effect, push it a lot, and you can see it better.

 

In the program it is not so subtle. You can see the two divs stepping on each other. And, on load, the second time the divs are already present instead of starting opacity at 0.

Edited by Sunflair
loaded codepen
Link to comment
Share on other sites

If this isn't showing the effect well enough, I can supply a video.  In the program, the duration of the fade is much smoother, not sure why it is different here. But, if you push the button several times, you can see it starts looking stilted. In the program, the effect is magnified.

Link to comment
Share on other sites

Hi Sunflair, 

 

You're creating the same animation over and over again. You need to kill the previous animation before creating a new one. It's probably going to need a little more work than this because you can interrupt the animation, but for now I'm just going to set the progress back to 0. You're also adding a brand event listener in your gameEnd function, which is create even more calls.

 

function gameEnd() {
  finalSBPrint2.progress(0).kill();
  finalSBPrint2 = gsap.timeline({ repeat: -1 });
  let fadeDuration = 1,
    stayDuration = 3;
    

  finalSBPrint2
    .to(".time", { opacity: 0, duration: fadeDuration }, stayDuration)
    .to(".date", { opacity: 1, duration: fadeDuration }, "-=100%")
    .to(".time", { opacity: 1, duration: fadeDuration }, "+=" + stayDuration)
    .to(".date", { opacity: 0, duration: fadeDuration }, "-=100%");
}

 

  • Like 2
Link to comment
Share on other sites

Thank you! I had not heard of kill, and it sounds like that is the ticket.

 

Also, thank you about the event listener. I had an issue with the button and had to remove and create and all that mess, and finally figured it out but forgot to move this. I will do that!

 

If I need more help, I will ask for it. 

 

Thank you for being patient with me. I am still new to coding and think Greensock is super cool.

  • Like 1
Link to comment
Share on other sites

I am so sorry to bother you further, but this solution kills my animation before it can be used. I tried to put the kill event on a button, but it kills it before it starts (I read the question and answer in the forum, but that is from 5 years ago, and I could not make the solution work).

 

Is there a way to reference the .finalSPPrint2 outside of the function that originally calls it? Will it be out of scope if I try to call it in another function? If not, would hoisting wreck it anyway?

 

I also tried pause instead of kill. Same result. It stops .finalSPPrint2 from working.

 

Link to comment
Share on other sites

Posted (edited)

Hey, in your codepen you’re creating 2 gsap timelines. One in the main body and another in the gameEnd function. Each time gameEnd is called it creates a new one.


I’ve forked your codepen and made some adjustments. I had to add a gsap.set to reset opacity to 1 otherwise the time would disappear (I’m on my phone so couldn’t debug why that happens)


The significant changes were deleting the finalSBPrint2 variable inside the gameEnd function so there’s only one reference to the gsap timeline and removing the duplicated addEventListener. I also removed the code creating the timeline outside gameEnd and just called gameEnd on init as that again was duplicated code.

 

See the Pen XWVqOqV by whizz-shumphrey (@whizz-shumphrey) on CodePen

Edited by scottgroovez
Added code change context
  • Like 1
Link to comment
Share on other sites

I had to augment the codepen to mimic what happens in my program.

 

gameEnd() does not repeat, it is one function that I listed twice in the codepen because I didn't want to make it recursive here. The game goes through, and gets to gameEnd(), then runs. The button is pushed and you go to the beginning of the game and play the whole thing and get to gameEnd again. At that point, finalSBPrint2 is called again. It's still running from the first time it is called and when called the second, (and third, and fourth) time, those fades overlap and it gets to look really sloppy.

I tried to make .time and .date opacity 0 in the game restart(), but that does not work. Tried changing it in Javascript style and attribute, but that does not work, either.

I even tried keyframes, but it will not act on those classes once gsap prints them.

 

I like your fix, and will try to incorporate some of the things here in my next attempt.

It's spaghetti code, I know. I am just learning and when I learn something new, I try to change it, but it's a lot and a big file, so I don't want to post the whole thing. If you want to look, it is in github. I am Sunflair0, and this is cash-grab.  Master branch for now.  

 

I say that so you can see in context, but really, I just need a way to turn off the fade, or stop it mid-fade when I get out of this function, and let it re-start when it needs to be called again. When I put in stops or pauses, or resets, they are called right away instead of waiting, so it never runs properly the first time.

 

I will keep trying until I get it!

 

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