Created
May 26, 2015 14:21
-
-
Save lourd/c2fd4af98f7292ce6a57 to your computer and use it in GitHub Desktop.
D3 and React Integration Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function createChart(dom, props){ | |
var width = props.width; | |
var height = props.height; | |
width = width + 200; | |
var data = props.data; | |
var sum = data.reduce(function(memo, num){ return memo + num.count; }, 0); | |
var chart = d3.select(dom).append('svg').attr('class', 'd3').attr('width', width).attr('height', height) | |
.append("g") | |
.attr("transform", "translate(" + (props.width/2) + "," + (height/2) + ")"); | |
var outerRadius = props.width/2.2; | |
var innerRadius = props.width/8; | |
var arc = d3.svg.arc() | |
.outerRadius(outerRadius) | |
.innerRadius(innerRadius); | |
var colors = ['#FD9827', '#DA3B21', '#3669C9', '#1D9524', '#971497']; | |
var pie = d3.layout.pie() | |
.value(function (d) { return d.count; }); | |
var g = chart.selectAll(".arc") | |
.data(pie(data)) | |
.enter().append("g") | |
.attr("class", "arc") | |
.on("click", function(d) { | |
alert('you clicked ' + d.data.name) | |
}) | |
.on('mouseover', function (d, i) { | |
d3.select(this) | |
.transition() | |
.duration(500) | |
.ease('bounce') | |
.attr('transform', function (d) { | |
var dist = 10; | |
d.midAngle = ((d.endAngle - d.startAngle) / 2) + d.startAngle; | |
var x = Math.sin(d.midAngle) * dist; | |
var y = -Math.cos(d.midAngle) * dist; | |
return 'translate(' + x + ',' + y + ')'; | |
}); | |
d3.select(this).append("text").style("fill", function(d) { return colors[i]; }).attr("id", "percent") | |
.attr('transform', "translate(0,-5)") | |
.attr("text-anchor", "middle").attr("dy", ".35em").style("font", "bold 15px Arial") | |
.text(function(d) { return (((d.value/sum)*100).toFixed(1) + " %"); }); | |
g.filter(function(e) { return e.value != d.value; }).style('opacity',0.5); | |
}).on('mouseout', function (d, i) { | |
d3.select(this) | |
.transition() | |
.duration(500) | |
.ease('bounce') | |
.attr('transform', 'translate(0,0)'); | |
d3.select("#percent").remove(); | |
g.filter(function(e) { return e.value != d.value; }).style('opacity',1) | |
}); | |
g.append("path") | |
.style("fill", function(d, i) { return colors[i]; }) | |
.transition().delay(function(d, i) { return i * 400; }).duration(500) | |
.attrTween('d', function(d) { | |
var i = d3.interpolate(d.startAngle, d.endAngle); | |
return function(t) { | |
d.endAngle = i(t); | |
return arc(d); | |
} | |
}); | |
var center = | |
g.filter(function(d) { return d.endAngle - d.startAngle > .1; }).append("text").style("fill", "white") | |
.attr('transform', function(d){ | |
return "translate(" + arc.centroid(d) + ")"; | |
}) | |
.attr("text-anchor", "middle").attr("dy", ".35em") | |
.text(function(d) { return d.value; }); | |
var legend = chart.selectAll(".legend") | |
.data(data) | |
.enter().append("g") | |
.attr("class", "legend") | |
.attr("transform", function (d, i) { | |
return "translate(150," + (-i * 20) + ")"; | |
}); | |
var rect = legend.append("rect") | |
.attr("width", 18) | |
.attr("height", 18) | |
.style("fill", function(d, i) { return colors[i]; }).style('opacity', 0); | |
var name = legend.append("text") | |
.attr("x", 24) | |
.attr("y", 12) | |
.text(function (d) { | |
var text = d.name; | |
if(text.length >30){ | |
text = text.substring(0,26); | |
text = text + '...'; | |
} | |
return text; | |
}).style('opacity', 0); | |
rect.transition().delay(function(d, i) { return i * 400; }).duration(1000).style('opacity',1); | |
name.transition().delay(function(d, i) { return i * 400; }).duration(1000).style('opacity',1); | |
}; | |
var PieChart = React.createClass({ | |
propTypes: { | |
width: React.PropTypes.number, | |
height: React.PropTypes.number, | |
title: React.PropTypes.string, | |
data: React.PropTypes.array.isRequired, | |
}, | |
getDefaultProps: function() { | |
return { | |
width: 300, | |
height: 350, | |
title: '', | |
Legend: true, | |
}; | |
}, | |
render: function() { | |
return ( | |
<div> | |
<h4> {this.props.title} </h4> | |
</div> | |
); | |
}, | |
componentDidMount: function() { | |
var dom = this.getDOMNode(); | |
createChart(dom, this.props); | |
}, | |
shouldComponentUpdate: function() { | |
var dom = this.getDOMNode(); | |
createChart(dom, this.props); | |
return false; | |
} | |
}); | |
var data = [ | |
{name: "Apples", count: 10}, | |
{name: "Oranges", count: 20}, | |
{name: "Bananas", count: 5}, | |
{name: "Blueberries", count: 42}, | |
{name: "mangoes ", count: 29} | |
]; | |
React.render(<PieChart data={data} title="Sample Fruits"/>, document.body); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var D3Legend = React.createClass({ | |
propTypes: { | |
width: React.PropTypes.number, | |
height: React.PropTypes.number, | |
colors: React.PropTypes.array.isRequired, | |
data: React.PropTypes.array.isRequired, | |
}, | |
render: function() { | |
var color = this.props.colors; | |
var data = this.props.data; | |
var elements = data.map(function(item, i){ | |
return ( | |
<LegendElement color={color} xpos="0" ypos={100+i*20} data={item.name} key={i} ikey={i}/> | |
) | |
}) | |
return( | |
<svg className="legend" width={this.props.width} height={this.props.height}>{elements}</svg> | |
); | |
} | |
}); | |
var LegendElement = React.createClass({ | |
render: function() { | |
var position = "translate(" + this.props.xpos + "," + this.props.ypos + ")"; | |
return ( | |
<g transform={position}> | |
<rect width="18" height="18" fill={this.props.color[this.props.ikey]}></rect> | |
<text x="24" y="9" dy=".35em">{this.props.data}</text> | |
</g> | |
); | |
} | |
}); | |
var Sector = React.createClass({ | |
getInitialState: function() { | |
return {text: '', opacity:'arc'}; | |
}, | |
render: function() { | |
var outerRadius = this.props.width/2.2; | |
var innerRadius = this.props.width/8; | |
var arc = d3.svg.arc() | |
.outerRadius(outerRadius) | |
.innerRadius(innerRadius); | |
var data = this.props.data; | |
var center = "translate(" + arc.centroid(data) + ")"; | |
var percentCenter = "translate(0,3)"; | |
var color = this.props.colors; | |
return ( | |
<g onMouseOver={this.onMouseOver} onMouseOut={this.onMouseOut} onClick={this.onClick}> | |
<path className={this.state.opacity} fill={color[this.props.ikey]} d={arc(this.props.data)}></path> | |
<text fill="white" transform={center} textAnchor="middle" fontSize="15px">{data.value}</text> | |
<text fill={color[this.props.ikey]} stroke={color} fontSize="15px" transform={percentCenter} textAnchor="middle">{this.state.text}</text> | |
</g> | |
); | |
}, | |
onMouseOver: function() { | |
this.setState({text: '', opacity:'arc-hover'}); | |
var percent = (this.props.data.value/this.props.total)*100; | |
percent = percent.toFixed(1); | |
this.setState({text: percent + " %"}); | |
}, | |
onMouseOut: function() { | |
this.setState({text: '', opacity:'arc'}); | |
}, | |
onClick: function() { | |
alert("You clicked "+this.props.name); | |
} | |
}); | |
var DataSeries = React.createClass({ | |
propTypes: { | |
width: React.PropTypes.number.isRequired, | |
height: React.PropTypes.number.isRequired, | |
color: React.PropTypes.array, | |
data: React.PropTypes.array.isRequired, | |
}, | |
render: function() { | |
var color = this.props.colors; | |
var data = this.props.data; | |
var width = this.props.width; | |
var height = this.props.height; | |
var pie = d3.layout.pie(); | |
var result = data.map(function(item){ | |
return item.count; | |
}) | |
var names = data.map(function(item){ | |
return item.name; | |
}) | |
var sum = result.reduce(function(memo, num){ return memo + num; }, 0); | |
var position = "translate(" + (width)/2 + "," + (height)/2 + ")"; | |
var bars = (pie(result)).map(function(point, i) { | |
return ( | |
<Sector data={point} ikey={i} key={i} name={names[i]} colors={color} total= | |
{sum} width={width} height={height}/> | |
) | |
}); | |
return ( | |
<g transform={position}>{bars}</g> | |
); | |
} | |
}); | |
var D3Chart = React.createClass({ | |
propTypes: { | |
width: React.PropTypes.number.isRequired, | |
height: React.PropTypes.number.isRequired, | |
children: React.PropTypes.node, | |
}, | |
render: function() { | |
return ( | |
<svg width={this.props.width} height={this.props.height}> | |
{this.props.children}</svg> | |
); | |
} | |
}); | |
var D3PieChart = React.createClass({ | |
propTypes: { | |
width: React.PropTypes.number, | |
height: React.PropTypes.number, | |
title: React.PropTypes.string, | |
data: React.PropTypes.array.isRequired, | |
}, | |
getDefaultProps: function() { | |
return { | |
width: 300, | |
height: 350, | |
title: '', | |
Legend: true, | |
}; | |
}, | |
render: function() { | |
var colors = ['#FD9827', '#DA3B21', '#3669C9', '#1D9524', '#971497']; | |
return ( | |
<div> | |
<h4> {this.props.title} </h4> | |
<D3Chart width={this.props.width} height={this.props.height}> | |
<DataSeries data={this.props.data} colors={colors} width= | |
{this.props.width} height={this.props.height}/> | |
</D3Chart> | |
<D3Legend data={this.props.data} colors={colors} width={this.props.width - 100} height={this.props.height} /> | |
</div> | |
); | |
} | |
}); | |
var data = [ | |
{name: "Apples", count: 10}, | |
{name: "Oranges", count: 20}, | |
{name: "Bananas", count: 5}, | |
{name: "Blueberries", count: 42}, | |
{name: "mangoes ", count: 29} | |
]; | |
React.render(<D3PieChart data={data} title="Sample Fruits"/>, document.body); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment