Multi-series bar chart rendered using React and D3.
Last active
September 19, 2019 18:30
-
-
Save slashdotdash/8342273 to your computer and use it in GitHub Desktop.
React + D3 (v2)
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
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<title>React + d3</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.5.2/underscore.js"></script> | |
<script src="http://cdnjs.cloudflare.com/ajax/libs/react/0.8.0/react.js"></script> | |
<script src="http://cdnjs.cloudflare.com/ajax/libs/react/0.8.0/JSXTransformer.js"></script> | |
<script src="http://cdnjs.cloudflare.com/ajax/libs/d3/3.3.13/d3.js"></script> | |
</head> | |
<body> | |
<div id="container"> </div> | |
<script type="text/jsx"> | |
/** @jsx React.DOM */ | |
var Chart = React.createClass({ | |
render: function() { | |
return ( | |
<svg width={this.props.width} height={this.props.height}>{this.props.children}</svg> | |
); | |
} | |
}); | |
var Bar = React.createClass({ | |
getDefaultProps: function() { | |
return { | |
width: 0, | |
height: 0, | |
x: 0, | |
y: 0 | |
} | |
}, | |
render: function() { | |
return ( | |
<rect fill={this.props.color} | |
width={this.props.width} height={this.props.height} | |
x={this.props.x} y={this.props.y} /> | |
); | |
} | |
}); | |
var DataSeries = React.createClass({ | |
getDefaultProps: function() { | |
return { | |
title: '', | |
data: [] | |
} | |
}, | |
render: function() { | |
var self = this, | |
props = this.props, | |
refs = props.__owner__.refs | |
size = props.size, | |
width = size.width, | |
height = size.height; | |
var yScale = props.yScale; | |
var xScale = d3.scale.ordinal() | |
.domain(d3.range(props.data.length)) | |
.rangeRoundBands([0, width], 0.05); | |
var otherSeries = _.chain(refs) | |
.values() | |
.reject(function(component) { return component === self; }) | |
.value(); | |
var bars = _.map(props.data, function(point, i) { | |
var yOffset = _.reduce(otherSeries, function(memo, series) { | |
return memo + series.props.data[i]; | |
}, 0); | |
return ( | |
<Bar height={yScale(point)} width={xScale.rangeBand()} x={xScale(i)} y={size.height - yScale(yOffset) - yScale(point)} color={props.color} key={i} /> | |
) | |
}); | |
return ( | |
<g>{bars}</g> | |
); | |
} | |
}); | |
var StackedBarChart = React.createClass({ | |
getDefaultProps: function() { | |
return { | |
width: 600, | |
height: 300 | |
} | |
}, | |
render: function() { | |
var data = this.props.data, | |
size = { width: this.props.width, height: this.props.height }; | |
var zipped = _.zip(data.series1, data.series2, data.series3); | |
var totals = _.map(zipped, function(values) { | |
return _.reduce(values, function(memo, value) { return memo + value; }, 0); | |
}); | |
var yScale = d3.scale.linear() | |
.domain([0, d3.max(totals)]) | |
.range([0, this.props.height]); | |
return ( | |
<Chart width={this.props.width} height={this.props.height}> | |
<DataSeries data={data.series1} size={size} yScale={yScale} ref="series1" color="cornflowerblue" /> | |
<DataSeries data={data.series2} size={size} yScale={yScale} ref="series2" color="red" /> | |
<DataSeries data={data.series3} size={size} yScale={yScale} ref="series3" color="green" /> | |
</Chart> | |
); | |
} | |
}); | |
var data = { | |
series1: [ 30, 10, 5, 8, 15, 10 ], | |
series2: [ 5, 20, 12, 4, 6, 2 ], | |
series3: [ 5, 8, 2, 4, 6, 2 ] | |
}; | |
React.renderComponent( | |
<StackedBarChart data={data} />, | |
document.getElementById('container') | |
); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment