5

Update: I added a codesanbox at the bottom of this with a more detailed explanation of what I need done.

So I don't quite understand how classes work in React, I am new to react and have used useState a little bit, but never have know what to do with a class. I am using this react package that has an example of how to use a controller to make you animation interactive built with flare now called rive. https://github.com/2d-inc/Flare-React#readme

What I want to achieve is to either run a different animation, or the same animation again when I hover over canvas element that is generated. I can create a second animation in flate(rive) that would still output in the same .flr file and I should then be able to reference it in the controller and run it on hover, just stuck on how to even do that part, or even get this controller to work. One thing to note is I can get the animation to run fine without the controller.

In the docs they have this example code

class PenguinController extends FlareComponent.Controller
{
    constructor()
    {
        super();
        this._MusicWalk = null;
        this._Walk = null;
        this._WalkTime = 0;
    }

    initialize(artboard)
    {
        this._MusicWalk = artboard.getAnimation("music_walk");
        this._Walk = artboard.getAnimation("walk");
    }

    advance(artboard, elapsed)
    {
        // advance the walk time
        this._WalkTime += elapsed;
        const { _MusicWalk: musicWalk, _Walk: walk, _WalkTime: walkTime } = this;

        // mix the two animations together by applying one and then the other (note that order matters).
        walk.apply(walkTime % walk.duration, artboard, 1.0);
        // if you want to slowly disable the head bobbing (musicWalk animation) you could ramp down the 
        // final argument (the mix argument) to 0.0 over some time. For now we're mixing at full strength.
        musicWalk.apply(walkTime % musicWalk.duration, artboard, 1.0);

        // keep rendering
        return true;
    }
}

First of all what is a constructor? what does super mean? then what are they defining in the constructor, is that some state, how do I determine what to define here?

For the initialized I assume I match it to the state above, and get the animation by the name I named it in flare(rive)

The advance part I don't really understand are we setting the animation with this._WalkTime += elapsed; to how long the animation runs? I think I understand the apply section, it is applying a duration to the animation.

Next it has this code

class MyComponent extends React.Component
{
    constructor()
    {
        this.state = { penguinController: new PenguinController() };
    }

    render()
    {
        return <FlareComponent controller={this.state.penguinController} /*... more properties here ...*/ />;
    }
}

Here is my attempted code currently I get the following error

TypeError: Cannot set property 'state' of undefined

import React from "react"
import PropTypes from "prop-types"
import { useStaticQuery, graphql } from "gatsby"
import FlareComponent from 'flare-react';
import styled from 'styled-components'
import Header from "./header"
import "../sass/index.scss"

const LogoWrapper = styled.div`
  width:200px;
  height:200px;
`

class AnimationController extends FlareComponent.Controller
{
    constructor()
    {
        super();
        this._MusicWalk = null;
    }

    initialize(artboard)
    {
        this._MusicWalk = artboard.getAnimation("Wispy Appear");
    }

    advance(artboard, elapsed)
    {

        const { _MusicWalk: musicWalk } = this;

        musicWalk.apply(musicWalk.duration, artboard, 1.0);

        // keep rendering
        return true;
    }
}

const Layout = ({ children }) => {
  const data = useStaticQuery(graphql`
    query SiteTitleQuery {
      site {
        siteMetadata {
          title
        }
      }
    }
  `)


        this.state = { AnimationController: new AnimationController() };


  return (
    <>
      <LogoWrapper>
        <FlareComponent width={200} height={200} animationName="Wispy Appear" controller={this.state.AnimationController} file="/wispy-2.flr"/>
      </LogoWrapper>

        <main className="main-wrapper">{children}</main>
        <footer>
          © {new Date().getFullYear()}, Built with
          {` `}
          <a href="https://www.gatsbyjs.org">Gatsby</a>
        </footer>
    </>
  )
}

Layout.propTypes = {
  children: PropTypes.node.isRequired,
}

export default Layout

For reference there is a a tutorial on how to make an animation interactive but it's for flutter, but it has some insights into there api https://medium.com/rive/building-a-responsive-house-with-flare-flutter-31af823ba805

Update

Here is my new attempted code after trying to read up on classes in es6, I still need to learn more.

So how do I go about running a second animation on click or hover or any event. The animation runs once now, but I don't know whow to use the controller?

import React from "react"
import Img from 'gatsby-image'
import styled from "styled-components"
import FlareComponent from 'flare-react';
import Layout from "../components/layout"


const LogoWrapper = styled.div`
  width:200px;
  height:200px;
`

class wispyController extends FlareComponent.Controller
{
    constructor()
    {
        super();
        this._Animate = null;
    }

    initialize(artboard)
    {
        this._Animate = artboard.getAnimation("Wispy Appear");
    }

    advance(artboard, elapsed)
    {

        const { _Animate: animate } = this;
        animate.apply(5, artboard, 1.0);

        // keep rendering
        return true;
    }
}


class IndexPage extends React.Component  {

  constructor()
  {
      super();
      this.state = { wispyController: new wispyController() };
  }

  render(){
    const {data} = this.props;

    return(

      <Layout>

        <LogoWrapper>
          <FlareComponent width={200} height={200} animationName="Wispy Appear" controller={this.state.wispyController} file="/Wispy.flr"/>
        </LogoWrapper>



    {data.allSanityBlogPost.edges.map(({ node: post }) => (  
      <article key={post.id}>
        <h1>{post.name}</h1>
        <img src={post.imageGif.asset.url}/>
      </article>
    ))}


      </Layout>
    )

  }

}

export default IndexPage

export const query = graphql`
  query IndexQuery {
    allSanityBlogPost {
      edges {
        node {
          name
          id
          imageGif {
            asset {
              url
            }
          }
        }
      }
    }
  }
`

Ok Hopefully someone can help here, I made a codesandbox so someone can see what I am trying to achieve. There are two animations, on the page you can see the first one which has a controller which should be mixing the two, and then the other two animations on there own. What I want to happen is the first animation run and then the second one to run on hover. HEre is the code sandbox https://codesandbox.io/s/frosty-water-jnj9m

coreyward
  • 77,547
  • 20
  • 137
  • 166
Anders Kitson
  • 1,413
  • 6
  • 38
  • 98
  • Your question could use a little bit of focus. Maybe try and build a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) on CodePen to help you narrow it down to a single issue. – sallf Jan 17 '20 at 03:40
  • @sallf I aded a codesanbox above, maybe it will help explain more of what I am trying to achieve. – Anders Kitson Jan 19 '20 at 03:39

1 Answers1

2

Classes in the context of React can be thought of as classes in most Object Oriented Programming language, they are a blueprint to create an object from. In order to let the language know how and what to do when we create it, it needs a constructor method. This constructor method is calling a special method called super() so that it calls the constructor of the class it is extending from, in this case FlareComponent.Controller

The method advance will be called to add to the captured walk time that the class is keepi track of.

One of the problems is that you are trying to set the state of the component directly instead of using setState https://reactjs.org/docs/react-component.html

I would highly recommend brushing up on React basics before you continue with this, it will really help you get the proper foundation you need.

JoelAK
  • 340
  • 2
  • 11
  • I updated my question after doing some reading, I am still stuck, hopefully you can point me in the right direction, the part that I am stuck on is setting the state in the IndexPage class. I think I have the other parts right. – Anders Kitson Jan 18 '20 at 00:12
  • I was missing super(). so I added that, what I am stuck on now is that I can't seem to figure out how to run the animation a second time I don't know how to run the controller, or control it so it runs on a mouse event either click or hover. – Anders Kitson Jan 18 '20 at 00:24