class D3Comp extends React.Component { constructor(props) { super(props); // Consts this.ANIMATION_DURATION = 1000; // ms this.REACT_LOGO = ''; this.D3_LOGO = ''; // Initialize state this.state = { width: window.innerWidth, height: window.innerHeight, xyData: this._getRandomXYData() }; this._d3Digest = this._d3Digest.bind(this); } componentDidMount() { setInterval(() => this.setState({ xyData: this._getRandomXYData() }), this.ANIMATION_DURATION + 100); // Force update this._d3Digest(); // Init } componentDidUpdate(prevProps, prevState) { this._d3Digest(); } render() { return { this.canvas = elem }} width = {this.state.width} height = {this.state.height} />; } _d3Digest() { let logos = d3.select(this.canvas) .selectAll('.logo') .data(this.state.xyData); logos.exit() .transition().duration(this.ANIMATION_DURATION) .style('opacity', 0) .remove(); logos.merge( logos.enter() .append('g') .classed('logo', true) .style('opacity', 0) .attr('transform', `translate(${this.state.width/2},${this.state.height/2})`) // Init on center .html(() => [this.REACT_LOGO, this.D3_LOGO][Math.floor(Math.random()*2)]) ).transition().duration(this.ANIMATION_DURATION) .style('opacity', 1) .attr('transform', d => `translate(${this.state.width * d[0]},${this.state.height * d[1]})`); } _getRandomXYData() { return d3.range(Math.round(Math.random() * 100)).map(() => [Math.random(), Math.random()]); } } D3Comp.propTypes = {}; D3Comp.defaultProps = {};