2 class ChartStatusView extends ComponentBase {
4 constructor(metric, chart)
10 this._usedSelection = null;
11 this._usedCurrentPoint = null;
12 this._usedPreviousPoint = null;
14 this._currentValue = null;
15 this._comparisonClass = null;
16 this._comparisonLabel = null;
18 this._renderedCurrentValue = null;
19 this._renderedComparisonClass = null;
20 this._renderedComparisonLabel = null;
25 this.updateStatusIfNeeded();
27 if (this._renderedCurrentValue == this._currentValue
28 && this._renderedComparisonClass == this._comparisonClass
29 && this._renderedComparisonLabel == this._comparisonLabel)
32 this._renderedCurrentValue = this._currentValue;
33 this._renderedComparisonClass = this._comparisonClass;
34 this._renderedComparisonLabel = this._comparisonLabel;
36 this.content().querySelector('.chart-status-current-value').textContent = this._currentValue || '';
37 var comparison = this.content().querySelector('.chart-status-comparison');
38 comparison.className = 'chart-status-comparison ' + (this._comparisonClass || '');
39 comparison.textContent = this._comparisonLabel;
42 updateStatusIfNeeded()
47 if (this._chart instanceof InteractiveTimeSeriesChart) {
48 var selection = this._chart.currentSelection();
49 if (selection && this._usedSelection == selection)
53 var data = this._chart.sampledDataBetween('current', selection[0], selection[1]);
57 if (data && data.length > 1) {
58 this._usedSelection = selection;
59 currentPoint = data[data.length - 1];
60 previousPoint = data[0];
63 currentPoint = this._chart.currentPoint();
64 previousPoint = this._chart.currentPoint(-1);
67 var data = this._chart.sampledTimeSeriesData('current');
71 currentPoint = data[data.length - 1];
74 if (currentPoint == this._usedCurrentPoint && previousPoint == this._usedPreviousPoint)
77 this._usedCurrentPoint = currentPoint;
78 this._usedPreviousPoint = previousPoint;
80 this.computeChartStatusLabels(currentPoint, previousPoint);
85 computeChartStatusLabels(currentPoint, previousPoint)
87 var status = currentPoint ? this._computeChartStatus(this._metric, this._chart, currentPoint, previousPoint) : null;
89 this._currentValue = status.currentValue;
91 this._currentValue += ` (${status.valueDelta} / ${status.relativeDelta})`;
92 this._comparisonClass = status.className;
93 this._comparisonLabel = status.label;
95 this._currentValue = null;
96 this._comparisonClass = null;
97 this._comparisonLabel = null;
101 _computeChartStatus(metric, chart, currentPoint, previousPoint)
103 var currentTimeSeriesData = chart.sampledTimeSeriesData('current');
104 var baselineTimeSeriesData = chart.sampledTimeSeriesData('baseline');
105 var targetTimeSeriesData = chart.sampledTimeSeriesData('target');
106 if (!currentTimeSeriesData)
109 var formatter = metric.makeFormatter(3);
110 var deltaFormatter = metric.makeFormatter(2, true);
113 currentPoint = currentTimeSeriesData[currentTimeSeriesData.length - 1];
115 var baselinePoint = this._findLastPointPriorToTime(currentPoint, baselineTimeSeriesData);
116 var diffFromBaseline = baselinePoint !== undefined ? (currentPoint.value - baselinePoint.value) / baselinePoint.value : undefined;
118 var targetPoint = this._findLastPointPriorToTime(currentPoint, targetTimeSeriesData);
119 var diffFromTarget = targetPoint !== undefined ? (currentPoint.value - targetPoint.value) / targetPoint.value : undefined;
124 function labelForDiff(diff, referencePoint, name, comparison)
126 var relativeDiff = Math.abs(diff * 100).toFixed(1);
127 var referenceValue = referencePoint ? ` (${formatter(referencePoint.value)})` : '';
128 return `${relativeDiff}% ${comparison} ${name}${referenceValue}`;
131 var smallerIsBetter = metric.isSmallerBetter();
132 if (diffFromBaseline !== undefined && diffFromTarget !== undefined) {
133 if (diffFromBaseline > 0 == smallerIsBetter) {
134 label = labelForDiff(diffFromBaseline, baselinePoint, 'baseline', 'worse than');
136 } else if (diffFromTarget < 0 == smallerIsBetter) {
137 label = labelForDiff(diffFromTarget, targetPoint, 'target', 'better than');
138 className = 'better';
140 label = labelForDiff(diffFromTarget, targetPoint, 'target', 'until');
141 } else if (diffFromBaseline !== undefined) {
142 className = diffFromBaseline > 0 == smallerIsBetter ? 'worse' : 'better';
143 label = labelForDiff(diffFromBaseline, baselinePoint, 'baseline', className + ' than');
144 } else if (diffFromTarget !== undefined) {
145 className = diffFromTarget < 0 == smallerIsBetter ? 'better' : 'worse';
146 label = labelForDiff(diffFromTarget, targetPoint, 'target', className + ' than');
149 var valueDelta = null;
150 var relativeDelta = null;
152 valueDelta = deltaFormatter(currentPoint.value - previousPoint.value);
153 var relativeDelta = (currentPoint.value - previousPoint.value) / previousPoint.value;
154 relativeDelta = (relativeDelta * 100).toFixed(0) + '%';
157 className: className,
159 currentValue: formatter(currentPoint.value),
160 valueDelta: valueDelta,
161 relativeDelta: relativeDelta,
165 _findLastPointPriorToTime(currentPoint, timeSeriesData)
167 if (!currentPoint || !timeSeriesData || !timeSeriesData.length)
171 while (i < timeSeriesData.length - 1 && timeSeriesData[i + 1].time < currentPoint.time)
173 return timeSeriesData[i];
176 static htmlTemplate()
180 <span class="chart-status-current-value"></span>
181 <span class="chart-status-comparison"></span>
188 .chart-status-current-value {
189 padding-right: 0.5rem;
192 .chart-status-comparison.worse {
196 .chart-status-comparison.better {