React-motion: Looped Pulse Animation Hack - is there a better approach?

Created on 21 May 2016  路  3Comments  路  Source: chenglou/react-motion

I've created a pulsing circle svg element using react-motion. Basically I want a circle to scale larger and fade to nothing, and repeat indefinitely. React-motion spring tends to create the reverse animation as well which I'm trying to eliminate.

I can get it to repeat indefinitely by setting damping = 0 and I don't wan't the reverse animation to happen - that is is if the spring goes from 0 to 1, I don't want it to animate back from 1 to 0. So I've basically made a hack to invert the reverse interpolation so instead of transitioning like 0->1, 1->0, 0->1, 1->0 it does 0->1, 0->1, 0->1, 0->1. It just figures out if the spring is transitioning up or down, and if it's transitioning down it inverts it.

It feels a bit hacky. Is there a better way to approach this? Maybe spring and react-motion isn't the best solution for this type of animation?

import React from 'react';
import {Motion, spring} from 'react-motion';

class Node extends React.Component {

  constructor(props) {
    super(props);
  }


  render() {
    var springDirectionUp = true; //keep track if spring is going up or down
    return (
      <g>
        <circle cx={this.props.xPos} cy={this.props.yPos} r={this.props.radius} fill={#FFC700} />
          <Motion  defaultStyle={{s:0}} style={{s: spring(.5, {stiffness: 5, damping: 0})}}> 
            {({s}) => {
              if (s <= 0.01) { // when reaches trough
                springDirectionUp = true;
              } else if (s >= .99) { // when reaches peak
                springDirectionUp = false;
              }
              let v = springDirectionUp ? s : (1-s); //go from 0->1 twice in a single cycle, ie. replaces the returning 1->0 with 0->1
              return (
                <circle className="pulse" cx={this.props.xPos} cy={this.props.yPos} r={this.props.radius+this.props.radius*v} fill={#FFC700} style={{opacity: 0.75-v*0.75}}/>
              );
            }}
          </Motion>
      </g>
    );
  }

}


export default Node;

Most helpful comment

See this simple Motion wrapper to do Looping and Pulsing animations (check readme/examples)
https://www.npmjs.com/package/react-motion-loop

All 3 comments

making loop animations is something I've struggled I'd hope to see a better way to do it

you can use onRest to know when the animation is idle, adds a bit of state (demo).

class Node extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      isResting: false,
    }
    this.handleRest = this.handleRest.bind(this)
  }

  handleRest() {
    this.setState({
      isResting: true,
    }, () => {
      requestAnimationFrame(() => {
        this.setState({
          isResting: false,
        })
      })
    })
  }

  render() {
    return (
      <g>
        <circle
          cx={this.props.xPos}
          cy={this.props.yPos}
          r={this.props.radius}
          fill={"#FFC700"}
        />
        <ReactMotion.Motion
          defaultStyle={{ s: 0 }}
          style={{
            s: this.state.isResting ? 0 : ReactMotion.spring(1, {stiffness: 130, damping: 26})
          }}
          onRest={this.handleRest}
        > 
          {({ s }) =>
              <circle
                className="pulse"
                cx={this.props.xPos}
                cy={this.props.yPos}
                r={this.props.radius + this.props.radius * s}
                fill={"#FFC700"}
                style={{
                  opacity: 0.75 - s * 0.75,
                }}
              />
          }
        </ReactMotion.Motion>
      </g>
    );
  }
}


ReactDOM.render(
  <svg width={400} height={400}>
    <Node
      xPos={200}
      yPos={200}
      radius={100}
    />
  </svg>,
  document.getElementById("App")
)

See this simple Motion wrapper to do Looping and Pulsing animations (check readme/examples)
https://www.npmjs.com/package/react-motion-loop

Was this page helpful?
0 / 5 - 0 ratings

Related issues

efdor picture efdor  路  3Comments

DanielRuf picture DanielRuf  路  4Comments

p4bloch picture p4bloch  路  3Comments

alexreardon picture alexreardon  路  5Comments

irvinebroque picture irvinebroque  路  7Comments