OLD | NEW |
1 <!DOCTYPE html> | 1 <!DOCTYPE html> |
2 <!-- | 2 <!-- |
3 Copyright 2016 The Chromium Authors. All rights reserved. | 3 Copyright 2016 The Chromium Authors. All rights reserved. |
4 Use of this source code is governed by a BSD-style license that can be | 4 Use of this source code is governed by a BSD-style license that can be |
5 found in the LICENSE file. | 5 found in the LICENSE file. |
6 --> | 6 --> |
7 | 7 |
8 <link rel="import" href="/tracing/base/fixed_color_scheme.html"> | 8 <link rel="import" href="/tracing/base/fixed_color_scheme.html"> |
9 <link rel="import" href="/tracing/extras/chrome/chrome_user_friendly_category_dr
iver.html"> | 9 <link rel="import" href="/tracing/extras/chrome/chrome_user_friendly_category_dr
iver.html"> |
10 <link rel="import" href="/tracing/metrics/all_fixed_color_schemes.html"> | 10 <link rel="import" href="/tracing/metrics/all_fixed_color_schemes.html"> |
(...skipping 24 matching lines...) Expand all Loading... |
35 <div id="container"></div> | 35 <div id="container"></div> |
36 <span> | 36 <span> |
37 <tr-ui-b-table id="table"></tr-ui-b-table> | 37 <tr-ui-b-table id="table"></tr-ui-b-table> |
38 </span> | 38 </span> |
39 </div> | 39 </div> |
40 </template> | 40 </template> |
41 </dom-module> | 41 </dom-module> |
42 | 42 |
43 <script> | 43 <script> |
44 'use strict'; | 44 'use strict'; |
45 | |
46 tr.exportTo('tr.v.ui', function() { | 45 tr.exportTo('tr.v.ui', function() { |
47 const DEFAULT_COLOR_SCHEME = new tr.b.SinebowColorGenerator(); | 46 const DEFAULT_COLOR_SCHEME = new tr.b.SinebowColorGenerator(); |
48 | 47 |
| 48 function getHistogramName(histogram, diagnosticName, key) { |
| 49 const nameMap = histogram.diagnostics.get(diagnosticName); |
| 50 if (nameMap === undefined) return undefined; |
| 51 return nameMap.get(key); |
| 52 } |
| 53 |
| 54 function getColorScheme(colorSchemeName) { |
| 55 if (colorSchemeName === |
| 56 tr.v.d.COLOR_SCHEME_CHROME_USER_FRIENDLY_CATEGORY_DRIVER) { |
| 57 return name => { |
| 58 let cat = name.split(' '); |
| 59 cat = cat[cat.length - 1]; |
| 60 return tr.e.chrome.ChromeUserFriendlyCategoryDriver.getColor(cat); |
| 61 }; |
| 62 } |
| 63 |
| 64 if (colorSchemeName !== undefined) { |
| 65 return name => tr.b.FixedColorSchemeRegistry.lookUp( |
| 66 colorSchemeName).getColor(name); |
| 67 } |
| 68 |
| 69 return name => DEFAULT_COLOR_SCHEME.colorForKey(name); |
| 70 } |
| 71 |
| 72 function getUnit(name, histograms) { |
| 73 const candidates = histograms.getHistogramsNamed(name); |
| 74 if (candidates.length === 0) return undefined; |
| 75 return candidates[0].unit; |
| 76 } |
| 77 |
49 class BreakdownTableSummaryRow { | 78 class BreakdownTableSummaryRow { |
50 constructor(displayElement, histogramNames) { | 79 constructor(valueSpan, histogramNames) { |
51 this.displayElement_ = displayElement; | 80 this.valueSpan_ = valueSpan; |
52 this.histogramNames_ = histogramNames; | 81 this.histogramNames_ = histogramNames; |
53 this.keySpan_ = undefined; | 82 this.keySpan_ = undefined; |
54 } | 83 } |
55 | 84 |
56 get numberValue() { | 85 get sanitizedValue() { |
57 // Prevent this row from appearing in the ColumnChart. | 86 // Prevent this row from appearing in the ColumnChart. |
58 return undefined; | 87 return undefined; |
59 } | 88 } |
60 | 89 |
61 get keySpan() { | 90 get keySpan() { |
62 if (this.keySpan_ === undefined) { | 91 if (this.keySpan_ === undefined) { |
63 if (this.histogramNames_.length) { | 92 if (this.histogramNames_.length) { |
64 this.keySpan_ = document.createElement('tr-ui-a-analysis-link'); | 93 this.keySpan_ = document.createElement('tr-ui-a-analysis-link'); |
65 this.keySpan_.setSelectionAndContent( | 94 this.keySpan_.setSelectionAndContent( |
66 this.histogramNames_, 'Select All'); | 95 this.histogramNames_, 'Select All'); |
67 } else { | 96 } else { |
68 this.keySpan_ = 'Sum'; | 97 this.keySpan_ = 'Sum'; |
69 } | 98 } |
70 } | 99 } |
71 return this.keySpan_; | 100 return this.keySpan_; |
72 } | 101 } |
73 | 102 |
74 get name() { | 103 get name() { |
75 return 'Sum'; | 104 return 'Sum'; |
76 } | 105 } |
77 | 106 |
78 get displayElement() { | 107 get valueSpan() { |
79 return this.displayElement_; | 108 return this.valueSpan_; |
80 } | 109 } |
81 | 110 |
82 get stringPercent() { | 111 get percentString() { |
83 return '100%'; | 112 return '100%'; |
84 } | 113 } |
85 } | 114 } |
86 | 115 |
87 class BreakdownTableRow { | 116 class BreakdownTableRow { |
88 constructor(name, value, unit, color) { | 117 constructor(name, value, histogramName, unit, color) { |
89 this.name_ = name; | 118 this.name_ = name; |
90 this.value = value; | 119 this.value_ = value; |
91 this.unit = unit; | 120 this.histogramName_ = histogramName; |
| 121 this.unit_ = unit; |
92 | 122 |
93 if (!this.isHistogram && typeof value !== 'number') { | 123 if (typeof value !== 'number') { |
94 throw new Error('unsupported value ' + value); | 124 throw new Error('unsupported value ' + value); |
95 } | 125 } |
96 | 126 |
97 this.tableSum_ = undefined; | 127 this.tableSum_ = undefined; |
98 this.keySpan_ = undefined; | 128 this.keySpan_ = undefined; |
99 | 129 |
100 this.color_ = color; | 130 this.color_ = color; |
101 const hsl = this.color.toHSL(); | 131 const hsl = this.color.toHSL(); |
102 hsl.l *= 0.85; | 132 hsl.l *= 0.85; |
103 this.highlightedColor_ = tr.b.Color.fromHSL(hsl); | 133 this.highlightedColor_ = tr.b.Color.fromHSL(hsl); |
104 | 134 |
105 if (this.isHistogram) { | 135 if (this.sanitizedValue !== undefined && this.unit_) { |
106 this.displayElement_ = tr.v.ui.createScalarSpan(this.numberValue, { | 136 this.valueSpan_ = tr.v.ui.createScalarSpan(this.sanitizedValue, { |
107 unit: this.value.unit, | 137 unit: this.unit_, |
108 }); | 138 }); |
109 } else { | 139 } else { |
110 this.displayElement_ = tr.ui.b.createSpan({ | 140 this.valueSpan_ = tr.ui.b.createSpan({ |
111 textContent: this.stringValue, | 141 textContent: this.stringValue, |
112 }); | 142 }); |
113 } | 143 } |
114 } | 144 } |
115 | 145 |
116 get isHistogram() { | |
117 return this.value instanceof tr.v.Histogram; | |
118 } | |
119 | |
120 get name() { | 146 get name() { |
121 return this.name_; | 147 return this.name_; |
122 } | 148 } |
123 | 149 |
| 150 /** |
| 151 * @return {number|undefined} |
| 152 */ |
| 153 get sanitizedValue() { |
| 154 if (isNaN(this.value_) || |
| 155 this.value_ === Infinity || |
| 156 this.value_ === -Infinity || |
| 157 this.value_ < 0) { |
| 158 return undefined; |
| 159 } |
| 160 return this.value_; |
| 161 } |
| 162 |
124 get color() { | 163 get color() { |
125 return this.color_; | 164 return this.color_; |
126 } | 165 } |
127 | 166 |
128 get highlightedColor() { | 167 get highlightedColor() { |
129 return this.highlightedColor_; | 168 return this.highlightedColor_; |
130 } | 169 } |
131 | 170 |
132 get keySpan() { | 171 get keySpan() { |
133 if (this.keySpan_ === undefined) { | 172 if (this.keySpan_ === undefined) { |
134 if (this.isHistogram) { | 173 if (this.histogramName_) { |
135 this.keySpan_ = document.createElement('tr-ui-a-analysis-link'); | 174 this.keySpan_ = document.createElement('tr-ui-a-analysis-link'); |
136 this.keySpan_.setSelectionAndContent([this.value.name], this.name); | 175 this.keySpan_.setSelectionAndContent( |
| 176 [this.histogramName_], this.name); |
137 this.keySpan_.color = this.color; | 177 this.keySpan_.color = this.color; |
138 this.keySpan_.title = this.value.name; | 178 this.keySpan_.title = this.histogramName_; |
139 } else { | 179 } else { |
140 this.keySpan_ = document.createElement('span'); | 180 this.keySpan_ = tr.ui.b.createSpan({ |
141 this.keySpan_.innerText = this.name; | 181 textContent: this.name, |
142 this.keySpan_.style.color = this.color; | 182 color: this.color, |
| 183 }); |
143 } | 184 } |
144 } | 185 } |
145 return this.keySpan_; | 186 return this.keySpan_; |
146 } | 187 } |
147 | 188 |
148 /** | |
149 * @return {number|undefined} | |
150 */ | |
151 get numberValue() { | |
152 if (this.isHistogram) return this.value.sum; | |
153 if (!isNaN(this.value) && | |
154 (this.value !== Infinity) && | |
155 (this.value !== -Infinity) && | |
156 (this.value > 0)) return this.value; | |
157 // Prevent this row from appearing in the ColumnChart. | |
158 return undefined; | |
159 } | |
160 | |
161 get stringValue() { | 189 get stringValue() { |
162 if (!this.isHistogram && | 190 if (this.unit !== undefined) return this.unit.format(this.value_); |
163 (isNaN(this.value) || | 191 return this.value_.toString(); |
164 this.value === Infinity || | |
165 this.value === -Infinity)) { | |
166 return this.value.toString(); | |
167 } | |
168 if (this.unit !== undefined) return this.unit.format(this.value); | |
169 if (this.isHistogram) return this.value.sum.toString(); | |
170 return this.value.toString(); | |
171 } | 192 } |
172 | 193 |
173 set tableSum(s) { | 194 set tableSum(s) { |
174 this.tableSum_ = s; | 195 this.tableSum_ = s; |
175 } | 196 } |
176 | 197 |
177 get stringPercent() { | 198 get percentString() { |
178 if (this.tableSum_ === undefined) return ''; | 199 if (this.tableSum_ === undefined) return ''; |
179 const num = this.numberValue; | 200 const num = this.sanitizedValue; |
180 if (num === undefined) return ''; | 201 if (num === undefined) return ''; |
181 return Math.floor(num * 100.0 / this.tableSum_) + '%'; | 202 return Math.floor(num * 100.0 / this.tableSum_) + '%'; |
182 } | 203 } |
183 | 204 |
184 get displayElement() { | 205 get valueSpan() { |
185 return this.displayElement_; | 206 return this.valueSpan_; |
186 } | 207 } |
187 | 208 |
188 compare(other) { | 209 compare(other) { |
189 if (this.numberValue === undefined) { | 210 if (this.sanitizedValue === undefined) { |
190 if (other.numberValue === undefined) { | 211 if (other.sanitizedValue === undefined) { |
191 return this.name.localeCompare(other.name); | 212 return this.name.localeCompare(other.name); |
192 } | 213 } |
193 return 1; | 214 return 1; |
194 } | 215 } |
195 if (other.numberValue === undefined) { | 216 if (other.sanitizedValue === undefined) { |
196 return -1; | 217 return -1; |
197 } | 218 } |
198 if (this.numberValue === other.numberValue) { | 219 if (this.sanitizedValue === other.sanitizedValue) { |
199 return this.name.localeCompare(other.name); | 220 return this.name.localeCompare(other.name); |
200 } | 221 } |
201 return other.numberValue - this.numberValue; | 222 return other.sanitizedValue - this.sanitizedValue; |
202 } | 223 } |
203 } | 224 } |
204 | 225 |
205 Polymer({ | 226 Polymer({ |
206 is: 'tr-v-ui-breakdown-span', | 227 is: 'tr-v-ui-breakdown-span', |
207 behaviors: [tr.v.ui.DIAGNOSTIC_SPAN_BEHAVIOR], | 228 behaviors: [tr.v.ui.DIAGNOSTIC_SPAN_BEHAVIOR], |
208 | 229 |
209 created() { | 230 created() { |
210 this.chart_ = new tr.ui.b.ColumnChart(); | 231 this.chart_ = new tr.ui.b.ColumnChart(); |
211 this.chart_.graphHeight = 130; | 232 this.chart_.graphHeight = 130; |
212 this.chart_.isStacked = true; | 233 this.chart_.isStacked = true; |
213 this.chart_.hideXAxis = true; | 234 this.chart_.hideXAxis = true; |
214 this.chart_.hideLegend = true; | 235 this.chart_.hideLegend = true; |
215 this.chart_.enableHoverBox = false; | 236 this.chart_.enableHoverBox = false; |
216 this.chart_.addEventListener('rect-mouseenter', | 237 this.chart_.addEventListener('rect-mouseenter', |
217 event => this.onRectMouseEnter_(event)); | 238 event => this.onRectMouseEnter_(event)); |
218 this.chart_.addEventListener('rect-mouseleave', | 239 this.chart_.addEventListener('rect-mouseleave', |
219 event => this.onRectMouseLeave_(event)); | 240 event => this.onRectMouseLeave_(event)); |
220 }, | 241 }, |
221 | 242 |
222 onRectMouseEnter_(event) { | 243 onRectMouseEnter_(event) { |
223 for (const row of this.$.table.tableRows) { | 244 for (const row of this.$.table.tableRows) { |
224 if (row.name === event.rect.key) { | 245 if (row.name === event.rect.key) { |
225 row.displayElement.style.background = event.rect.color; | 246 row.valueSpan.style.background = event.rect.color; |
226 row.keySpan.scrollIntoViewIfNeeded(); | 247 row.keySpan.scrollIntoViewIfNeeded(); |
227 } else { | 248 } else { |
228 row.displayElement.style.background = ''; | 249 row.valueSpan.style.background = ''; |
229 } | 250 } |
230 } | 251 } |
231 }, | 252 }, |
232 | 253 |
233 onRectMouseLeave_(event) { | 254 onRectMouseLeave_(event) { |
234 for (const row of this.$.table.tableRows) { | 255 for (const row of this.$.table.tableRows) { |
235 row.displayElement.style.background = ''; | 256 row.valueSpan.style.background = ''; |
236 } | 257 } |
237 }, | 258 }, |
238 | 259 |
239 ready() { | 260 ready() { |
240 Polymer.dom(this.$.container).appendChild(this.chart_); | 261 Polymer.dom(this.$.container).appendChild(this.chart_); |
241 | 262 |
242 this.$.table.zebra = true; | 263 this.$.table.zebra = true; |
243 this.$.table.showHeader = false; | 264 this.$.table.showHeader = false; |
244 this.$.table.tableColumns = [ | 265 this.$.table.tableColumns = [ |
245 { | 266 { |
246 value: row => row.keySpan, | 267 value: row => row.keySpan, |
247 }, | 268 }, |
248 { | 269 { |
249 value: row => row.displayElement, | 270 value: row => row.valueSpan, |
250 align: tr.ui.b.TableFormat.ColumnAlignment.RIGHT, | 271 align: tr.ui.b.TableFormat.ColumnAlignment.RIGHT, |
251 }, | 272 }, |
252 { | 273 { |
253 value: row => row.stringPercent, | 274 value: row => row.percentString, |
254 align: tr.ui.b.TableFormat.ColumnAlignment.RIGHT, | 275 align: tr.ui.b.TableFormat.ColumnAlignment.RIGHT, |
255 }, | 276 }, |
256 ]; | 277 ]; |
257 }, | 278 }, |
258 | 279 |
259 updateContents_() { | 280 updateContents_() { |
260 this.$.container.style.display = 'none'; | 281 this.$.container.style.display = 'none'; |
261 this.$.table.style.display = 'none'; | 282 this.$.table.style.display = 'none'; |
262 this.$.empty.style.display = 'block'; | 283 this.$.empty.style.display = 'block'; |
263 | 284 |
264 if (!this.diagnostic_) { | 285 if (!this.diagnostic_ || this.diagnostic_.size === 0) { |
265 this.chart_.data = []; | 286 this.chart_.data = []; |
266 return; | 287 return; |
267 } | 288 } |
268 | 289 |
269 if (this.histogram_) this.chart_.unit = this.histogram_.unit; | 290 const colorScheme = getColorScheme(this.diagnostic.colorScheme); |
| 291 const tableRows = []; |
| 292 const histogramNames = new Set(); |
| 293 let tableSum = 0; |
| 294 let conflictingUnits = false; |
| 295 for (const [key, value] of this.diagnostic) { |
| 296 const histogramName = getHistogramName(this.histogram_, this.name_, |
| 297 key); |
| 298 let unit = this.histogram_.unit; |
| 299 if (histogramName) { |
| 300 histogramNames.add(histogramName); |
270 | 301 |
271 let colorScheme = undefined; | 302 unit = getUnit(histogramName, this.histograms_); |
272 // https://github.com/catapult-project/catapult/issues/2970 | 303 if (unit !== undefined) { |
273 if (this.diagnostic.colorScheme === | 304 if (this.chart_.unit === undefined && |
274 tr.v.d.COLOR_SCHEME_CHROME_USER_FRIENDLY_CATEGORY_DRIVER) { | 305 !conflictingUnits) { |
275 colorScheme = (name) => { | 306 this.chart_.unit = unit; |
276 let cat = name.split(' '); | 307 } else if (unit !== this.chart_.unit) { |
277 cat = cat[cat.length - 1]; | 308 conflictingUnits = true; |
278 return tr.e.chrome.ChromeUserFriendlyCategoryDriver.getColor(cat); | 309 this.chart_.unit = undefined; |
279 }; | 310 } |
280 } else if (this.diagnostic.colorScheme !== undefined) { | 311 } |
281 colorScheme = (name) => tr.b.FixedColorSchemeRegistry.lookUp( | 312 } else { |
282 this.diagnostic.colorScheme).getColor(name); | 313 this.chart_.unit = unit; |
283 } else { | 314 } |
284 colorScheme = (name) => DEFAULT_COLOR_SCHEME.colorForKey(name); | |
285 } | |
286 | 315 |
287 const tableRows = []; | |
288 let tableSum = 0; | |
289 const histogramNames = []; | |
290 for (const [name, value] of this.diagnostic) { | |
291 const row = new BreakdownTableRow( | 316 const row = new BreakdownTableRow( |
292 name, value, this.chart_.unit, colorScheme(name)); | 317 key, value, histogramName, unit, colorScheme(key)); |
293 tableRows.push(row); | 318 tableRows.push(row); |
294 if (row.numberValue !== undefined) tableSum += row.numberValue; | 319 if (row.sanitizedValue !== undefined) tableSum += row.sanitizedValue; |
295 if (row.isHistogram) { | |
296 histogramNames.push(value.name); | |
297 } | |
298 } | 320 } |
299 tableRows.sort((x, y) => x.compare(y)); | 321 tableRows.sort((x, y) => x.compare(y)); |
300 | 322 |
301 if (tableSum > 0) { | 323 if (tableRows.length > 1) { |
302 let summaryDisplayElement = tableSum; | 324 let summaryDisplayElement = tableSum; |
303 if (this.chart_.unit !== undefined) { | 325 if (this.chart_.unit !== undefined) { |
304 summaryDisplayElement = this.chart_.unit.format(tableSum); | 326 summaryDisplayElement = this.chart_.unit.format(tableSum); |
305 } | 327 } |
306 summaryDisplayElement = tr.ui.b.createSpan({ | 328 summaryDisplayElement = tr.ui.b.createSpan({ |
307 textContent: summaryDisplayElement, | 329 textContent: summaryDisplayElement, |
308 }); | 330 }); |
309 tableRows.unshift(new BreakdownTableSummaryRow( | 331 tableRows.unshift(new BreakdownTableSummaryRow( |
310 summaryDisplayElement, histogramNames)); | 332 summaryDisplayElement, histogramNames)); |
311 } | 333 } |
312 | 334 |
313 const chartData = {x: 0}; | 335 const chartData = {x: 0}; |
314 for (const row of tableRows) { | 336 for (const row of tableRows) { |
315 if (row.numberValue === undefined) continue; | 337 if (row.sanitizedValue === undefined) continue; |
316 | 338 |
317 // Let the row compute its percentage. | 339 if (tableRows.length > 1) { |
318 row.tableSum = tableSum; | 340 // Let the row compute its percentage. |
| 341 row.tableSum = tableSum; |
| 342 } |
319 | 343 |
320 // Add it to the chart. | 344 // Add it to the chart. |
321 chartData[row.name] = row.numberValue; | 345 chartData[row.name] = row.sanitizedValue; |
322 | 346 |
323 // Configure the colors. | 347 // Configure the colors. |
324 const dataSeries = this.chart_.getDataSeries(row.name); | 348 const dataSeries = this.chart_.getDataSeries(row.name); |
325 dataSeries.color = row.color; | 349 dataSeries.color = row.color; |
326 dataSeries.highlightedColor = row.highlightedColor; | 350 dataSeries.highlightedColor = row.highlightedColor; |
327 } | 351 } |
328 | 352 |
329 if (tableRows.length > 0) { | 353 if (tableRows.length > 0) { |
330 this.$.table.style.display = 'block'; | 354 this.$.table.style.display = 'block'; |
331 this.$.empty.style.display = 'none'; | 355 this.$.empty.style.display = 'none'; |
332 this.$.table.tableRows = tableRows; | 356 this.$.table.tableRows = tableRows; |
333 this.$.table.rebuild(); | 357 this.$.table.rebuild(); |
334 } | 358 } |
335 | 359 |
336 if (Object.keys(chartData).length > 1) { | 360 if (Object.keys(chartData).length > 2) { |
337 this.$.container.style.display = 'block'; | 361 this.$.container.style.display = 'block'; |
338 this.$.empty.style.display = 'none'; | 362 this.$.empty.style.display = 'none'; |
339 this.chart_.data = [chartData]; | 363 this.chart_.data = [chartData]; |
340 } | 364 } |
341 } | 365 } |
342 }); | 366 }); |
343 | 367 |
344 return {}; | 368 return {}; |
345 }); | 369 }); |
346 </script> | 370 </script> |
OLD | NEW |