1<!DOCTYPE html> 2<!-- 3Copyright (c) 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/tracks/chart_transform.html"> 9<link rel="import" href="/tracing/ui/tracks/track.html"> 10<link rel="import" href="/tracing/ui/base/heading.html"> 11<link rel="import" href="/tracing/ui/base/ui.html"> 12 13<style> 14.chart-track { 15 height: 30px; 16 position: relative; 17} 18</style> 19 20<script> 21'use strict'; 22 23tr.exportTo('tr.ui.tracks', function() { 24 25 /** 26 * A track that displays a chart. 27 * 28 * @constructor 29 * @extends {Track} 30 */ 31 var ChartTrack = 32 tr.ui.b.define('chart-track', tr.ui.tracks.Track); 33 34 ChartTrack.prototype = { 35 __proto__: tr.ui.tracks.Track.prototype, 36 37 decorate: function(viewport) { 38 tr.ui.tracks.Track.prototype.decorate.call(this, viewport); 39 this.classList.add('chart-track'); 40 this.series_ = undefined; 41 42 // GUID -> {axis: ChartAxis, series: [ChartSeries]}. 43 this.axisGuidToAxisData_ = undefined; 44 45 // The maximum top and bottom padding of all series. 46 this.topPadding_ = undefined; 47 this.bottomPadding_ = undefined; 48 49 this.heading_ = document.createElement('tr-ui-heading'); 50 this.appendChild(this.heading_); 51 }, 52 53 set heading(heading) { 54 this.heading_.heading = heading; 55 }, 56 57 get heading() { 58 return this.heading_.heading; 59 }, 60 61 set tooltip(tooltip) { 62 this.heading_.tooltip = tooltip; 63 }, 64 65 get series() { 66 return this.series_; 67 }, 68 69 /** 70 * Set the list of chart series to be displayed on this track. The list 71 * is assumed to be sorted in increasing z-order (i.e. the last series in 72 * the list will be drawn at the top). 73 */ 74 set series(series) { 75 this.series_ = series; 76 this.calculateAxisDataAndPadding_(); 77 this.invalidateDrawingContainer(); 78 }, 79 80 get height() { 81 return window.getComputedStyle(this).height; 82 }, 83 84 set height(height) { 85 this.style.height = height; 86 this.invalidateDrawingContainer(); 87 }, 88 89 get hasVisibleContent() { 90 return !!this.series && this.series.length > 0; 91 }, 92 93 calculateAxisDataAndPadding_: function() { 94 if (!this.series_) { 95 this.axisGuidToAxisData_ = undefined; 96 this.topPadding_ = undefined; 97 this.bottomPadding_ = undefined; 98 return; 99 } 100 101 var axisGuidToAxisData = {}; 102 var topPadding = 0; 103 var bottomPadding = 0; 104 105 this.series_.forEach(function(series) { 106 var axis = series.axis; 107 var axisGuid = axis.guid; 108 if (!(axisGuid in axisGuidToAxisData)) { 109 axisGuidToAxisData[axisGuid] = { 110 axis: axis, 111 series: [] 112 }; 113 } 114 axisGuidToAxisData[axisGuid].series.push(series); 115 topPadding = Math.max(topPadding, series.topPadding); 116 bottomPadding = Math.max(bottomPadding, series.bottomPadding); 117 }, this); 118 119 this.axisGuidToAxisData_ = axisGuidToAxisData; 120 this.topPadding_ = topPadding; 121 this.bottomPadding_ = bottomPadding; 122 }, 123 124 draw: function(type, viewLWorld, viewRWorld) { 125 switch (type) { 126 case tr.ui.tracks.DrawType.GENERAL_EVENT: 127 this.drawChart_(viewLWorld, viewRWorld); 128 break; 129 } 130 }, 131 132 drawChart_: function(viewLWorld, viewRWorld) { 133 if (!this.series_) 134 return; 135 136 var ctx = this.context(); 137 138 // Get track drawing parameters. 139 var displayTransform = this.viewport.currentDisplayTransform; 140 var pixelRatio = window.devicePixelRatio || 1; 141 var bounds = this.getBoundingClientRect(); 142 var highDetails = this.viewport.highDetails; 143 144 // Pre-multiply all device-independent pixel parameters with the pixel 145 // ratio to avoid unnecessary recomputation in the performance-critical 146 // drawing code. 147 var width = bounds.width * pixelRatio; 148 var height = bounds.height * pixelRatio; 149 var topPadding = this.topPadding_ * pixelRatio; 150 var bottomPadding = this.bottomPadding_ * pixelRatio; 151 152 // Set up clipping. 153 ctx.save(); 154 ctx.beginPath(); 155 ctx.rect(0, 0, width, height); 156 ctx.clip(); 157 158 // Draw all series in the increasing z-order. 159 this.series_.forEach(function(series) { 160 var chartTransform = new tr.ui.tracks.ChartTransform( 161 displayTransform, series.axis, width, height, topPadding, 162 bottomPadding, pixelRatio); 163 series.draw(ctx, chartTransform, highDetails); 164 }, this); 165 166 // Stop clipping. 167 ctx.restore(); 168 }, 169 170 addEventsToTrackMap: function(eventToTrackMap) { 171 // TODO(petrcermak): Consider adding the series to the track map instead 172 // of the track (a potential performance optimization). 173 this.series_.forEach(function(series) { 174 series.points.forEach(function(point) { 175 point.addToTrackMap(eventToTrackMap, this); 176 }, this); 177 }, this); 178 }, 179 180 addIntersectingEventsInRangeToSelectionInWorldSpace: function( 181 loWX, hiWX, viewPixWidthWorld, selection) { 182 this.series_.forEach(function(series) { 183 series.addIntersectingEventsInRangeToSelectionInWorldSpace( 184 loWX, hiWX, viewPixWidthWorld, selection); 185 }, this); 186 }, 187 188 addEventNearToProvidedEventToSelection: function(event, offset, selection) { 189 var foundItem = false; 190 this.series_.forEach(function(series) { 191 foundItem = foundItem || series.addEventNearToProvidedEventToSelection( 192 event, offset, selection); 193 }, this); 194 return foundItem; 195 }, 196 197 addAllEventsMatchingFilterToSelection: function(filter, selection) { 198 // Do nothing. 199 }, 200 201 addClosestEventToSelection: function(worldX, worldMaxDist, loY, hiY, 202 selection) { 203 this.series_.forEach(function(series) { 204 series.addClosestEventToSelection( 205 worldX, worldMaxDist, loY, hiY, selection); 206 }, this); 207 }, 208 209 /** 210 * Automatically set the bounds of all axes on this track from the range of 211 * values of all series (in this track) associated with each of them. 212 * 213 * See the description of ChartAxis.autoSetFromRange for the optional 214 * configuration argument flags. 215 */ 216 autoSetAllAxes: function(opt_config) { 217 tr.b.iterItems(this.axisGuidToAxisData_, function(axisGuid, axisData) { 218 var axis = axisData.axis; 219 var series = axisData.series; 220 axis.autoSetFromSeries(series, opt_config); 221 }, this); 222 }, 223 224 /** 225 * Automatically set the bounds of the provided axis from the range of 226 * values of all series (in this track) associated with it. 227 * 228 * See the description of ChartAxis.autoSetFromRange for the optional 229 * configuration argument flags. 230 */ 231 autoSetAxis: function(axis, opt_config) { 232 var series = this.axisGuidToAxisData_[axis.guid].series; 233 axis.autoSetFromSeries(series, opt_config); 234 } 235 }; 236 237 return { 238 ChartTrack: ChartTrack 239 }; 240}); 241</script> 242