Skip to content

Instantly share code, notes, and snippets.

@jmgimeno
Forked from jstcki/README.md
Created February 25, 2014 16:07
Show Gist options
  • Select an option

  • Save jmgimeno/9211929 to your computer and use it in GitHub Desktop.

Select an option

Save jmgimeno/9211929 to your computer and use it in GitHub Desktop.

Using D3 in a React TransitionGroup to transition elements. D3 is used purely for transitions, no data-joins are used. The distinction between entering and exiting elements is handled by the TransitionGroup component. See the React documentation for more features.

Alternative implementations only with D3 and using React without addons.

Note: This implementation is around 30% slower in processing 1000 circles than the other two. Also, componentWillEnter() only is triggered when the TransitionGroup is being re-rendered and not when it is mounted (notice the gray circle at the start).

<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
background: #fff;
}
.item {
fill: #333;
stroke-width: 1.5;
}
.item--transitioning {
fill: none;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://fb.me/react-with-addons-0.9.0.min.js"></script>
<script>
var width = 960,
height = 500,
data = [];
var x = d3.scale.linear()
.domain([0, 1])
.range([0, width]);
var y = d3.scale.linear()
.domain([0, 1])
.range([150, height - 150]);
var r = d3.scale.sqrt()
.domain([0, 1])
.range([0, 30]);
var circle = React.createClass({
componentWillEnter: function(done) {
d3.select(this.getDOMNode())
.classed('item--transitioning', true) // componentWillEnter() does not fire for first item, highlight it
.style('stroke', '#3E6E9C')
.transition().duration(1000)
.style('stroke', '#D8E467')
.attr('cy', y(this.props.y))
.each('end', done);
},
componentWillLeave: function(done) {
d3.select(this.getDOMNode())
.transition().duration(1000)
.style('stroke', '#3E6E9C')
.attr('cy', height)
.each('end', done);
},
render: function() {
return React.DOM.circle({
className: 'item',
cx: x(this.props.x),
cy: 0,
r: r(this.props.r)
});
}
});
function render() {
React.renderComponent(
React.addons.TransitionGroup(
{
transitionName: 'circles',
component: React.DOM.svg,
width: width,
height: height
},
data.map(circle)
),
document.body
);
}
var circlesCreated = 0;
function add() {
data.push({key: Date.now(), x: Math.random(), y: Math.random(), r: Math.random()});
render();
setTimeout(data.length < 100 ? add : remove, 5);
}
function remove() {
data = data.slice(1);
render();
if (++circlesCreated === 1000) console.timeEnd('1000 circles');
setTimeout(data.length > 0 ? remove : add, 5);
}
console.time('1000 circles');
add();
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment