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 The chart-container element represents one chart and all related functionality, | 8 The chart-container element represents one chart and all related functionality, |
9 including a legend listing different traces that can be plotted on the same | 9 including a legend listing different traces that can be plotted on the same |
10 chart, a revision range selecting mini-chart at the bottom, and all of the alert | 10 chart, a revision range selecting mini-chart at the bottom, and all of the alert |
11 triaging functionality in the chart. | 11 triaging functionality in the chart. |
12 --> | 12 --> |
13 | 13 |
14 <link rel="import" href="/components/core-collapse/core-collapse.html"> | 14 <link rel="import" href="/components/iron-flex-layout/iron-flex-layout.html"> |
15 <link rel="import" href="/components/core-icon/core-icon.html"> | 15 <link rel="import" href="/components/iron-icon/iron-icon.html"> |
16 <link rel="import" href="/components/paper-button/paper-button.html"> | 16 <link rel="import" href="/components/paper-button/paper-button.html"> |
17 | 17 |
18 <link rel="import" href="/dashboard/elements/alert-icon.html"> | 18 <link rel="import" href="/dashboard/elements/alert-icon.html"> |
19 <link rel="import" href="/dashboard/elements/chart-legend.html"> | 19 <link rel="import" href="/dashboard/elements/chart-legend.html"> |
20 <link rel="import" href="/dashboard/elements/chart-slider.html"> | 20 <link rel="import" href="/dashboard/elements/chart-slider.html"> |
21 <link rel="import" href="/dashboard/elements/chart-title.html"> | 21 <link rel="import" href="/dashboard/elements/chart-title.html"> |
22 <link rel="import" href="/dashboard/elements/chart-tooltip.html"> | 22 <link rel="import" href="/dashboard/elements/chart-tooltip.html"> |
23 <link rel="import" href="/dashboard/static/graph.html"> | 23 <link rel="import" href="/dashboard/static/graph.html"> |
24 <link rel="import" href="/dashboard/static/simple_xhr.html"> | 24 <link rel="import" href="/dashboard/static/simple_xhr.html"> |
25 <link rel="import" href="/dashboard/static/testselection.html"> | 25 <link rel="import" href="/dashboard/static/testselection.html"> |
26 <link rel="import" href="/dashboard/static/uri.html"> | 26 <link rel="import" href="/dashboard/static/uri.html"> |
27 | 27 |
28 <polymer-element name="chart-container" | 28 <dom-module name="chart-container"> |
29 attributes="graphParams revisionInfo xsrfToken alertKey | |
30 showCompact collapseLegend testSuites | |
31 isInternalUser" | |
32 on-drop="{{onDrop}}" | |
33 on-dragover="{{allowDrop}}"> | |
34 | 29 |
35 <template> | 30 <template> |
36 <style> | 31 <style> |
37 #container { | 32 #container { |
38 width: 100%; | 33 width: 100%; |
39 display: flex; | 34 display: flex; |
40 display: -webkit-flex; | 35 display: -webkit-flex; |
41 flex-direction: column; | 36 flex-direction: column; |
42 -webkit-flex-direction: column; | 37 -webkit-flex-direction: column; |
43 align-items: center; | 38 align-items: center; |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
131 position: absolute; | 126 position: absolute; |
132 margin-top: -5px; | 127 margin-top: -5px; |
133 margin-left: -6px; | 128 margin-left: -6px; |
134 z-index: 1000; | 129 z-index: 1000; |
135 } | 130 } |
136 | 131 |
137 #close-chart { | 132 #close-chart { |
138 color: #e91e63; | 133 color: #e91e63; |
139 } | 134 } |
140 | 135 |
141 #close-chart > core-icon { | 136 #close-chart > iron-icon { |
142 margin-right: 4px; | 137 margin-right: 4px; |
143 } | 138 } |
144 | 139 |
145 #top-bar { | 140 #top-bar { |
146 width: 100%; | 141 width: 100%; |
147 } | 142 } |
148 </style> | 143 </style> |
149 | 144 |
150 <div id="container" compact?="{{showCompact}}"> | 145 <div id="container" compact$="{{showCompact}}"> |
151 <div id="top-bar" horizontal layout> | 146 <div id="top-bar" class="horizontal layout"> |
152 <div flex horizontal center-justified layout> | 147 <div class="flex horizontal center-justified layout"> |
153 <chart-title id="title" seriesGroupList="{{seriesGroupList}}" | 148 <chart-title id="title" seriesGroupList="{{seriesGroupList}}" |
154 testSuites="{{testSuites}}"></chart-title> | 149 testSuites="{{testSuites}}"></chart-title> |
155 </div> | 150 </div> |
156 <div horizontal layout center> | 151 <div class="horizontal layout center"> |
157 <paper-button id="close-chart" on-click="{{closeChartClicked}}"> | 152 <paper-button id="close-chart" on-click="closeChartClicked"> |
158 Close | 153 Close |
159 </paper-button> | 154 </paper-button> |
160 </div> | 155 </div> |
161 </div> | 156 </div> |
162 <div id="horizontal"> | 157 <div id="horizontal"> |
163 <div id="chart-yaxis-container"> | 158 <div id="chart-yaxis-container"> |
164 <div id="chart-yaxis-label">{{chartYAxisLabel}}</div> | 159 <div id="chart-yaxis-label">{{chartYAxisLabel}}</div> |
165 </div> | 160 </div> |
166 <div id="alert-icon-container"></div> | 161 <div id="alert-icon-container"></div> |
167 <chart-tooltip id="tooltip" | 162 <chart-tooltip id="tooltip" |
168 xsrfToken="{{xsrfToken}}"></chart-tooltip> | 163 xsrfToken="{{xsrfToken}}"></chart-tooltip> |
169 | 164 |
170 <div id="plots-container" on-mouseleave="{{onMouseLeave}}"> | 165 <div id="plots-container" on-mouseleave="onMouseLeave"> |
171 <div id="plot"> | 166 <div id="plot"> |
172 <div id="loading-div"> | 167 <div id="loading-div"> |
173 <img src="//www.google.com/images/loading.gif"> | 168 <img src="//www.google.com/images/loading.gif"> |
174 </div> | 169 </div> |
175 </div> | 170 </div> |
176 <chart-slider id="slider" on-revisionrange="{{onRevisionRange}}"></cha
rt-slider> | 171 <chart-slider id="slider" on-revisionrange="onRevisionRange"></chart-s
lider> |
177 </div> | 172 </div> |
178 | 173 |
179 <div id="warning"> | 174 <div id="warning"> |
180 <template repeat="{{item in warnings}}"> | 175 <template is="dom-repeat" items="{{warnings}}"> |
181 <span>{{item}}</span><br> | 176 <span>{{item}}</span><br> |
182 </template> | 177 </template> |
183 </div> | 178 </div> |
184 | 179 |
185 <a hidden id="original" | 180 <a hidden id="original" |
186 on-click="{{onViewOriginal}}" | 181 on-click="onViewOriginal" |
187 href="javascript:void(0);">View original graph</a> | 182 href="javascript:void(0);">View original graph</a> |
188 | 183 |
189 <chart-legend id="legend" | 184 <chart-legend id="legend" |
190 seriesGroupList={{seriesGroupList}} | 185 seriesGroupList="{{seriesGroupList}}" |
191 indicesToGraph={{indicesToGraph}} | 186 indicesToGraph="{{indicesToGraph}}" |
192 collapseLegend={{collapseLegend}} | 187 collapseLegend="{{collapseLegend}}" |
193 on-dragstart={{legendSeriesDragStart}} | 188 on-dragstart="legendSeriesDragStart" |
194 on-dragend={{legendSeriesDragEnd}} | 189 on-dragend="legendSeriesDragEnd" |
195 deltaAbsolute={{deltaAbsolute}} | 190 deltaAbsolute="{{deltaAbsolute}}" |
196 deltaPercent={{deltaPercent}} | 191 deltaPercent="{{deltaPercent}}" |
197 showDelta={{showDelta}}> | 192 showDelta="{{showDelta}}"> |
198 </div> | 193 </div> |
199 | 194 |
200 </div> | 195 </div> |
201 </template> | 196 </template> |
202 <script> | 197 <script> |
203 'use strict'; | 198 'use strict'; |
204 (function() { | 199 (function() { |
205 | 200 |
206 // Minimum multiple standard deviation for a value to be considered | 201 // Minimum multiple standard deviation for a value to be considered |
207 // an outlier. | 202 // an outlier. |
208 var MULTIPLE_OF_STD_DEV = 5; | 203 var MULTIPLE_OF_STD_DEV = 5; |
209 | 204 |
| 205 // Regex for links in series annotation which are shown in tooltip. |
| 206 var TOOLTIP_LINK_REGEX = /\[(.+?)\]\((.+?)\)/g; |
| 207 |
210 /** | 208 /** |
211 * Gets the mean for list of numbers. | 209 * Gets the mean for list of numbers. |
212 * | 210 * |
213 * @return {number} A number. | 211 * @return {number} A number. |
214 */ | 212 */ |
215 function calculateMean(values) { | 213 function calculateMean(values) { |
216 var len = values.length; | 214 var len = values.length; |
217 var sum = values.reduce(function(v1, v2) { return v1 + v2;}, 0); | 215 var sum = values.reduce(function(v1, v2) { return v1 + v2;}, 0); |
218 return sum / len; | 216 return sum / len; |
219 var squaredDevianceSum = values.reduce( | 217 var squaredDevianceSum = values.reduce( |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
348 }; | 346 }; |
349 | 347 |
350 function arrayUnique(array) { | 348 function arrayUnique(array) { |
351 var dict = {}; | 349 var dict = {}; |
352 array.forEach(function(item) { | 350 array.forEach(function(item) { |
353 dict[item] = true; | 351 dict[item] = true; |
354 }); | 352 }); |
355 return Object.keys(dict); | 353 return Object.keys(dict); |
356 }; | 354 }; |
357 | 355 |
358 Polymer('chart-container', { | 356 Polymer({ |
359 | 357 |
360 SERIES_SELECTION_OPTIONS: ['important', 'all', 'none'], | 358 is: 'chart-container', |
| 359 properties: { |
| 360 SERIES_SELECTION_OPTIONS: { |
| 361 type: Array, |
| 362 value: () => ['important', 'all', 'none'] |
361 | 363 |
362 // Regex for links in series annotation which are shown in tooltip. | 364 // Default values for reverting series highlighting. |
363 TOOLTIP_LINK_REGEX: /\[(.+?)\]\((.+?)\)/g, | 365 DEFAULT_SERIES_PROPERTIES: { |
| 366 type: Object, |
| 367 value: () => { |
| 368 lineWidth: 2, |
| 369 opacity: 1, |
| 370 fill: 0.2, |
| 371 shadowSize: 3 |
| 372 } |
| 373 }, |
364 | 374 |
365 // Default values for reverting series highlighting. | 375 DEFAULT_JSON_PROPERTIES: { |
366 DEFAULT_SERIES_PROPERTIES: { | 376 type: Object, |
367 lineWidth: 2, | 377 value: () => { |
368 opacity: 1, | 378 annotations: { |
369 fill: 0.2, | 379 series: {} |
370 shadowSize: 3 | 380 }, |
| 381 data: {}, |
| 382 error_bars: {}, |
| 383 warning: null |
| 384 } |
| 385 }, |
| 386 |
| 387 // Amount of time before a warning is shown for tests with no new |
| 388 // data. |
| 389 STALE_DATA_DELTA_MS: 7 * 86400000, |
| 390 |
| 391 alertKey: { notify: true }, |
| 392 collapseLegend: { |
| 393 notify: true, |
| 394 observer: 'collapseLegendChanged' |
| 395 }, |
| 396 graphParams: { notify: true }, |
| 397 indicesToGraph: { observer: 'indicesToGraphChanged' }, |
| 398 isInternalUser: { notify: true }, |
| 399 onUri: { observer: 'onUriChanged' }, |
| 400 revisionInfo: { notify: true }, |
| 401 showCompact: { notify: true }, |
| 402 testSuites: { notify: true }, |
| 403 warnings: { observer: 'warningsChanged' }, |
| 404 xsrfToken: { notify: true } |
371 }, | 405 }, |
372 | 406 |
373 DEFAULT_JSON_PROPERTIES: { | |
374 annotations: { | |
375 series: {} | |
376 }, | |
377 data: {}, | |
378 error_bars: {}, | |
379 warning: null | |
380 }, | |
381 | |
382 // Amount of time before a warning is shown for tests with no new data. | |
383 STALE_DATA_DELTA_MS: 7 * 86400000, | |
384 | |
385 created: function() { | 407 created: function() { |
386 // List of indices of series which are selected and will be plotted. | 408 // List of indices of series which are selected and will be plotted. |
387 // We declare this here to avoid changed event on load. | 409 // We declare this here to avoid changed event on load. |
388 this.indicesToGraph = []; | 410 this.indicesToGraph = []; |
389 }, | 411 }, |
390 | 412 |
391 /** | 413 /** |
392 * Initializes the chart-container element and all of its properties. | 414 * Initializes the chart-container element and all of its properties. |
393 * | 415 * |
394 * This is a custom element lifecycle callback that's called when an | 416 * This is a custom element lifecycle callback that's called when an |
(...skipping 664 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1059 */ | 1081 */ |
1060 leftView: function() { | 1082 leftView: function() { |
1061 this.drawable = false; | 1083 this.drawable = false; |
1062 window.removeEventListener('resize', this.resizeHandler); | 1084 window.removeEventListener('resize', this.resizeHandler); |
1063 }, | 1085 }, |
1064 | 1086 |
1065 /** | 1087 /** |
1066 * Handler for the click event of X button on the top-right corner. | 1088 * Handler for the click event of X button on the top-right corner. |
1067 */ | 1089 */ |
1068 closeChartClicked: function() { | 1090 closeChartClicked: function() { |
1069 this.parentNode.removeChild(this); | 1091 Polymer.dom(Polymer.dom(this).parentNode).removeChild(this); |
1070 this.fire('chartclosed', { | 1092 this.fire('chartclosed', { |
1071 target: this, | 1093 target: this, |
1072 stateName: 'chartclosed', | 1094 stateName: 'chartclosed', |
1073 params: { | 1095 params: { |
1074 seriesGroupList: this.seriesGroupList | 1096 seriesGroupList: this.seriesGroupList |
1075 } | 1097 } |
1076 }); | 1098 }); |
1077 }, | 1099 }, |
1078 | 1100 |
1079 /** | 1101 /** |
(...skipping 435 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1515 var flotPoint = flotData[flotIndex].data[dataIndex]; | 1537 var flotPoint = flotData[flotIndex].data[dataIndex]; |
1516 var left = xOffset + Math.round( | 1538 var left = xOffset + Math.round( |
1517 flotData[flotIndex].xaxis.p2c(flotPoint[0])); | 1539 flotData[flotIndex].xaxis.p2c(flotPoint[0])); |
1518 var top = Math.round( | 1540 var top = Math.round( |
1519 flotData[flotIndex].yaxis.p2c(flotPoint[1])); | 1541 flotData[flotIndex].yaxis.p2c(flotPoint[1])); |
1520 | 1542 |
1521 var alertIcon = document.createElement('alert-icon'); | 1543 var alertIcon = document.createElement('alert-icon'); |
1522 alertIcon.initialize( | 1544 alertIcon.initialize( |
1523 annotations[jsonSeriesIndex][dataIndex]['g_anomaly'], | 1545 annotations[jsonSeriesIndex][dataIndex]['g_anomaly'], |
1524 this.alertKey); | 1546 this.alertKey); |
1525 this.$['alert-icon-container'].appendChild(alertIcon); | 1547 Polymer.dom( |
| 1548 this.$['alert-icon-container']).appendChild(alertIcon); |
1526 alertIcon.setPosition(top, left); | 1549 alertIcon.setPosition(top, left); |
1527 | 1550 |
1528 alertIcon.onmouseover = this.showTooltip.bind( | 1551 alertIcon.onmouseover = this.showTooltip.bind( |
1529 this, flotIndex, dataIndex); | 1552 this, flotIndex, dataIndex); |
1530 alertIcon.onclick = this.onAlertClick.bind( | 1553 alertIcon.onclick = this.onAlertClick.bind( |
1531 this, flotIndex, dataIndex); | 1554 this, flotIndex, dataIndex); |
1532 } | 1555 } |
1533 } | 1556 } |
1534 }, | 1557 }, |
1535 | 1558 |
(...skipping 870 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2406 | 2429 |
2407 if (selected.length == 0 && unselected.length == 0) { | 2430 if (selected.length == 0 && unselected.length == 0) { |
2408 selected = ['none']; | 2431 selected = ['none']; |
2409 } else if (seriesGroup.selection) { | 2432 } else if (seriesGroup.selection) { |
2410 selected = [seriesGroup.selection]; | 2433 selected = [seriesGroup.selection]; |
2411 } | 2434 } |
2412 selected = arrayUnique(selected); | 2435 selected = arrayUnique(selected); |
2413 state.push([seriesGroup.path, selected]); | 2436 state.push([seriesGroup.path, selected]); |
2414 }); | 2437 }); |
2415 return state; | 2438 return state; |
| 2439 }, |
| 2440 |
| 2441 listeners: { |
| 2442 drop: 'onDrop', |
| 2443 dragover: 'allowDrop' |
2416 } | 2444 } |
2417 }); | 2445 }); |
2418 })(); | 2446 })(); |
2419 </script> | 2447 </script> |
2420 </polymer-element> | 2448 </dom-module> |
OLD | NEW |