48

Animated React Metaballs

 6 years ago
source link: https://www.tuicool.com/articles/hit/juIJfev
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Animated React + d3 Metaballs

fIbm2u3.gif
react-metaballs: Animated Metaballs in React and d3

Some time ago I wrote about Advanced Metaballs , describing their utility and outlining an algorithm to compute an SVG path given a set of circles. However, I did not include sample code or information on animation.

That’s where React Metaballs comes in. It’s a simple component built using React and d3. Below is an overview of the project, how to use it, and a bit on my attempts at animation.

react-metaballs

You can find a demo of react-metaballs , as well as the package on npm , and source code available on GitHub .

Installation

npm install react-metaballs

Usage

Once installed, the Metaballs component can be imported as follows

import ReactMetaballs from 'react-metaballs'

Data is formatted as an array of objects containing three values:

const circles = [
  {
    cx: 200,
    cy: 100,
    r: 64
  }, // ...
];

cx — center on the x-axis

cy — center on the y-axis

r — radius

The coordinates are relative to the whole, meaning a rectangle is constructed around all circles creating the SVG viewBox . It then constructs a single path element around all circles using bezier curves .

class App extends Component {
  render () {
    return (
      <Metaballs
        easement={d3.easeBackOut}
        circles={circles} />
    )
  }
}

The final output renders an svg element that scales with it’s contain as defined by the preserveAspectRatio attribute. That’s the scalable in SVG, we’ve defined a vector that the browser knows how to scale up or down.

Animation

If you’ve held a reference to the Metaballs element, there’s an updateCircles method that takes care of transitioning between two sets of data.

For example, to transition between two states:

this.metaballRef.current.updateCircles(newCircles)

The original transitions were written with one line in CSS, but this approach was abandoned because of compatibility issues.

path {
    transition: d 300ms ease-in-out;
}

If only animation were this simple. This actually works in Google Chrome, but only Google Chrome :( For other, modern browsers there is the SVG animate element, but this too has compatibility concerns . Other guides on React SVG Animations suggest requestAnimationFrame , but this seemed to likely to cause issues and too difficult to manipulate animation properties like easing.

Enter d3 (pun intended)! d3 comes with tons of options, and has supports animating the d property easily . By creating a component that encapsulates a path element, animating the d property was easy:

componentWillReceiveProps(nextProps) {
    if (this.props.path !== nextProps.path) {
        let { duration, easement = d3.easeLinear } = this.props;
        this.path.transition()
                 .ease(easement)
                 .attr('d', nextProps.path)
                 .on('end', () => this.setState({
                     path: nextProps.path
                 }))
                 .duration(duration);
    }
}

For the purists, this violates all the rules . From a d3 perspective, we’re not really binding to data just using d3 as a tweening library. From a React perspective, we’re manipulating the DOM directly and using the soon-to-be-deprecated componentWillReceiveProps method. But there certainly are others using React + d3 in this way, and with great results.

That’s it for now. I hope to explore react-move in the future, which promises to wed React + d3 in a manner consistent with both frameworks. Credit to Varun Vachhar for his code and article on the mathematics of Metaballs .

You can find source code on GitHub . For ideas on styling and use cases, see my previous article on Pretty Metaballs .


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK