Chromium Code Reviews| Index: dashboard/dashboard/elements/chart-container.html |
| diff --git a/dashboard/dashboard/elements/chart-container.html b/dashboard/dashboard/elements/chart-container.html |
| index 4d0d380c2fe4b3cdf3793a06ddb1d9b0933312d8..d845ca5a55402703dc590537c39493721d2799b9 100644 |
| --- a/dashboard/dashboard/elements/chart-container.html |
| +++ b/dashboard/dashboard/elements/chart-container.html |
| @@ -14,13 +14,16 @@ triaging functionality in the chart. |
| <link rel="import" href="/components/iron-flex-layout/iron-flex-layout-classes.html"> |
| <link rel="import" href="/components/iron-icon/iron-icon.html"> |
| <link rel="import" href="/components/paper-button/paper-button.html"> |
| +<link rel="import" href="/components/paper-tabs/paper-tabs.html"> |
| <link rel="import" href="/dashboard/elements/alert-icon.html"> |
| <link rel="import" href="/dashboard/elements/chart-legend.html"> |
| <link rel="import" href="/dashboard/elements/chart-slider.html"> |
| <link rel="import" href="/dashboard/elements/chart-title.html"> |
| <link rel="import" href="/dashboard/elements/chart-tooltip.html"> |
| +<link rel="import" href="/dashboard/elements/spark-line.html"> |
|
shatch
2017/09/07 17:23:57
nit: convention seems to be chart-<foo> for all th
|
| <link rel="import" href="/dashboard/static/events.html"> |
| +<link rel="import" href="/dashboard/static/related_timeseries.html"> |
| <link rel="import" href="/dashboard/static/series_group.html"> |
| <link rel="import" href="/dashboard/static/simple_xhr.html"> |
| <link rel="import" href="/dashboard/static/testselection.html"> |
| @@ -64,6 +67,10 @@ triaging functionality in the chart. |
| z-index: 1000; |
| } |
| + #vline-container { |
| + display: flex; |
| + width: 100%; |
| + } |
| #plots-container { |
| flex-grow: 1; |
| display: flex; |
| @@ -134,6 +141,53 @@ triaging functionality in the chart. |
| #top-bar { |
| width: 100%; |
| } |
| + |
| + #related-tabs-container { |
| + display: flex; |
| + align-items: center; |
| + width: 100%; |
| + } |
| + #related-tabs { |
| + margin-left: 1em; |
| + flex-grow: 1; |
| + --paper-tabs-selection-bar-color: black; |
| + --paper-tabs: { |
| + background-color: #ccc; |
| + height: 2em; |
| + }; |
| + } |
| + #related-sparkline-container { |
| + width: 100%; |
| + max-height: 290px; |
| + overflow-y: scroll; |
| + } |
| + #related-sparkline-container spark-line { |
| + margin-top: 0.5em; |
| + } |
| + paper-tab { |
| + flex-grow: 0; |
| + color: #555; |
| + } |
| + paper-tab:last-of-type { |
| + flex-grow: 1; |
| + } |
| + paper-tab:last-of-type { |
| + --paper-tab-content: { |
| + justify-content: flex-end; |
| + }; |
| + } |
| + paper-tab.iron-selected { |
| + color: black; |
| + } |
| + |
| + #vline { |
| + width: 0; |
| + height: 214px; |
| + position: relative; |
| + top: 8px; |
| + border-left: 1px solid black; |
| + display: none; |
| + } |
| </style> |
| <div id="container" compact$="{{showCompact}}"> |
| @@ -156,13 +210,17 @@ triaging functionality in the chart. |
| <chart-tooltip id="tooltip" |
| xsrf-token="{{xsrfToken}}"></chart-tooltip> |
| - <div id="plots-container" on-mouseleave="onMouseLeave"> |
| - <div id="plot"> |
| - <div id="loading-div"> |
| - <img src="//www.google.com/images/loading.gif"> |
| + <div id="vline-container"> |
| + <div id="vline"> </div> |
| + <div id="plots-container" on-mouseleave="onMouseLeave"> |
| + <div id="plot"> |
| + <div id="loading-div"> |
| + <!-- TODO(#3803): Use paper spinner. --> |
| + <img src="//www.google.com/images/loading.gif"> |
| + </div> |
| </div> |
| + <chart-slider id="slider" on-revisionrange="onRevisionRange"></chart-slider> |
| </div> |
| - <chart-slider id="slider" on-revisionrange="onRevisionRange"></chart-slider> |
| </div> |
| <div id="warning"> |
| @@ -188,8 +246,31 @@ triaging functionality in the chart. |
| <canvas hidden id="text_measurement"></canvas> |
| + <div hidden$="[[!showRelatedTabs_(relatedTabs)]]" style="width: 100%"> |
| + <div id="related-tabs-container"> |
| + <div>Related</div> |
| + <paper-tabs id="related-tabs" selected="{{selectedRelatedTabIndex}}"> |
| + <template is="dom-repeat" items="[[relatedTabs]]"> |
| + <paper-tab>[[item.name]]</paper-tab> |
| + </template> |
| + </paper-tabs> |
| + </div> |
| + <div id="related-sparkline-container"> |
| + <template is="dom-repeat" items="[[selectedRelatedTab]]"> |
| + <spark-line name="[[item.name]]" |
| + chart-options="[[getSparklineChartOptions()]]" |
| + revision-map="[[revisionMap]]" |
| + start-rev="[[sliderStartRev]]" |
| + end-rev="[[sliderEndRev]]" |
| + vline-point-id="[[vlinePointId]]" |
| + testpaths="[[item.testpaths]]"> |
| + </spark-line> |
| + </template> |
| + </div> |
| + </div> |
| </div> |
| </template> |
| + |
| <script> |
| 'use strict'; |
| (function() { |
| @@ -498,8 +579,37 @@ triaging functionality in the chart. |
| revisionInfo: { notify: true }, |
| showCompact: { notify: true }, |
| testSuites: { notify: true }, |
| - xsrfToken: { notify: true } |
| + xsrfToken: { notify: true }, |
| + |
| + relatedTabs: { |
| + type: Array, |
| + value: () => [], |
| + }, |
| + |
| + selectedRelatedTab: { |
| + type: Array, |
| + value: () => [], |
| + }, |
| + |
| + selectedRelatedTabIndex: { |
| + type: Number, |
| + value: -1, |
| + observer: 'onSelectedRelatedTabIndexChange_', |
| + }, |
| + |
| + vlinePointId: { |
| + type: Number, |
| + }, |
| + |
| + sliderStartRev: { |
| + type: String, |
| + }, |
| + |
| + sliderEndRev: { |
| + type: String, |
| + }, |
| }, |
| + |
| observers: [ |
| 'indicesToGraphChanged(indicesToGraph.splices)' |
| ], |
| @@ -672,6 +782,7 @@ triaging functionality in the chart. |
| } |
| this.updateSeriesGroupDisplayNames(); |
| + this.buildRelatedTabs_(); |
| if (Object.keys(selectedTestPathDict).length > 0) { |
| this.sendGraphJsonRequest(selectedTestPathDict, true); |
| @@ -865,6 +976,7 @@ triaging functionality in the chart. |
| */ |
| updateWarningsForSelectedSeries() { |
| this.warnings = this.warnings.filter(function(value) { |
| + if (value.value) value = value.value; |
|
shatch
2017/09/07 17:23:57
nit: What was this for again?
|
| return (value.indexOf('Graph out of date!') == -1 && |
| value.indexOf('No data available.') == -1); |
| }); |
| @@ -1007,6 +1119,7 @@ triaging functionality in the chart. |
| this.updateSlider(); |
| this.updateYAxisLabel(); |
| this.updateSmartAutoscaleMap(); |
| + this.buildRelatedTabs_(); |
| if (isSelected) { |
| this.updateIndicesToGraph(); |
| @@ -1273,6 +1386,8 @@ triaging functionality in the chart. |
| this.graphParams = newGraphParams; |
| this.reloadChart(); |
| this.fireChartStateChangedEvent(null); |
| + this.set('sliderStartRev', detail.start_rev); |
| + this.set('sliderEndRev', detail.end_rev); |
| }, |
| /** |
| @@ -1635,6 +1750,8 @@ triaging functionality in the chart. |
| } |
| this.$.slider.startrev = orderedRevisions[0]; |
| this.$.slider.endrev = orderedRevisions[orderedRevisions.length - 1]; |
| + this.set('sliderStartRev', this.$.slider.startrev); |
| + this.set('sliderEndRev', this.$.slider.endrev); |
| // We keep a map of the ordered revision index to the [revision, |
| // series index, data index] so that it's easy to show the right |
| @@ -2155,9 +2272,17 @@ triaging functionality in the chart. |
| // Un-hide and position the tooltip box. |
| const top = flotData[flotSeriesIndex].yaxis.p2c(yValue); |
| - const left = flotData[flotSeriesIndex].xaxis.p2c(xValue) + |
| + let left = flotData[flotSeriesIndex].xaxis.p2c(xValue) + |
| this.chartOptions.yaxis.labelWidth; |
| this.$.tooltip.openAtPosition(top, left); |
| + |
| + // The tooltip doesn't need to be positioned exactly on the point, but |
| + // the vertical line does. Flot's xaxis.p2c() above seems to be off by |
| + // a few pixels for some reason. |
| + left += 6.5; |
| + this.$.vline.style.display = 'block'; |
| + this.$.vline.style.left = left + 'px'; |
| + this.set('vlinePointId', pointId); |
| }, |
| /** |
| @@ -2685,6 +2810,12 @@ triaging functionality in the chart. |
| drop: 'onDrop', |
| dragover: 'allowDrop', |
| populateTestPicker: 'populateTestPicker_', |
| + chartstatechanged: 'onChartStateChanged_', |
| + }, |
| + |
| + onChartStateChanged_(event) { |
| + this.buildRelatedTabs_(); |
| + this.onSelectedRelatedTabIndexChange_(); |
| }, |
| populateTestPicker_(event) { |
| @@ -2729,6 +2860,88 @@ triaging functionality in the chart. |
| const url = window.location.origin + '/report?' + queryParts.join('&'); |
| this.fire('openReportPage', {url}); |
| }, |
| + |
| + buildRelatedTabs_() { |
| + if (uri.getParameter('3405') === null) return; |
| + |
| + const sourceTestPaths = []; |
| + for (const seriesGroup of this.seriesGroupList) { |
| + for (const test of seriesGroup.tests) { |
| + if (!test.selected) continue; |
| + // `test.path` is set in the addSeriesGroup2() path. |
| + // This method needs to handle the old SeriesGroup.path/test.name |
| + // form for the addSeriesGroup() path. |
| + const testpath = test.path || seriesGroup.path + '/' + test.name; |
| + sourceTestPaths.push({ |
| + testpath, |
| + color: GENERATOR.colorForKey(testpath).toString(), |
| + }); |
| + } |
| + } |
| + |
| + const relatedTabs = d.buildRelatedTimeseries(sourceTestPaths); |
| + |
| + // The last tab is actually a button to unset the tab to hide the |
| + // sparklines. |
| + relatedTabs.push({ |
| + name: String.fromCharCode(8212), |
| + sparklines: [], |
| + }); |
| + |
| + this.set('relatedTabs', relatedTabs); |
| + }, |
| + |
| + getSparklineChartOptions() { |
| + return { |
| + crosshair: { |
| + }, |
| + grid: { |
| + borderWidth: 0, |
| + }, |
| + xaxis: { |
| + ticks: [], |
| + }, |
| + yaxis: { |
| + ticks: [], |
| + max: parseFloat(uri.getParameter('slyamax') || 0) || |
| + this.chartOptions.yaxis.max, |
| + min: Number.MAX_VALUE, |
| + }, |
| + selection: { |
| + }, |
| + }; |
| + }, |
| + |
| + showRelatedTabs_(relatedTabs) { |
| + return relatedTabs.length > 1; |
| + }, |
| + |
| + onSelectedRelatedTabIndexChange_() { |
| + // The last tab is actually a button to unset the tab to hide the |
| + // sparklines. |
| + if (this.selectedRelatedTabIndex === this.relatedTabs.length - 1) { |
| + this.set('selectedRelatedTabIndex', -1); |
| + } |
| + |
| + // It seems that setting this from one Array directly to another |
| + // doesn't always make Polymer clear the old spark-lines and build new |
| + // ones, so explicitly clear this to force it to clear the old |
| + // spark-lines. |
| + this.set('selectedRelatedTab', []); |
|
shatch
2017/09/07 17:23:57
Hrm, seems a bit magic, kinda would like to know w
|
| + |
| + if (this.selectedRelatedTabIndex < 0 || |
| + this.selectedRelatedTabIndex >= this.relatedTabs.length) { |
| + return; |
| + } |
| + |
| + // Wait for Polymer to clear out the sparklines in response to |
| + // clearing the selectedRelatedTab. |
| + // TODO(#3841): Use dom-change or observeNodes instead of async(). |
| + this.async(() => { |
| + this.set('selectedRelatedTab', |
| + this.relatedTabs[this.selectedRelatedTabIndex].sparklines); |
| + }); |
| + }, |
| }); |
| })(); |
| </script> |