Skip to content

Instantly share code, notes, and snippets.

@jstcki
Created November 20, 2014 17:44
Show Gist options
  • Save jstcki/b226253275b248c04a61 to your computer and use it in GitHub Desktop.
Save jstcki/b226253275b248c04a61 to your computer and use it in GitHub Desktop.
React-D3 Components

React-D3 components.

<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
background: #fff;
font: 10px Helvetica, sans-serif;
}
line, path {
fill: none;
stroke: #ccc;
shape-rendering: crispEdges;
}
.labels text {
text-anchor: middle;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://fb.me/react-0.12.0.js"></script>
<script src="http://fb.me/JSXTransformer-0.12.0.js"></script>
<script type="text/jsx">
var generateDatum = DataGenerator(d3.random.normal(5000, 1000));
var ChartMixin = {
propTypes: {
xScale: React.PropTypes.func.isRequired,
yScale: React.PropTypes.func.isRequired,
data: React.PropTypes.array.isRequired,
transitionDuration: React.PropTypes.number.isRequired
},
componentDidMount: function() {
d3.select(this.getDOMNode())
.call(this.renderData);
},
componentDidUpdate: function(prevProps, prevState) {
this.xScale0 = prevProps.xScale;
this.yScale0 = prevProps.yScale;
d3.select(this.getDOMNode()).transition().duration(this.props.transitionDuration)
.call(this.renderData);
},
render: function() {
return (
this.transferPropsTo(<g />)
);
}
};
var Axis = React.createClass({
propTypes: {
scale: React.PropTypes.func.isRequired,
orient: React.PropTypes.string.isRequired,
transitionDuration: React.PropTypes.number.isRequired
},
componentDidMount: function() {
this.axis = d3.svg.axis()
.scale(this.props.scale)
.orient(this.props.orient);
d3.select(this.getDOMNode()).call(this.axis);
},
componentDidUpdate: function(prevProps, prevState) {
this.axis
.scale(this.props.scale)
.orient(this.props.orient);
d3.select(this.getDOMNode()).transition().duration(this.props.transitionDuration)
.call(this.axis);
},
render: function() {
return this.transferPropsTo(<g />);
}
});
var Dots = React.createClass({
mixins: [ChartMixin],
renderData: function(g) {
var x = this.props.xScale;
var y = this.props.yScale;
var x0 = this.xScale0 || x;
var y0 = this.yScale0 || y;
var data = this.props.data;
g.each(function() {
var c = d3.select(this).selectAll('circle').data(data, function(d) { return d.id; });
c.enter().append('circle')
.attr('cx', function(d) { return x0(d.x); })
.attr('cy', function(d) { return y0(d.y); })
.style('opacity', 1e-6);
d3.transition(c)
.attr('cx', function(d) { return x(d.x); })
.attr('cy', function(d) { return y(d.y); })
.attr('r', function(d) { return 3; })
.style('opacity', 1);
c.exit()
.remove();
});
},
});
var Labels = React.createClass({
mixins: [ChartMixin],
renderData: function(g) {
var x = this.props.xScale;
var y = this.props.yScale;
var x0 = this.xScale0 || x;
var y0 = this.yScale0 || y;
var data = this.props.data;
g.each(function() {
var c = d3.select(this).selectAll('text').data(data, function(d) { return d.id; });
c.enter().append('text')
.attr('x', function(d) { return x0(d.x); })
.attr('y', function(d) { return y0(d.y); })
.attr('dy', -10)
.style('opacity', 1e-6);
d3.transition(c)
.attr('x', function(d) { return x(d.x); })
.attr('y', function(d) { return y(d.y); })
.style('opacity', 1)
.text(function(d) { return d.id; });
c.exit()
.remove();
});
}
});
var Chart = React.createClass({
getInitialState: function() {
return {
width: 960,
height: 500,
data: d3.range(20).map(generateDatum)
};
},
componentDidMount: function() {
setInterval(function() {
this.setState({
data: this.state.data.slice(10).concat(d3.range(10).map(generateDatum))
});
}.bind(this), 1500);
},
render: function() {
var x = d3.scale.linear()
.domain(d3.extent(this.state.data, function(d) { return d.x; }))
.range([60, this.state.width - 30])
.nice();
var y = d3.scale.linear()
.domain(d3.extent(this.state.data, function(d) { return d.y; }))
.range([this.state.height - 30, 30])
.nice();
return (
<svg width={this.state.width} height={this.state.height}>
<Axis className='x axis' scale={x} orient='bottom' transform='translate(0, 470)' transitionDuration={1000} />
<Axis className='y axis' scale={y} orient='left' transform='translate(60, 0)' transitionDuration={1000} />
<Dots className='dots' xScale={x} yScale={y} data={this.state.data} transitionDuration={1000} />
<Labels className='labels' xScale={x} yScale={y} data={this.state.data} transitionDuration={1000} />
</svg>
);
}
})
React.render(<Chart />, document.body);
function DataGenerator(random) {
var id = 0;
return function() {
return {
id: ++id,
x: random(),
y: random()
};
}
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment