| <!DOCTYPE html> |
| <!-- |
| Copyright 2015 The Chromium Authors. All rights reserved. |
| Use of this source code is governed by a BSD-style license that can be |
| found in the LICENSE file. |
| --> |
| |
| <link rel="import" href="/tracing/extras/rail/rail_score.html"> |
| <link rel="import" href="/tracing/extras/rail/rail_ir_finder.html"> |
| <link rel="import" href="/tracing/model/ir_coverage.html"> |
| <link rel="import" href="/tracing/ui/analysis/analysis_link.html"> |
| <link rel="import" href="/tracing/ui/base/color_legend.html"> |
| <link rel="import" href="/tracing/ui/base/table.html"> |
| <link rel="import" href="/tracing/ui/extras/rail/rail_score_span.html"> |
| <link rel="import" href="/tracing/ui/side_panel/side_panel.html"> |
| <link rel="import" href="/tracing/ui/units/time_duration_span.html"> |
| |
| <polymer-element name='tr-ui-e-rail-rail-score-side-panel' |
| extends='tr-ui-side-panel'> |
| <template> |
| <style> |
| :host { |
| display: flex; |
| flex-direction: column; |
| width: 450px; |
| overflow-x: auto; |
| } |
| |
| #score { |
| background-color: rgb(236, 236, 236) |
| flex: 0 0 auto; |
| } |
| |
| #content { |
| min-width: 0; |
| flex-direction: column; |
| display: flex; |
| flex: 1 1 auto; |
| } |
| |
| #coverage { |
| font-size: 10px; |
| } |
| </style> |
| |
| <tr-ui-e-rail-rail-score-span id="score"></tr-ui-e-rail-rail-score-span> |
| <tr-ui-b-table id="table"></tr-ui-b-table> |
| |
| <div id="coverage"> |
| <b>Coverage:</b><br> |
| <tr-ui-a-analysis-link id="associated-events"></tr-ui-a-analysis-link><br> |
| <tr-ui-a-analysis-link id="unassociated-events"></tr-ui-a-analysis-link> |
| </div> |
| <button id="test">Create Test</button> |
| </template> |
| </polymer-element> |
| |
| <script> |
| 'use strict'; |
| (function() { |
| function setCoverageLink( |
| link, labelString, events, eventRatio, cpuMs, cpuRatio) { |
| link.setSelectionAndContent(events); |
| |
| labelString += ' ' + events.length + ' events'; |
| labelString += ' (' + parseInt(100 * eventRatio) + '%)'; |
| if (cpuRatio !== undefined) |
| labelString += ', '; |
| link.appendChild(document.createTextNode(labelString)); |
| |
| if (cpuRatio === undefined) |
| return; |
| |
| var cpuMsSpan = document.createElement('tr-ui-u-time-duration-span'); |
| // There will be some text after the cpuMsSpan, that should be on the same |
| // line if it fits. This "span" has display: block for its sparkline... so I |
| // guess I'll set it inline here? |
| cpuMsSpan.style.display = 'inline'; |
| cpuMsSpan.duration = cpuMs; |
| cpuMsSpan.contentTextDecoration = 'underline'; |
| link.appendChild(cpuMsSpan); |
| |
| var cpuString = ' (' + parseInt(100 * cpuRatio) + '%)'; |
| link.appendChild(document.createTextNode(cpuString)); |
| } |
| |
| Polymer('tr-ui-e-rail-rail-score-side-panel', { |
| ready: function() { |
| this.rangeOfInterest_ = new tr.b.Range(); |
| this.model_ = undefined; |
| this.railScore_ = undefined; |
| this.selection_ = new tr.model.EventSet(); |
| this.$.test.addEventListener('click', this.createTest_.bind(this)); |
| }, |
| |
| createTest_: function() { |
| var overlay = new tr.ui.b.Overlay(); |
| overlay.title = 'RAILIRFinder test'; |
| var textarea = document.createElement('textarea'); |
| textarea.textContent = tr.e.rail.createIRFinderTestCaseStringFromModel( |
| this.model_); |
| textarea.rows = textarea.textContent.split('\n').length; |
| textarea.cols = 80; |
| overlay.appendChild(textarea); |
| overlay.visible = true; |
| textarea.select(); |
| textarea.focus(); |
| }, |
| |
| get textLabel() { |
| return 'RAIL Info'; |
| }, |
| |
| supportsModel: function(m) { |
| if (m === undefined) { |
| return { |
| supported: false, |
| reason: 'Unknown tracing model' |
| }; |
| } |
| |
| var railScore = tr.e.rail.RAILScore.fromModel(m); |
| if (railScore === undefined) { |
| return { |
| supported: false, |
| reason: 'RAIL interactions were not found on the model' |
| }; |
| } |
| |
| return { |
| supported: true |
| }; |
| }, |
| |
| get model() { |
| return this.model_; |
| }, |
| |
| set model(model) { |
| this.model_ = model; |
| this.updateScore_(); |
| this.updateCoverage_(); |
| this.updateTable_(); |
| }, |
| |
| get listeningToKeys() { |
| return false; |
| }, |
| |
| get effectiveRangeOfInterest() { |
| if (!this.rangeOfInterest_ || this.rangeOfInterest_.isEmpty) { |
| if (this.model) |
| return this.model.bounds; |
| else |
| return new tr.b.Range(); |
| } |
| |
| return this.rangeOfInterest_; |
| }, |
| |
| set rangeOfInterest(rangeOfInterest) { |
| this.rangeOfInterest_ = rangeOfInterest; |
| this.updateScore_(); |
| // TODO(benjhayden): Make updateCoverage_ reflect rangeOfInterest. |
| // https://github.com/catapult-project/catapult/issues/1753 |
| this.updateTable_(); |
| }, |
| |
| updateScore_: function() { |
| if (!this.model) |
| return; |
| |
| this.railScore_ = tr.e.rail.RAILScore.fromModel( |
| this.model, this.effectiveRangeOfInterest); |
| this.$.score.railScore = this.railScore_; |
| }, |
| |
| updateCoverage_: function() { |
| if (!this.model) |
| return; |
| |
| var coverage = tr.model.getIRCoverageFromModel(this.model); |
| |
| if (!coverage) |
| return; |
| |
| var associatedEvents = |
| tr.model.getAssociatedEvents(this.model.interactionRecords); |
| var unassociatedEvents = tr.model.getUnassociatedEvents( |
| this.model, associatedEvents); |
| |
| setCoverageLink(this.shadowRoot.querySelector('#associated-events'), |
| 'Associated', |
| associatedEvents, |
| coverage.coveredEventsCountRatio, |
| coverage.associatedEventsCpuTimeMs, |
| coverage.coveredEventsCpuTimeRatio); |
| setCoverageLink(this.shadowRoot.querySelector('#unassociated-events'), |
| 'Unassociated', |
| unassociatedEvents, |
| 1.0 - coverage.coveredEventsCountRatio, |
| coverage.unassociatedEventsCpuTimeMs, |
| 1.0 - coverage.coveredEventsCpuTimeRatio); |
| }, |
| |
| updateTable_: function() { |
| if (!this.model) |
| return; |
| |
| function toThreeDigitLocaleString(value) { |
| return value.toLocaleString(undefined, |
| {minimumFractionDigits: 3, |
| maximumFractionDigits: 3}); |
| } |
| |
| var columns = [ |
| { |
| title: 'Type', |
| width: '150px', |
| value: function(ir) { |
| var events = new tr.model.EventSet([ir]); |
| events.addEventSet(ir.associatedEvents); |
| |
| var linkEl = document.createElement('tr-ui-a-analysis-link'); |
| linkEl.setSelectionAndContent(events, ir.railTypeName); |
| |
| var el = document.createElement('tr-ui-b-color-legend'); |
| el.setLabelAndColorId(linkEl, ir.colorId); |
| el.compoundEventSelectionState = |
| ir.computeCompoundEvenSelectionState(this.selection_); |
| return el; |
| }.bind(this), |
| cmp: function(a, b) { |
| return a.railTypeName.localeCompare(b.railTypeName); |
| } |
| }, |
| { |
| title: 'Efficiency', |
| width: '33%', |
| value: function(ir) { |
| return toThreeDigitLocaleString(ir.normalizedEfficiency); |
| }, |
| textAlign: 'right', |
| cmp: function(a, b) { |
| return a.normalizedEfficiency - b.normalizedEfficiency; |
| } |
| }, |
| { |
| title: 'Comfort', |
| width: '33%', |
| value: function(ir) { |
| return toThreeDigitLocaleString(ir.normalizedUserComfort); |
| }, |
| textAlign: 'right', |
| cmp: function(a, b) { |
| return a.normalizedUserComfort - b.normalizedUserComfort; |
| } |
| }, |
| { |
| title: 'Score', |
| width: '33%', |
| value: function(ir) { |
| var span = document.createElement('span'); |
| span.style.fontWeight = 'bold'; |
| span.textContent = toThreeDigitLocaleString(ir.railScore); |
| return span; |
| }, |
| textAlign: 'right', |
| cmp: function(a, b) { |
| return a.railScore - b.railScore; |
| } |
| } |
| ]; |
| |
| this.$.table.tableColumns = columns; |
| |
| var rows = []; |
| if (this.railScore_) { |
| this.railScore_.interactionRecords.forEach(function(ir) { |
| if (!this.effectiveRangeOfInterest.intersectsExplicitRangeExclusive( |
| ir.start, ir.end)) |
| return; |
| |
| rows.push(ir); |
| }, this); |
| } |
| |
| this.$.table.tableRows = rows; |
| this.$.table.rebuild(); |
| }, |
| |
| onTableSelectionChanged_: function() { |
| var selectedIR = this.$.table.selectedTableRow; |
| |
| var event = new tr.c.RequestSelectionChangeEvent(); |
| event.selection = new tr.c.Selection([selectedIR]); |
| this.dispatchEvent(event); |
| }, |
| |
| set selection(selection) { |
| if (selection === undefined) |
| selection = new tr.model.EventSet(); |
| |
| if (this.selection_.equals(selection)) |
| return; |
| |
| this.selection_ = selection; |
| this.updateTable_(); |
| } |
| }); |
| })(); |
| </script> |