From ea97833f7a67d673c80971b91920e7f9ee4cd3f1 Mon Sep 17 00:00:00 2001 From: Ben Vinegar Date: Sun, 18 Oct 2015 22:11:25 -0400 Subject: [PATCH] Improve barchart rendering perf by deferring tooltip title creation --- .../static/sentry/app/components/barChart.jsx | 85 ++++++++++++++----- 1 file changed, 62 insertions(+), 23 deletions(-) diff --git a/src/sentry/static/sentry/app/components/barChart.jsx b/src/sentry/static/sentry/app/components/barChart.jsx index fdc1695e7fc80d..03d9879febed93 100644 --- a/src/sentry/static/sentry/app/components/barChart.jsx +++ b/src/sentry/static/sentry/app/components/barChart.jsx @@ -6,15 +6,33 @@ import TooltipMixin from "../mixins/tooltip"; var BarChart = React.createClass({ mixins: [ TooltipMixin(function () { + var barChartInstance = this; return { html: true, placement: this.props.placement, selector: ".tip", - viewport: this.props.viewport + viewport: this.props.viewport, + + // This callback is fired when the user hovers over the + // barchart / triggers tooltip rendering. This is better + // than using data-title, which renders up-front for each + // BarChart (slow). + title: function (instance) { + // `this` is the targeted element + let pointIdx = this.getAttribute('data-point-index'); + return barChartInstance.renderTooltip(pointIdx); + } }; }) ], + + statics: { + getInterval(points) { + return points.length > 1 ? points[1].x - points[0].x : null; + } + }, + propTypes: { points: React.PropTypes.arrayOf(React.PropTypes.shape({ x: React.PropTypes.number.isRequired, @@ -42,6 +60,20 @@ var BarChart = React.createClass({ }; }, + getInitialState() { + return { + interval: BarChart.getInterval(this.props.points) + }; + }, + + componentWillReceiveProps(nextProps) { + if (nextProps.points) { + this.setState({ + interval: BarChart.getInterval(nextProps.points) + }); + } + }, + shouldComponentUpdate(nextProps, nextState) { return !valueIsEqual(this.props, nextProps, true); }, @@ -91,6 +123,19 @@ var BarChart = React.createClass({ return timeMoment.format("lll"); }, + getTimeLabel(point) { + switch (this.state.interval) { + case 3600: + return this.timeLabelAsHour(point); + case 86400: + return this.timeLabelAsDay(point); + case null: + return this.timeLabelAsFull(point); + default: + return this.timeLabelAsRange(this.state.interval, point); + } + }, + maxPointValue() { var maxval = 10; this.props.points.forEach((point) => { @@ -121,10 +166,10 @@ var BarChart = React.createClass({ ); }, - renderChartColumn(point, maxval, timeLabelFunc, pointWidth) { - var pct = this.floatFormat(point.y / maxval * 99, 2) + "%"; - var timeLabel = timeLabelFunc(point); - var title = ( + renderTooltip(pointIdx) { + let point = this.props.points[pointIdx]; + let timeLabel = this.getTimeLabel(point); + let title = ( '
' + point.y + ' ' + this.props.label + '
' + timeLabel + @@ -133,9 +178,19 @@ var BarChart = React.createClass({ if (point.label) { title += '
(' + point.label + ')
'; } + return title; + }, + + renderChartColumn(pointIdx, maxval, pointWidth) { + let point = this.props.points[pointIdx]; + let pct = this.floatFormat(point.y / maxval * 99, 2) + "%"; return ( - + {point.y} ); @@ -145,22 +200,6 @@ var BarChart = React.createClass({ var points = this.props.points; var pointWidth = this.floatFormat(100.0 / points.length, 2) + "%"; - var interval = (points.length > 1 ? points[1].x - points[0].x : null); - var timeLabelFunc; - switch (interval) { - case 3600: - timeLabelFunc = this.timeLabelAsHour; - break; - case 86400: - timeLabelFunc = this.timeLabelAsDay; - break; - case null: - timeLabelFunc = this.timeLabelAsFull; - break; - default: - timeLabelFunc = this.timeLabelAsRange.bind(this, interval); - } - var maxval = this.maxPointValue(); var markers = this.props.markers.slice(); @@ -171,7 +210,7 @@ var BarChart = React.createClass({ children.push(this.renderMarker(markers.shift())); } - children.push(this.renderChartColumn(point, maxval, timeLabelFunc, pointWidth)); + children.push(this.renderChartColumn(pointIdx, maxval, pointWidth)); }); // in bizarre case where markers never got rendered, render them last