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