mirror of
https://github.com/aclindsa/moneygo.git
synced 2024-12-26 07:33:21 -05:00
Add PieChart
This commit is contained in:
parent
4536db030e
commit
32fffdf91b
136
js/components/PieChart.js
Normal file
136
js/components/PieChart.js
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
var d3 = require('d3');
|
||||||
|
var React = require('react');
|
||||||
|
|
||||||
|
var Slice = React.createClass({
|
||||||
|
displayName: "Slice",
|
||||||
|
render: function() {
|
||||||
|
if (this.props.angle > Math.PI*2 - 0.00001) {
|
||||||
|
var slice = (<circle cx={this.props.cx} cy={this.props.cy} r={this.props.radius}
|
||||||
|
className={this.props.className}
|
||||||
|
onClick={this.props.onClick} />);
|
||||||
|
} else {
|
||||||
|
var center = this.props.cx + " " + this.props.cy;
|
||||||
|
var dx = Math.cos(this.props.angle)*this.props.radius - this.props.radius;
|
||||||
|
var dy = Math.sin(this.props.angle)*this.props.radius - 0.00001;
|
||||||
|
var large_arc_flag = this.props.angle > Math.PI ? 1 : 0;
|
||||||
|
var rotateDegrees = this.props.startAngle * 180 / Math.PI;
|
||||||
|
|
||||||
|
slice = (<path d={"M" + center + " l " + this.props.radius + " 0 a " + this.props.radius + " " + this.props.radius + ", 0, " + large_arc_flag + ", 1, " + dx + " " + dy + " Z"}
|
||||||
|
className={this.props.className}
|
||||||
|
onClick={this.props.onClick} />);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<g className="chart-series" transform={"rotate(" + rotateDegrees + " " + center + ")"}>
|
||||||
|
<title>{this.props.title}</title>
|
||||||
|
{slice}
|
||||||
|
</g>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = React.createClass({
|
||||||
|
displayName: "PieChart",
|
||||||
|
sortedSeries: function(series) {
|
||||||
|
// Return an array of the series names, from highest to lowest sums (in
|
||||||
|
// absolute terms)
|
||||||
|
|
||||||
|
var seriesNames = [];
|
||||||
|
var seriesValues = {};
|
||||||
|
for (var child in series) {
|
||||||
|
if (series.hasOwnProperty(child)) {
|
||||||
|
seriesNames.push(child);
|
||||||
|
seriesValues[child] = series[child].reduce(function(accum, curr, i, arr) {
|
||||||
|
return accum + curr;
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
seriesNames.sort(function(a, b) {
|
||||||
|
return seriesValues[b] - seriesValues[a];
|
||||||
|
});
|
||||||
|
|
||||||
|
return [seriesNames, seriesValues];
|
||||||
|
},
|
||||||
|
render: function() {
|
||||||
|
height = 400;
|
||||||
|
width = 600;
|
||||||
|
legendWidth = 100;
|
||||||
|
xMargin = 70;
|
||||||
|
yMargin = 70;
|
||||||
|
height -= yMargin*2;
|
||||||
|
width -= xMargin*2;
|
||||||
|
var radius = Math.min(height, width)/2;
|
||||||
|
|
||||||
|
var sortedSeriesValues = this.sortedSeries(this.props.report.FlattenedSeries);
|
||||||
|
var sortedSeries = sortedSeriesValues[0];
|
||||||
|
var seriesValues = sortedSeriesValues[1];
|
||||||
|
var r = d3.scaleLinear()
|
||||||
|
.range([0, 2*Math.PI])
|
||||||
|
.domain([0, sortedSeries.reduce(function(accum, curr, i, arr) {
|
||||||
|
return accum + Math.abs(seriesValues[curr]);
|
||||||
|
}, 0)]);
|
||||||
|
|
||||||
|
var slices = [];
|
||||||
|
|
||||||
|
// Add all the slices
|
||||||
|
var legendMap = {};
|
||||||
|
var childId=1;
|
||||||
|
var startAngle = 0;
|
||||||
|
for (var i=0; i < sortedSeries.length; i++) {
|
||||||
|
var child = sortedSeries[i];
|
||||||
|
var value = seriesValues[child];
|
||||||
|
if (value == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var sliceClasses = "chart-element chart-color" + (childId % 12);
|
||||||
|
var self = this;
|
||||||
|
var sliceOnClick = function() {
|
||||||
|
var childName = child;
|
||||||
|
var onSelectSeries = self.props.onSelectSeries;
|
||||||
|
return function() {
|
||||||
|
onSelectSeries(childName);
|
||||||
|
};
|
||||||
|
}();
|
||||||
|
|
||||||
|
var radians = r(Math.abs(value));
|
||||||
|
var title = child + ": " + value;
|
||||||
|
|
||||||
|
slices.push((
|
||||||
|
<Slice key={"slice-" + childId} title={title}
|
||||||
|
className={sliceClasses}
|
||||||
|
cx={width/2}
|
||||||
|
cy={height/2}
|
||||||
|
startAngle={startAngle}
|
||||||
|
angle={radians}
|
||||||
|
radius={radius}
|
||||||
|
onClick={sliceOnClick}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
legendMap[child] = childId;
|
||||||
|
childId++;
|
||||||
|
startAngle += radians;
|
||||||
|
}
|
||||||
|
|
||||||
|
var legend = [];
|
||||||
|
for (var series in legendMap) {
|
||||||
|
var legendClasses = "chart-color" + (legendMap[series] % 12);
|
||||||
|
var legendY = (legendMap[series] - 1)*15;
|
||||||
|
legend.push((
|
||||||
|
<rect key={"legend-key-"+legendMap[series]} className={legendClasses} x={0} y={legendY} width={10} height={10}/>
|
||||||
|
));
|
||||||
|
legend.push((
|
||||||
|
<text key={"legend-label-"+legendMap[series]} x={0 + 15} y={legendY + 10}>{series}</text>
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<svg height={height + 2*yMargin} width={width + 2*xMargin + legendWidth}>
|
||||||
|
<g className="pie-chart" transform={"translate("+xMargin+" "+yMargin+")"}>
|
||||||
|
{slices}
|
||||||
|
</g>
|
||||||
|
<g className="chart-legend" transform={"translate("+(width + 2*xMargin)+" "+yMargin+")"}>
|
||||||
|
{legend}
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user