Jump to content
Search Community

TL interruption & restart w/ new props

beau_dev test
Moderator Tag

Recommended Posts

First of all, I hope everyone is well & healthy.

 

My apologies for not creating a codepen usecase–the complexity is a bit over my head for this example to put into codepen.

 

I am posting a URL for an app (for phones only at the moment), I hope it's okay.

 

GSAP2.thumb.jpg.1728c2a605a1e325e6dd0b12241583b3.jpg

 

 

(App URL)

 

I have the beginning of an app displaying images illustrating the effects of mix-blend-mode properties.

The bottom right button cycles through 15 mix-blend-modes.

 

Sadly, it has various animation problems atm 🙄😭...

 

Principally, I'm running into the animation of the<div> component (displaying mode names) that slides up (y-axis) upon click.

 

const ModeNameDisplay = ({ mode }) => {
  let txtBox = useRef(null)
  useEffect(()=> {
    gsap.set(txtBox, { y:25})

    const tl = gsap.timeline({ defaults: { delay: .3 } })
    tl
    .to(txtBox, { duration: .2, y: 0 }, '-=0')
    .to(txtBox, { duration: 1, y: 25 }, '+=3')
  })
  return (
    <ModeNameContainer    ref={elem => txtBox = elem}>
      <h1 width="100%" height="100%">{mode}</h1>
    </ModeNameContainer>
  );
}

The simple animation, itself, works nicely: upon new props received, the timeline runs quite smoothly.

 

–Until, however, user clicks again before the initial TL finishes.

 

An impatient user clicks, sends a new prop, all hell breaks loose...and I feel like I should put away GSAP before I hurt myself.

 

The issue, I recognize, is that I'm not handling events (new user clicks) that occur before the timeline ends.

From searching the forums, I suspect it may be an issue with cleaning the cache of a timeline upon a new event(click).

 

The ideal behavior that I'd like to achieve would be:

IF  User interrupts previous TL with a click,

THEN a new TL restarts from scratch (textbox hidden) and a new prop (mode) displaying a new mode name that slides into view.

 

I have an inclination that either of the following might solve my problem:

.invalidate()

.kill()
.restart()

 

Although they are well written, I simply can't decipher the docs so as to apply their lessons to this case.

 

I would very much appreciate any help with this mess & hope everyone is healthy and staying safe.

 

Many, many thanks in advance if you come across this and are able to offer some advice.

 

Cheers,

 

Beau


REPO Link to the relevant file

 

 

 

 

Link to comment
Share on other sites

I'm not sure I follow everything completely, but you can always use the isActive() method to prevent clicks. If you want to allow a user to interrupt the playback, that's certainly doable too. In that case, I'd probably check if the timeline is active and force it to finish with .progress(1). Then you can use it again with new targets, properties etc. You could also kill or invalidate if you like. Here's a simplified example which might help.

 

See the Pen mdeoNZb by PointC (@PointC) on CodePen

 

You can see that the timeline is populated on click. If one of the boxes is active, the timeline is immediately set to progress(1). This prevents any weird overlaps or elements getting out of position.

 

Hopefully that gives you some ideas.

 

Happy tweening.

:)

 

  • Like 3
Link to comment
Share on other sites

After spending the day with this. I couldn't seem to get

 

if (tl && tl.isActive()) {
    tl.progress(1);
  }

to run... the .isActive()... I couldn't get it to return true & thus executing the .progress(1) method.

 

I discovered the error in my code, however... (for posterity, I'll note it).

 

It's the nature of useEffect() in react.

 

useEffect requires a dependency for the behavior that I expected.

 

therefore:

const ModeNameDisplay = ({ mode }) => {
  let txtBox = useRef(null)
  useEffect(()=> {
    gsap.set(txtBox, { y:25})

    const tl = gsap.timeline({ defaults: { delay: .3 } })
    tl
    .to(txtBox, { duration: .2, y: 0 }, '-=0')
    .to(txtBox, { duration: 1, y: 25 }, '+=3')
  }, [mode])
  return (
    <ModeNameContainer    ref={elem => txtBox = elem}>
      <h1 width="100%" height="100%">{mode}</h1>
    </ModeNameContainer>
  );
}

the deconstructed mode prop (visible just above the return statement) is the 2nd arg placed in the useEffect callback.

 

Everything runs nicely, now.

I elected not to go with the 

    .to(txtBox, { duration: 1, y: 25 }, '+=3')

I simply couldn't get that method to run.

 

Many thanks for your help. I'd love to know if there's anything else I could try.

 

It could be a react quirk. 🤔

 

Anyway... Thanks again.

Cheers,

Beau

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