Skip to content

Commit cb9e13b

Browse files
committed
Improve barchart rendering perf by deferring tooltip title creation
1 parent 964d061 commit cb9e13b

File tree

1 file changed

+62
-23
lines changed

1 file changed

+62
-23
lines changed

src/sentry/static/sentry/app/components/barChart.jsx

Lines changed: 62 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,33 @@ import TooltipMixin from "../mixins/tooltip";
66
var BarChart = React.createClass({
77
mixins: [
88
TooltipMixin(function () {
9+
var barChartInstance = this;
910
return {
1011
html: true,
1112
placement: this.props.placement,
1213
selector: ".tip",
13-
viewport: this.props.viewport
14+
viewport: this.props.viewport,
15+
16+
// This callback is fired when the user hovers over the
17+
// barchart / triggers tooltip rendering. This is better
18+
// than using data-title, which renders up-front for each
19+
// BarChart (slow).
20+
title: function (instance) {
21+
// `this` is the targeted element
22+
let pointIdx = this.getAttribute('data-point-index');
23+
return barChartInstance.renderTooltip(pointIdx);
24+
}
1425
};
1526
})
1627
],
1728

29+
30+
statics: {
31+
getInterval(points) {
32+
return points.length > 1 ? points[1].x - points[0].x : null;
33+
}
34+
},
35+
1836
propTypes: {
1937
points: React.PropTypes.arrayOf(React.PropTypes.shape({
2038
x: React.PropTypes.number.isRequired,
@@ -42,6 +60,20 @@ var BarChart = React.createClass({
4260
};
4361
},
4462

63+
getInitialState() {
64+
return {
65+
interval: BarChart.getInterval(this.props.points)
66+
};
67+
},
68+
69+
componentWillReceiveProps(nextProps) {
70+
if (nextProps.points) {
71+
this.setState({
72+
interval: BarChart.getInterval(nextProps.points)
73+
});
74+
}
75+
},
76+
4577
shouldComponentUpdate(nextProps, nextState) {
4678
return !valueIsEqual(this.props, nextProps, true);
4779
},
@@ -91,6 +123,19 @@ var BarChart = React.createClass({
91123
return timeMoment.format("lll");
92124
},
93125

126+
getTimeLabel(point) {
127+
switch (this.state.interval) {
128+
case 3600:
129+
return this.timeLabelAsHour(point);
130+
case 86400:
131+
return this.timeLabelAsDay(point);
132+
case null:
133+
return this.timeLabelAsFull(point);
134+
default:
135+
return this.timeLabelAsRange(this.state.interval, point);
136+
}
137+
},
138+
94139
maxPointValue() {
95140
var maxval = 10;
96141
this.props.points.forEach((point) => {
@@ -121,10 +166,10 @@ var BarChart = React.createClass({
121166
);
122167
},
123168

124-
renderChartColumn(point, maxval, timeLabelFunc, pointWidth) {
125-
var pct = this.floatFormat(point.y / maxval * 99, 2) + "%";
126-
var timeLabel = timeLabelFunc(point);
127-
var title = (
169+
renderTooltip(pointIdx) {
170+
let point = this.props.points[pointIdx];
171+
let timeLabel = this.getTimeLabel(point);
172+
let title = (
128173
'<div style="width:130px">' +
129174
point.y + ' ' + this.props.label + '<br/>' +
130175
timeLabel +
@@ -133,9 +178,19 @@ var BarChart = React.createClass({
133178
if (point.label) {
134179
title += '<div>(' + point.label + ')</div>';
135180
}
181+
return title;
182+
},
183+
184+
renderChartColumn(pointIdx, maxval, pointWidth) {
185+
let point = this.props.points[pointIdx];
186+
let pct = this.floatFormat(point.y / maxval * 99, 2) + "%";
136187

137188
return (
138-
<a key={point.x} className="chart-column tip" data-title={title} style={{ width: pointWidth }}>
189+
<a key={point.x}
190+
className="chart-column tip"
191+
data-point-index={pointIdx}
192+
style={{ width: pointWidth }}
193+
>
139194
<span style={{ height: pct }}>{point.y}</span>
140195
</a>
141196
);
@@ -145,22 +200,6 @@ var BarChart = React.createClass({
145200
var points = this.props.points;
146201
var pointWidth = this.floatFormat(100.0 / points.length, 2) + "%";
147202

148-
var interval = (points.length > 1 ? points[1].x - points[0].x : null);
149-
var timeLabelFunc;
150-
switch (interval) {
151-
case 3600:
152-
timeLabelFunc = this.timeLabelAsHour;
153-
break;
154-
case 86400:
155-
timeLabelFunc = this.timeLabelAsDay;
156-
break;
157-
case null:
158-
timeLabelFunc = this.timeLabelAsFull;
159-
break;
160-
default:
161-
timeLabelFunc = this.timeLabelAsRange.bind(this, interval);
162-
}
163-
164203
var maxval = this.maxPointValue();
165204

166205
var markers = this.props.markers.slice();
@@ -171,7 +210,7 @@ var BarChart = React.createClass({
171210
children.push(this.renderMarker(markers.shift()));
172211
}
173212

174-
children.push(this.renderChartColumn(point, maxval, timeLabelFunc, pointWidth));
213+
children.push(this.renderChartColumn(pointIdx, maxval, pointWidth));
175214
});
176215

177216
// in bizarre case where markers never got rendered, render them last

0 commit comments

Comments
 (0)