1<!DOCTYPE html>
2<!--
3Copyright 2015 The Chromium Authors. All rights reserved.
4Use of this source code is governed by a BSD-style license that can be
5found in the LICENSE file.
6-->
7
8<link rel="import" href="/tracing/ui/base/deep_utils.html">
9<link rel="import" href="/tracing/ui/base/polymer_utils.html">
10<link rel="import" href="/tracing/value/numeric.html">
11<link rel="import" href="/tracing/value/unit.html">
12
13<script>
14'use strict';
15tr.exportTo('tr.v.ui', function() {
16  function createScalarSpan(value, opt_config) {
17    if (value === undefined)
18      return '';
19
20    var config = opt_config || {};
21    var ownerDocument = config.ownerDocument || document;
22
23    var span = ownerDocument.createElement('tr-v-ui-scalar-span');
24
25    var numericValue;
26    if (value instanceof tr.v.ScalarNumeric) {
27      span.value = value;
28      numericValue = value.value;
29    } else {
30      var unit = config.unit;
31      if (unit === undefined) {
32        throw new Error(
33            'Unit must be provided in config when value is a number');
34      }
35      span.setValueAndUnit(value, unit);
36      numericValue = value;
37    }
38
39    if (config.total)
40      span.percentage = numericValue / config.total;
41
42    if (config.rightAlign)
43      span.rightAlign = true;
44
45    return span;
46  }
47
48  tr.v.Unit.addEventListener('display-mode-changed', function(e) {
49    var scalarSpanTagName = 'tr-v-ui-scalar-span';
50    var subclassNames = tr.ui.b.getPolymerElementsThatSubclass(
51        scalarSpanTagName);
52    subclassNames.push(scalarSpanTagName);
53    var isSubclass = {};
54    subclassNames.forEach(function(n) {
55      isSubclass[n.toUpperCase()] = true;
56    });
57
58    var m = tr.b.findDeepElementsMatchingPredicate(
59        document.body,
60        function(el) {
61         return isSubclass[el.tagName];
62        });
63    m.forEach(function(el) {
64      el.updateContent_();
65    });
66  });
67
68  return {
69    createScalarSpan: createScalarSpan
70  };
71});
72</script>
73
74<polymer-element name="tr-v-ui-scalar-span">
75  <template>
76    <style>
77    :host {
78      display: block;
79      position: relative;
80    }
81    #content.right-align {
82      text-align: right;
83      position: relative;
84      display: block;
85    }
86    #sparkline {
87      width: 0%;
88      position: absolute;
89      bottom: 0;
90      right: 0;
91      display: none;
92      height: 100%;
93      background-color: hsla(216, 100%, 94.5%, .75);
94      border-left: 1px solid hsl(216, 100%, 89%);
95      box-sizing: border-box;
96    }
97    #warning {
98      margin-left: 4px;
99      font-size: 66%;
100    }
101    </style>
102    <span id="sparkline"></span>
103    <span id="content"></span>
104    <span id="warning" style="display:none">&#9888;</span>
105  </template>
106  <script>
107  'use strict';
108
109  Polymer({
110    ready: function() {
111      this.value_ = undefined;
112      this.unit_ = undefined;
113
114      this.warning_ = undefined;
115      this.percentage_ = undefined;
116    },
117
118    set contentTextDecoration(deco) {
119      this.$.content.style.textDecoration = deco;
120    },
121
122    get value() {
123      return this.value_;
124    },
125
126    set value(value) {
127      if (value instanceof tr.v.ScalarNumeric) {
128        this.value_ = value.value;
129        this.unit_ = value.unit;
130      } else {
131        this.value_ = value;
132      }
133      this.updateContent_();
134    },
135
136    get unit() {
137      return this.unit_;
138    },
139
140    set unit(unit) {
141      this.unit_ = unit;
142      this.updateContent_();
143    },
144
145    setValueAndUnit: function(value, unit) {
146      this.value_ = value;
147      this.unit_ = unit;
148      this.updateContent_();
149    },
150
151    get percentage() {
152      return this.percentage_;
153    },
154
155    set percentage(percentage) {
156      this.percentage_ = percentage;
157      this.updateSparkline_();
158    },
159
160    get rightAlign() {
161      return this.$.content.classList.contains('right-align');
162    },
163
164    set rightAlign(rightAlign) {
165      if (rightAlign)
166        this.$.content.classList.add('right-align');
167      else
168        this.$.content.classList.remove('right-align');
169    },
170
171    updateSparkline_: function() {
172      if (this.percentage_ === undefined) {
173        this.$.sparkline.style.display = 'none';
174        this.$.sparkline.style.width = '0';
175      } else {
176        this.$.sparkline.style.display = 'block';
177        this.$.sparkline.style.width = (this.percentage_ * 100) + '%';
178      }
179    },
180
181    updateContent_: function() {
182      if (this.unit_ === undefined) {
183        this.$.content.textContent = '';
184        this.$.content.style.color = '';
185        return;
186      }
187
188      this.$.content.textContent = this.unit_.format(this.value);
189
190      var BIGGER_IS_BETTER = tr.v.ImprovementDirection.BIGGER_IS_BETTER;
191      var SMALLER_IS_BETTER = tr.v.ImprovementDirection.SMALLER_IS_BETTER;
192      var color = '';
193      if (this.unit_.isDelta) {
194        var improvementDirection = this.unit_.improvementDirection;
195        if (this.value > 0) {
196          // Positive delta.
197          switch (improvementDirection) {
198            case BIGGER_IS_BETTER:
199              color = 'green';
200              break;
201            case SMALLER_IS_BETTER:
202              color = 'red';
203              break;
204          }
205        } else if (this.value < 0) {
206          // Negative delta.
207          switch (improvementDirection) {
208            case BIGGER_IS_BETTER:
209              color = 'red';
210              break;
211            case SMALLER_IS_BETTER:
212              color = 'green';
213              break;
214          }
215        }
216      }
217      this.$.content.style.color = color;
218    },
219
220    get warning() {
221      return this.warning_;
222    },
223
224    set warning(warning) {
225      this.warning_ = warning;
226      var warningEl = this.$.warning;
227      if (this.warning_) {
228        warningEl.title = warning;
229        warningEl.style.display = '';
230      } else {
231        warningEl.title = '';
232        warningEl.style.display = 'none';
233      }
234    }
235  });
236  </script>
237</polymer-element>
238