Jump to content
Gilbert

GSAP + React - how to access timeline in children components

Recommended Posts

I am experimenting with these title animations https://github.com/bigfanjs/react-titles and I want to sequence some titles. 

The questions that I have are:

 

How can I pause or play the original animations?

How can I sequence the animations (for each title)? - For example, play the first one, wait for .7 seconds and play the second one, etc.

How can I set the initial position of each title?

 

My code is:

Here is the code I have:

import React, { Component, Fragment } from "react";
import styled from "styled-components";
import * as titles from "react-titles";
import { TimelineMax, Power3 } from "gsap";

const mytitles = [
  {
    component: "Title2",
    title: "This is ",
    subTitle: "Sweet",
    isOpen: false,
    size: 100,
    x: '50'
  },
  {
    component: "Title6",
    title: "Let' see",
    subTitle: "if this works",
    isOpen: false,
    size: 400,
    x: '400'
  },
]

class Title extends Component {
  constructor(){
        super();
        this.renderTitle = this.renderTitle.bind(this);
        this.restartHandler = this.restartHandler.bind(this);
        this.tl = new TimelineMax({paused: true});
    }

  state = {
    isOpen: false
  }

  restartHandler(){
        const {tl} = this;
        tl.reversed( !tl.reversed() );
    }

  componentDidMount(){
        const {tl} = this;

        mytitles.forEach( (e,i) => {
            //tl.set(this.refs[e.component], {left:e.x, top:e.x})
            tl.to( this.refs[e.component], 1, {x: e.size, y: e.size/3 , scale: 0.5, opacity: 0.5}, .5 * i );
        });
        tl.reverse();
    }

  getComponent(e) {
    const ATitle = titles[e.component];
    //ATitle.handleRest();

    //const {t1} = this;
    //this.tl.set(this.refs[e.component], {left:e.x, top:e.x})
    return(
      <div  className="box" key={e.component} ref={e.component} >
        <ATitle
          size={e.size}
          text1={e.title}
          text2={e.subTitle}
          open="false"
          style={{ position: "absolute", x: " +e.x+" , y: " +e.x+", "fill": "orange" }}
          onComplete={this.handleComplete}
        />
      </div>
    )
  }

  renderTitle(e,i){
        return(
            this.getComponent(e)
        );
    }

handleComplete = (status) => {
    /*const {selected, component} = this.state;

    if (!status && selected !== component) {
      this.setState({ component: selected, isOpen: true });
    }*/
  }

  render() {
    return(
        <div>
            <button onClick={this.restartHandler}>Toggle Tween</button>
            <div>
                {mytitles.map(this.renderTitle)}
            </div>
         </div>
   )
  }
}

export default Title;

 

Share this post


Link to post
Share on other sites

Hi Gilbert and welcome to the GreenSock forums.

 

First try to avoid string refs, they are deprecated since React 15.x. Use the ref callback instead:

 

https://reactjs.org/docs/refs-and-the-dom.html

 

In the constructor create an empty array to add the elements as you call the render title method:

 

// this is inside the component's class
constructor(){
  super();
  // just an empty array, we'll use the ref callback to add the DOM elements
  this.titles = [];
  // the rest of your constructor code here
}

 

Then, IMHO I don't see the need for two methods to render each title, you can run all your logic in just one and use the ref callback to add the element to the array, like that you'll have a predictable way to add your elements to the timeline.

 

renderTitle(e) {
  
    const ATitle = titles[e.component];
  
    return(
      <div  className="box" key={e.component} ref={e => this.titles.push(e)} >
        <ATitle
          size={e.size}
          text1={e.title}
          text2={e.subTitle}
          open="false"
          style={{ position: "absolute", x: " +e.x+" , y: " +e.x+", "fill": "orange" }}
          onComplete={this.handleComplete}
        />
      </div>
    )
  }

 

The key is the ref callback which has the DOM node as the argument, then the DOM node is added to the titles array. Then you can access the titles array and create your timeline:

 

componentDidMount(){
  const { tl, titles } = this;
  
  titles.forEach( (e,i) => {
    tl.to( this.refs[e.component], 1, {x: e.size, y: e.size/3 , scale: 0.5, opacity: 0.5}, .5 * i );
  });
  tl.reverse();
}

 

This is a better and more actual approach to write your app.

 

Now to the sequencing part of your app. I'm a bit puzzled, because react-titles does creates either a GSAP instance or uses react-motion for the animations. If you want to control those animations, you'll have to fork the repo and create an API that exposes some way to do what you need, because react-titles starts as soon as the component is mounted. For the initial position, what I saw in the repo is that the code uses fromTo instances, which create an immediate render, which sets the initial position of the elements being animated, so no matter what you do react-title will enforce those initial values passed in the props of the component's instance. Such is the nature of re-usable React components, you have to work with whatever the creator of the component is giving you.

 

Also keep in mind that the open prop passed to the component is a boolean and you're passing a string "false". Try using a boolean instead:

 

<ATitle
  size={e.size}
  text1={e.title}
  text2={e.subTitle}
  open={false}
  style={{ position: "absolute", x: " +e.x+" , y: " +e.x+", "fill": "orange" }}
  onComplete={this.handleComplete}
/>

 

Another option is hack into the code of react-titles and create a way to control the animations. Honestly if I was you, I'd take the animations being created by react-titles and bake my own solution for the particular needs of the project.

 

The GSAP code in react-titles is good and there are no issues there and unfortunately we can't spend a lot of time figuring out how GSAP based tools work and how they're used. I saw that you started an issue in the repo, hopefully the creator(s) of the tool can help you more than I can and they can add a way to keep the tweens paused when mounting and give more control over them, as well as creating more complex sequences.

 

Happy Tweening!!!

  • Like 4
  • Thanks 1

Share this post


Link to post
Share on other sites

Rodrigo,

 

Thanks a lot for your help. You are the BEST!!!

  • Like 2

Share this post


Link to post
Share on other sites

The word React is like the Bat-Signal for @Rodrigo. If we need him, perhaps we just fire up the Rodrigo-React-Signal.

 

kkesqWD.jpg 

  • Like 1
  • Haha 7

Share this post


Link to post
Share on other sites
17 hours ago, Rodrigo said:

Ever heard of conditioning??

 

Ha! I'm the same way with SVG or mask related questions. I can't resist and start drooling. 😋 Blake will almost always appear when canvas and/or Pixi are mentioned in a thread. Everyone does seem to have their strong areas and favorites. Now if I can just get a PointC-SVG-Signal to show in the sky outside my window, I'd be all set. ;) 

  • Haha 2

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

  • Recently Browsing   0 members

    No registered users viewing this page.