| 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 |