| OLD | NEW |
| 1 <!DOCTYPE html> | 1 <!DOCTYPE html> |
| 2 <!-- | 2 <!-- |
| 3 Copyright 2015 The Chromium Authors. All rights reserved. | 3 Copyright 2015 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/ui/base/deep_utils.html"> | 8 <link rel="import" href="/tracing/ui/base/deep_utils.html"> |
| 9 <link rel="import" href="/tracing/value/numeric.html"> | 9 <link rel="import" href="/tracing/value/numeric.html"> |
| 10 <link rel="import" href="/tracing/value/unit.html"> | 10 <link rel="import" href="/tracing/value/unit.html"> |
| 11 <link rel="import" href="/tracing/value/value.html"> |
| 11 | 12 |
| 12 <script> | 13 <script> |
| 13 'use strict'; | 14 'use strict'; |
| 14 tr.exportTo('tr.v.ui', function() { | 15 tr.exportTo('tr.v.ui', function() { |
| 16 var emojiPrefix = String.fromCharCode(55357); |
| 17 var Emoji = { |
| 18 GRINNING_FACE: emojiPrefix + String.fromCharCode(56835), |
| 19 NEUTRAL_FACE: emojiPrefix + String.fromCharCode(56848), |
| 20 CONFOUNDED_FACE: emojiPrefix + String.fromCharCode(56854) |
| 21 }; |
| 22 |
| 23 /** |
| 24 * @param {undefined|tr.v.NumericValue|tr.v.Numeric} value |
| 25 * @param {Object=} opt_config |
| 26 * @param {number=} opt_config.total |
| 27 * @param {boolean=} opt_config.rightAlign |
| 28 * @param {!tr.v.Unit=} opt_config.unit |
| 29 * @param {tr.v.Significance=} opt_config.significance |
| 30 * @return {string|Element} |
| 31 */ |
| 15 function createScalarSpan(value, opt_config) { | 32 function createScalarSpan(value, opt_config) { |
| 16 if (value === undefined) | 33 if (value === undefined) |
| 17 return ''; | 34 return ''; |
| 18 | 35 |
| 19 var config = opt_config || {}; | 36 var config = opt_config || {}; |
| 20 var ownerDocument = config.ownerDocument || document; | 37 var ownerDocument = config.ownerDocument || document; |
| 21 | 38 |
| 22 var span = ownerDocument.createElement('tr-v-ui-scalar-span'); | 39 var span = ownerDocument.createElement('tr-v-ui-scalar-span'); |
| 23 | 40 |
| 41 if (value instanceof tr.v.NumericValue) { |
| 42 value = value.numeric; |
| 43 config.unit = value.unit; |
| 44 } |
| 45 |
| 24 var numericValue; | 46 var numericValue; |
| 25 if (value instanceof tr.v.ScalarNumeric) { | 47 if (value instanceof tr.v.ScalarNumeric) { |
| 26 span.value = value; | 48 span.value = value; |
| 27 numericValue = value.value; | 49 numericValue = value.value; |
| 50 } else if (value instanceof tr.v.Numeric) { |
| 51 numericValue = value.average; |
| 52 if (numericValue === undefined) |
| 53 return ''; |
| 54 span.setValueAndUnit(numericValue, value.unit); |
| 28 } else { | 55 } else { |
| 29 var unit = config.unit; | 56 var unit = config.unit; |
| 30 if (unit === undefined) { | 57 if (unit === undefined) { |
| 31 throw new Error( | 58 throw new Error( |
| 32 'Unit must be provided in config when value is a number'); | 59 'Unit must be provided in config when value is a number'); |
| 33 } | 60 } |
| 34 span.setValueAndUnit(value, unit); | 61 span.setValueAndUnit(value, unit); |
| 35 numericValue = value; | 62 numericValue = value; |
| 36 } | 63 } |
| 37 | 64 |
| 38 if (config.context) | 65 if (config.context) |
| 39 span.context = config.context; | 66 span.context = config.context; |
| 40 | 67 |
| 41 if (config.total) | 68 if (config.total) |
| 42 span.percentage = numericValue / config.total; | 69 span.percentage = numericValue / config.total; |
| 43 | 70 |
| 44 if (config.rightAlign) | 71 if (config.rightAlign) |
| 45 span.rightAlign = true; | 72 span.rightAlign = true; |
| 46 | 73 |
| 74 if (config.significance !== undefined) |
| 75 span.significance = config.significance; |
| 76 |
| 47 return span; | 77 return span; |
| 48 } | 78 } |
| 49 | 79 |
| 50 return { | 80 return { |
| 81 Emoji: Emoji, |
| 51 createScalarSpan: createScalarSpan | 82 createScalarSpan: createScalarSpan |
| 52 }; | 83 }; |
| 53 }); | 84 }); |
| 54 </script> | 85 </script> |
| 55 | 86 |
| 56 <dom-module id='tr-v-ui-scalar-span'> | 87 <dom-module id='tr-v-ui-scalar-span'> |
| 57 <template> | 88 <template> |
| 58 <style> | 89 <style> |
| 59 :host { | 90 :host { |
| 60 display: block; | 91 display: block; |
| 61 position: relative; | 92 position: relative; |
| 62 } | 93 } |
| 63 #content.right-align { | 94 #content.right-align { |
| 64 text-align: right; | 95 text-align: right; |
| 65 position: relative; | 96 position: relative; |
| 66 display: block; | 97 display: block; |
| 67 } | 98 } |
| 99 #significance.better, #content.better { |
| 100 color: green; |
| 101 } |
| 102 #significance.worse, #content.worse { |
| 103 color: red; |
| 104 } |
| 68 #sparkline { | 105 #sparkline { |
| 69 width: 0%; | 106 width: 0%; |
| 70 position: absolute; | 107 position: absolute; |
| 71 bottom: 0; | 108 bottom: 0; |
| 72 right: 0; | 109 right: 0; |
| 73 display: none; | 110 display: none; |
| 74 height: 100%; | 111 height: 100%; |
| 75 background-color: hsla(216, 100%, 94.5%, .75); | 112 background-color: hsla(216, 100%, 94.5%, .75); |
| 76 border-left: 1px solid hsl(216, 100%, 89%); | 113 border-left: 1px solid hsl(216, 100%, 89%); |
| 77 box-sizing: border-box; | 114 box-sizing: border-box; |
| 78 } | 115 } |
| 79 #warning { | 116 #warning { |
| 80 margin-left: 4px; | 117 margin-left: 4px; |
| 81 font-size: 66%; | 118 font-size: 66%; |
| 82 } | 119 } |
| 120 #significance { |
| 121 font-family: "Noto Color Emoji", "Apple Color Emoji", "Segoe UI Emoji", Ti
mes, Symbola, Aegyptus, Code2000, Code2001, Code2002, Musica, serif, LastResort; |
| 122 font-size: 13pt; |
| 123 } |
| 83 </style> | 124 </style> |
| 84 <span id="sparkline"></span> | 125 <span id="sparkline"></span> |
| 126 <span id="significance"></span> |
| 85 <span id="content"></span> | 127 <span id="content"></span> |
| 86 <span id="warning" style="display:none">⚠</span> | 128 <span id="warning" style="display:none">⚠</span> |
| 87 </template> | 129 </template> |
| 88 </dom-module> | 130 </dom-module> |
| 89 <script> | 131 <script> |
| 90 'use strict'; | 132 'use strict'; |
| 91 | 133 |
| 92 Polymer({ | 134 Polymer({ |
| 93 is: 'tr-v-ui-scalar-span', | 135 is: 'tr-v-ui-scalar-span', |
| 94 | 136 |
| 95 ready: function() { | 137 created: function() { |
| 96 this.value_ = undefined; | 138 this.value_ = undefined; |
| 97 this.unit_ = undefined; | 139 this.unit_ = undefined; |
| 140 this.context_ = undefined; |
| 98 | 141 |
| 99 this.warning_ = undefined; | 142 this.warning_ = undefined; |
| 100 this.percentage_ = undefined; | 143 this.percentage_ = undefined; |
| 144 this.significance_ = tr.v.Significance.DONT_CARE; |
| 145 }, |
| 146 |
| 147 get significance() { |
| 148 return this.significance_; |
| 149 }, |
| 150 |
| 151 set significance(s) { |
| 152 this.significance_ = s; |
| 153 this.updateContent_(); |
| 154 }, |
| 155 |
| 156 set contentTextDecoration(deco) { |
| 157 this.$.content.style.textDecoration = deco; |
| 158 }, |
| 159 |
| 160 get value() { |
| 161 return this.value_; |
| 162 }, |
| 163 |
| 164 set value(value) { |
| 165 if (value instanceof tr.v.ScalarNumeric) { |
| 166 this.value_ = value.value; |
| 167 this.unit_ = value.unit; |
| 168 } else { |
| 169 this.value_ = value; |
| 170 } |
| 171 this.updateContent_(); |
| 101 }, | 172 }, |
| 102 | 173 |
| 103 attached: function() { | 174 attached: function() { |
| 104 tr.v.Unit.addEventListener( | 175 tr.v.Unit.addEventListener( |
| 105 'display-mode-changed', this.updateContent_.bind(this)); | 176 'display-mode-changed', this.updateContent_.bind(this)); |
| 106 }, | 177 }, |
| 107 | 178 |
| 108 detached: function() { | 179 detached: function() { |
| 109 tr.v.Unit.removeEventListener( | 180 tr.v.Unit.removeEventListener( |
| 110 'display-mode-changed', this.updateContent_.bind(this)); | 181 'display-mode-changed', this.updateContent_.bind(this)); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 121 set value(value) { | 192 set value(value) { |
| 122 if (value instanceof tr.v.ScalarNumeric) { | 193 if (value instanceof tr.v.ScalarNumeric) { |
| 123 this.value_ = value.value; | 194 this.value_ = value.value; |
| 124 this.unit_ = value.unit; | 195 this.unit_ = value.unit; |
| 125 } else { | 196 } else { |
| 126 this.value_ = value; | 197 this.value_ = value; |
| 127 } | 198 } |
| 128 this.updateContent_(); | 199 this.updateContent_(); |
| 129 }, | 200 }, |
| 130 | 201 |
| 131 get context() { | 202 get context() { |
| 132 return this.context_; | 203 return this.context_; |
| 133 }, | 204 }, |
| 134 | 205 |
| 135 set context(context) { | 206 set context(context) { |
| 136 this.context_ = context; | 207 this.context_ = context; |
| 137 this.updateContent_(); | 208 this.updateContent_(); |
| 138 }, | 209 }, |
| 139 | 210 |
| 140 get unit() { | 211 get unit() { |
| 141 return this.unit_; | 212 return this.unit_; |
| 142 }, | 213 }, |
| 143 | 214 |
| 144 set unit(unit) { | 215 set unit(unit) { |
| 145 this.unit_ = unit; | 216 this.unit_ = unit; |
| 146 this.updateContent_(); | 217 this.updateContent_(); |
| 147 }, | 218 }, |
| 148 | 219 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 176 if (this.percentage_ === undefined) { | 247 if (this.percentage_ === undefined) { |
| 177 this.$.sparkline.style.display = 'none'; | 248 this.$.sparkline.style.display = 'none'; |
| 178 this.$.sparkline.style.width = '0'; | 249 this.$.sparkline.style.width = '0'; |
| 179 } else { | 250 } else { |
| 180 this.$.sparkline.style.display = 'block'; | 251 this.$.sparkline.style.display = 'block'; |
| 181 this.$.sparkline.style.width = (this.percentage_ * 100) + '%'; | 252 this.$.sparkline.style.width = (this.percentage_ * 100) + '%'; |
| 182 } | 253 } |
| 183 }, | 254 }, |
| 184 | 255 |
| 185 updateContent_: function() { | 256 updateContent_: function() { |
| 186 if (this.unit_ === undefined) { | 257 Polymer.dom(this.$.significance).textContent = ''; |
| 187 Polymer.dom(this.$.content).textContent = ''; | 258 Polymer.dom(this.$.content).textContent = ''; |
| 188 this.$.content.style.color = ''; | 259 Polymer.dom(this.$.content).classList.remove('better'); |
| 260 Polymer.dom(this.$.content).classList.remove('worse'); |
| 261 Polymer.dom(this.$.significance).classList.remove('better'); |
| 262 Polymer.dom(this.$.significance).classList.remove('worse'); |
| 263 |
| 264 if (this.unit_ === undefined) |
| 189 return; | 265 return; |
| 266 |
| 267 this.$.content.title = ''; |
| 268 Polymer.dom(this.$.content).textContent = |
| 269 this.unit_.format(this.value, this.context); |
| 270 this.updateDelta_(); |
| 271 }, |
| 272 |
| 273 updateDelta_: function() { |
| 274 if (!this.unit_.isDelta) |
| 275 return; |
| 276 |
| 277 var biggerIsBetter = false; |
| 278 var smallerIsBetter = false; |
| 279 switch (this.unit_.improvementDirection) { |
| 280 case tr.v.ImprovementDirection.DONT_CARE: |
| 281 return; |
| 282 |
| 283 case tr.v.ImprovementDirection.BIGGER_IS_BETTER: |
| 284 biggerIsBetter = true; |
| 285 break; |
| 286 |
| 287 case tr.v.ImprovementDirection.SMALLER_IS_BETTER: |
| 288 smallerIsBetter = true; |
| 289 break; |
| 190 } | 290 } |
| 191 | 291 |
| 192 Polymer.dom(this.$.content).textContent = | 292 var better = ((biggerIsBetter && this.value > 0) || |
| 193 this.unit_.format(this.value, this.context); | 293 (smallerIsBetter && this.value < 0)); |
| 294 var worse = ((biggerIsBetter && this.value < 0) || |
| 295 (smallerIsBetter && this.value > 0)); |
| 194 | 296 |
| 195 var BIGGER_IS_BETTER = tr.v.ImprovementDirection.BIGGER_IS_BETTER; | 297 var changeClass = ''; |
| 196 var SMALLER_IS_BETTER = tr.v.ImprovementDirection.SMALLER_IS_BETTER; | 298 var emoji = tr.v.ui.Emoji.NEUTRAL_FACE; |
| 197 var color = ''; | 299 var title = ''; |
| 198 if (this.unit_.isDelta) { | 300 |
| 199 var improvementDirection = this.unit_.improvementDirection; | 301 if (better) { |
| 200 if (this.value > 0) { | 302 changeClass = 'better'; |
| 201 // Positive delta. | 303 emoji = tr.v.ui.Emoji.GRINNING_FACE; |
| 202 switch (improvementDirection) { | 304 title = 'improvement'; |
| 203 case BIGGER_IS_BETTER: | 305 } else if (worse) { |
| 204 color = 'green'; | 306 changeClass = 'worse'; |
| 205 break; | 307 emoji = tr.v.ui.Emoji.CONFOUNDED_FACE; |
| 206 case SMALLER_IS_BETTER: | 308 title = 'regression'; |
| 207 color = 'red'; | 309 } else { |
| 208 break; | 310 title = 'no change'; |
| 209 } | 311 } |
| 210 } else if (this.value < 0) { | 312 |
| 211 // Negative delta. | 313 // Set the content class separately from the significance class so that |
| 212 switch (improvementDirection) { | 314 // NEUTRAL_FACE is always a neutral color. |
| 213 case BIGGER_IS_BETTER: | 315 if (changeClass) |
| 214 color = 'red'; | 316 Polymer.dom(this.$.content).classList.add(changeClass); |
| 215 break; | 317 |
| 216 case SMALLER_IS_BETTER: | 318 switch (this.significance) { |
| 217 color = 'green'; | 319 case tr.v.Significance.DONT_CARE: |
| 218 break; | 320 emoji = ''; |
| 219 } | 321 changeClass = ''; |
| 220 } | 322 break; |
| 323 |
| 324 case tr.v.Significance.INSIGNIFICANT: |
| 325 changeClass = ''; |
| 326 emoji = tr.v.ui.Emoji.NEUTRAL_FACE; |
| 327 if (better || worse) |
| 328 title = 'insignificant ' + title; |
| 329 break; |
| 330 |
| 331 case tr.v.Significance.SIGNIFICANT: |
| 332 if (!better && !worse) |
| 333 throw new Error('How can no change be significant?'); |
| 334 |
| 335 title = 'significant ' + title; |
| 336 break; |
| 337 } |
| 338 |
| 339 Polymer.dom(this.$.significance).textContent = emoji; |
| 340 this.$.significance.title = title; |
| 341 this.$.content.title = title; |
| 342 if (changeClass) |
| 343 Polymer.dom(this.$.significance).classList.add(changeClass); |
| 344 }, |
| 345 |
| 346 get warning() { |
| 347 return this.warning_; |
| 348 }, |
| 349 |
| 350 set warning(warning) { |
| 351 this.warning_ = warning; |
| 352 var warningEl = this.$.warning; |
| 353 if (this.warning_) { |
| 354 warningEl.title = warning; |
| 355 warningEl.style.display = ''; |
| 356 } else { |
| 357 warningEl.title = ''; |
| 358 warningEl.style.display = 'none'; |
| 221 } | 359 } |
| 222 this.$.content.style.color = color; | 360 this.$.content.style.color = color; |
| 223 }, | 361 }, |
| 224 | 362 |
| 225 get warning() { | 363 get warning() { |
| 226 return this.warning_; | 364 return this.warning_; |
| 227 }, | 365 }, |
| 228 | 366 |
| 229 set warning(warning) { | 367 set warning(warning) { |
| 230 this.warning_ = warning; | 368 this.warning_ = warning; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 258 | 396 |
| 259 set duration(duration) { | 397 set duration(duration) { |
| 260 if (duration instanceof tr.b.u.TimeDuration) { | 398 if (duration instanceof tr.b.u.TimeDuration) { |
| 261 this.value = duration; | 399 this.value = duration; |
| 262 return; | 400 return; |
| 263 } | 401 } |
| 264 this.setValueAndUnit(duration, tr.b.u.Units.timeDurationInMs); | 402 this.setValueAndUnit(duration, tr.b.u.Units.timeDurationInMs); |
| 265 } | 403 } |
| 266 }); | 404 }); |
| 267 </script> | 405 </script> |
| OLD | NEW |