Stacked area chart animations
This commit is contained in:
parent
a660f4ea3b
commit
93a88481c4
|
@ -1,17 +1,21 @@
|
||||||
var StackedAreaChart = React.createClass({
|
var StackedAreaChart = React.createClass({
|
||||||
mixins: [Router.Navigation, Router.State],
|
mixins: [Router.Navigation, Router.State, Chart],
|
||||||
|
|
||||||
numElements: 10,
|
numElements: 10,
|
||||||
|
maxWeeks: 20,
|
||||||
height: 250,
|
height: 250,
|
||||||
|
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
return {
|
return {
|
||||||
|
currentApi: null,
|
||||||
|
currentParams: null,
|
||||||
item: this.props.items[0],
|
item: this.props.items[0],
|
||||||
rawData: [],
|
rawData: [],
|
||||||
top: [],
|
top: [],
|
||||||
max: 1,
|
max: 1,
|
||||||
weeks: [],
|
weeks: [],
|
||||||
canvasWidth: 500
|
canvasWidth: 0,
|
||||||
|
state: 'initial'
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -23,21 +27,29 @@ var StackedAreaChart = React.createClass({
|
||||||
|
|
||||||
componentWillReceiveProps: function(newProps) {
|
componentWillReceiveProps: function(newProps) {
|
||||||
this.setState({
|
this.setState({
|
||||||
'item': newProps.items[0],
|
item: newProps.items[0],
|
||||||
'sort': 'commits'
|
sort: 'commits',
|
||||||
|
state: 'newProps'
|
||||||
}, this.fetchData);
|
}, this.fetchData);
|
||||||
},
|
},
|
||||||
|
|
||||||
calculateViewBoxWidth: function() {
|
shouldComponentUpdate: function(newProps, newState) {
|
||||||
this.setState({
|
// console.log("Should update?", newState.state);
|
||||||
canvasWidth: this.refs.svg.getDOMNode().offsetWidth
|
if (newState.canvasWidth === 0) {
|
||||||
});
|
return false;
|
||||||
|
}
|
||||||
|
if (newState.state !== 'newPoints') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// console.log("Updating!");
|
||||||
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
handleFilter: function(thing, i) {
|
handleFilter: function(thing, i) {
|
||||||
if (this.props.items[i] !== this.state.item) {
|
if (this.props.items[i] !== this.state.item) {
|
||||||
this.setState({
|
this.setState({
|
||||||
item: this.props.items[i]
|
item: this.props.items[i],
|
||||||
|
state: 'newProps'
|
||||||
}, this.fetchData);
|
}, this.fetchData);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -49,10 +61,26 @@ var StackedAreaChart = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
fetchData: function() {
|
fetchData: function() {
|
||||||
$.get(this.props.api, this.apiParams(), function(res){
|
if (!this.apiParams().item) {
|
||||||
this.setState({
|
return;
|
||||||
rawData: res
|
}
|
||||||
}, this.buildPoints);
|
if (this.state.currentApi === this.props.api &&
|
||||||
|
this.state.currentParams === JSON.stringify(this.apiParams())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// console.log('-----> fetching', this.props.api, this.state.item);
|
||||||
|
this.setState({
|
||||||
|
currentApi: this.props.api,
|
||||||
|
currentParams: JSON.stringify(this.apiParams()),
|
||||||
|
state: 'loadingData'
|
||||||
|
}, function() {
|
||||||
|
$.get(this.props.api, this.apiParams(), function(res){
|
||||||
|
this.setState({
|
||||||
|
rawData: res,
|
||||||
|
state: 'newData'
|
||||||
|
}, this.buildPoints);
|
||||||
|
}.bind(this));
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -99,10 +127,12 @@ var StackedAreaChart = React.createClass({
|
||||||
// return _.sum(_.values(items));
|
// return _.sum(_.values(items));
|
||||||
// }));
|
// }));
|
||||||
|
|
||||||
|
// console.log("New points!");
|
||||||
this.setState({
|
this.setState({
|
||||||
top: top,
|
top: top,
|
||||||
max: max,
|
max: max,
|
||||||
weeks: weeks
|
weeks: weeks,
|
||||||
|
state: 'newPoints'
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -117,18 +147,11 @@ var StackedAreaChart = React.createClass({
|
||||||
d.unshift('M0,'+ maxHeight);
|
d.unshift('M0,'+ maxHeight);
|
||||||
d.push('L'+ maxWidth +','+ maxHeight +'Z');
|
d.push('L'+ maxWidth +','+ maxHeight +'Z');
|
||||||
|
|
||||||
// for (var i = 0; i < missing; i++) {
|
|
||||||
// d.push('L'+ i +','+ this.props.height/2);
|
|
||||||
// }
|
|
||||||
// for (var i = 0; i < points.length; i++) {
|
|
||||||
// d.push('L'+ missing+i +','+ points[i]);
|
|
||||||
// }
|
|
||||||
// d.push('L'+ this.props.width +','+ this.props.height/2, 'Z');
|
|
||||||
|
|
||||||
return d.join(' ');
|
return d.join(' ');
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
|
// console.log("Rendering!");
|
||||||
var maxWidth = this.state.canvasWidth,
|
var maxWidth = this.state.canvasWidth,
|
||||||
maxHeight = this.height,
|
maxHeight = this.height,
|
||||||
rtop = this.state.top.reverse(),
|
rtop = this.state.top.reverse(),
|
||||||
|
@ -151,27 +174,49 @@ var StackedAreaChart = React.createClass({
|
||||||
return [week, points];
|
return [week, points];
|
||||||
})
|
})
|
||||||
.sort(0)
|
.sort(0)
|
||||||
|
.reverse()
|
||||||
|
.take(this.maxWeeks)
|
||||||
|
.reverse()
|
||||||
.value();
|
.value();
|
||||||
|
|
||||||
var paths = _.reduce(rtop, function(res, item, i) {
|
var paths = _.reduce(rtop, function(res, item, i) {
|
||||||
res[item] = _.map(points, function(pair) {
|
res[item] = _.map(points, function(pair) {
|
||||||
return pair[1][i];
|
return pair[1][i];
|
||||||
}).slice(-15);
|
});
|
||||||
return res;
|
return res;
|
||||||
}, {});
|
}, {});
|
||||||
|
var paths = _.map(rtop, function(item, i) {
|
||||||
|
var itemPoints = _.map(points, function(pair) {
|
||||||
|
return pair[1][i];
|
||||||
|
});
|
||||||
|
return[item, itemPoints];
|
||||||
|
});
|
||||||
|
|
||||||
var i = -1;
|
|
||||||
var colors = {}
|
var colors = {}
|
||||||
var areas = _.map(paths, function(path, item) {
|
// console.log('----- Areas!');
|
||||||
i++;
|
var areas = _.map(paths, function(pair, i) {
|
||||||
|
var item = pair[0], path = pair[1];
|
||||||
colors[item] = Colors2[i];
|
colors[item] = Colors2[i];
|
||||||
|
// console.log("Building path for", item, path);
|
||||||
|
// console.log('Area', i);
|
||||||
return (
|
return (
|
||||||
<StackedArea key={'sa-item-'+ item}
|
<StackedArea key={'area-'+ i}
|
||||||
item={item}
|
item={item}
|
||||||
path={roundPathCorners(this.buildPathD(path), 5)}
|
d={roundPathCorners(this.buildPathD(path), 5)}
|
||||||
color={Colors2[i]} />
|
color={colors[item]} />
|
||||||
);
|
);
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
areas = areas.reverse();
|
||||||
|
for (var i = areas.length; i < this.numElements; i++) {
|
||||||
|
// console.log('Area (empty)', i);
|
||||||
|
var d = 'M0,'+ this.height +' L'+ maxWidth +','+ maxHeight +'Z';
|
||||||
|
areas.push(
|
||||||
|
<StackedArea key={'area-'+ i}
|
||||||
|
item={''}
|
||||||
|
d={d}
|
||||||
|
color="rgba(0, 0, 0, 0)" />
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="sachart-container">
|
<div className="sachart-container">
|
||||||
|
@ -184,10 +229,10 @@ var StackedAreaChart = React.createClass({
|
||||||
items={['commits']}
|
items={['commits']}
|
||||||
value={'commits'} />
|
value={'commits'} />
|
||||||
</div>
|
</div>
|
||||||
<svg ref="svg" className="sachart"
|
<svg ref="svg" className="sachart" key="sachart-svg"
|
||||||
width="100%" height={maxHeight}
|
width="100%" height={maxHeight}
|
||||||
viewBox={"0 0 "+ this.state.canvasWidth + " "+ maxHeight}>
|
viewBox={"0 0 "+ this.state.canvasWidth + " "+ maxHeight}>
|
||||||
{areas.reverse()}
|
{areas}
|
||||||
</svg>
|
</svg>
|
||||||
<ul className="legend">
|
<ul className="legend">
|
||||||
{_.pairs(colors).map(function(pair){
|
{_.pairs(colors).map(function(pair){
|
||||||
|
@ -205,10 +250,33 @@ var StackedAreaChart = React.createClass({
|
||||||
});
|
});
|
||||||
|
|
||||||
var StackedArea = React.createClass({
|
var StackedArea = React.createClass({
|
||||||
|
mixins: [Chart],
|
||||||
|
easing: '0.55, 0.055, 0.675, 0.19',
|
||||||
|
|
||||||
|
getInitialState: function() {
|
||||||
|
return {lastd: ''};
|
||||||
|
},
|
||||||
|
|
||||||
|
componentDidMount: function() {
|
||||||
|
// console.log("-- mounted area");
|
||||||
|
},
|
||||||
|
|
||||||
|
componentWillReceiveProps: function(newProps) {
|
||||||
|
// console.log("New area props!", newProps.item);
|
||||||
|
this.setState({
|
||||||
|
lastd: this.props.d,
|
||||||
|
}, this.state.lastd === '' ? null : this.animateAll);
|
||||||
|
},
|
||||||
|
|
||||||
|
animateAll: function() {
|
||||||
|
// console.log("Animating area", this.props.item);
|
||||||
|
this.animate(this.refs.path, 'd', this.state.lastd, this.props.d);
|
||||||
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
return (
|
return (
|
||||||
<path key={'sac-area-'+ this.props.item}
|
<path ref="path"
|
||||||
d={this.props.path}
|
d={this.props.d}
|
||||||
fill={this.props.color}
|
fill={this.props.color}
|
||||||
shapeRendering="optimizeQuality" />
|
shapeRendering="optimizeQuality" />
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue