d3rrc
Version:
Reusable D3 Charts for React.js
170 lines (144 loc) • 4.79 kB
JSX
var React = require('react');
var Support = require('../lib/support');
var d3 = require('d3');
var TimeSeries2Chart = React.createClass({
chart: function(selection){
var {
margin,
width,
height,
xValue,
yValue,
style
} = Support.getProps(this, 'chart', {
margin: Support.types.Object({
top: Support.types.Number(10),
right: Support.types.Number(10),
bottom: Support.types.Number(100),
left: Support.types.Number(40)
}),
width: Support.types.Number(-1),
height: Support.types.Number(400),
style: Support.types.Object(false),
xValue: Support.types.Function(function(d) {
return d[0];
}),
yValue: Support.types.Function(function(d) {
return d[1];
})
});
var margin2 = {top: height-margin.bottom+20, right: margin.right, bottom: 20, left: margin.left};
var height2 = height - margin2.top - margin2.bottom;
var h = height - margin.top - margin.bottom;
selection.each(function(data) {
var w = (width===-1?this.offsetWidth:width) - margin.left - margin.right;
data = data.map(function(d, i) {
return [xValue.call(data, d, i), yValue.call(data, d, i)];
}).sort(function(a, b){
return a[0]-b[0];
});
var brushed = function() {
x.domain(brush.empty() ? x2.domain() : brush.extent());
focus.select(".area").attr("d", area);
focus.select(".x.axis").call(xAxis);
};
var x = d3.time.scale().range([0, w]),
x2 = d3.time.scale().range([0, w]),
y = d3.scale.linear().range([h, 0]),
y2 = d3.scale.linear().range([height2, 0]);
var xAxis = d3.svg.axis().scale(x).orient("bottom"),
xAxis2 = d3.svg.axis().scale(x2).orient("bottom"),
yAxis = d3.svg.axis().scale(y).orient("left");
var brush = d3.svg.brush()
.x(x2)
.on("brush", brushed);
var area = d3.svg.area()
.interpolate("monotone")
.x(function(d) { return x(d[0]); })
.y0(h)
.y1(function(d) { return y(d[1]); });
var area2 = d3.svg.area()
.interpolate("monotone")
.x(function(d) { return x2(d[0]); })
.y0(height2)
.y1(function(d) { return y2(d[1]); });
var svg = d3.select(this).selectAll("svg").data([data]);
var svg = svg.enter().append("svg")
.attr("width", w + margin.left + margin.top)
.attr("height", h + margin.top + margin.bottom);
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", w)
.attr("height", h);
var focus = svg.append("g")
.attr("class", "focus")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var context = svg.append("g")
.attr("class", "context")
.attr("transform", "translate(" + margin2.left + "," + margin2.top + ")");
x.domain(d3.extent(data.map(function(d) { return d[0]; })));
y.domain([0, d3.max(data.map(function(d) { return d[1]; }))]);
x2.domain(x.domain());
y2.domain(y.domain());
focus.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area);
focus.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + h + ")")
.call(xAxis);
focus.append("g")
.attr("class", "y axis")
.call(yAxis);
context.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area2);
context.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height2 + ")")
.call(xAxis2);
context.append("g")
.attr("class", "x brush")
.call(brush)
.selectAll("rect")
.attr("y", -6)
.attr("height", height2 + 7);
if(style){
Object.keys(style).forEach(function(key){
svg.selectAll(key).attr('style', style[key]);
});
}
});
},
renderChart: function(data){
if(!data){
return;
}
var container = this.getDOMNode();
d3.select(container)
.datum(data)
.call(this.chart)
;
},
componentDidMount: function(){
return this.renderChart(this.props.data);
},
componentDidUpdate: function(){
return this.renderChart(this.props.data);
},
render: function(){
var classNames = Support.classList(this, {
'bar-chart': true
});
return (
<div className={classNames}>
</div>
);
}
});
module.exports = {
TimeSeries2Chart: TimeSeries2Chart
};