3 Copyright (c) 2013 The Chromium Authors. All rights reserved.
4 Use of this source code is governed by a BSD-style license that can be
5 found in the LICENSE file.
8 <link rel="stylesheet" href="/tracing/tracks/counter_track.css">
10 <link rel="import" href="/tracing/trace_model/event.html">
11 <link rel="import" href="/tracing/tracks/heading_track.html">
12 <link rel="import" href="/tracing/color_scheme.html">
13 <link rel="import" href="/tvcm/ui.html">
18 tvcm.exportTo('tracing.tracks', function() {
20 var SelectionState = tracing.trace_model.SelectionState;
21 var EventPresenter = tracing.EventPresenter;
22 var LAST_SAMPLE_PIXELS = 8;
25 * A track that displays a Counter object.
27 * @extends {HeadingTrack}
31 tvcm.ui.define('counter-track', tracing.tracks.HeadingTrack);
33 CounterTrack.prototype = {
34 __proto__: tracing.tracks.HeadingTrack.prototype,
36 decorate: function(viewport) {
37 tracing.tracks.HeadingTrack.prototype.decorate.call(this, viewport);
38 this.classList.add('counter-track');
45 set counter(counter) {
46 this.counter_ = counter;
47 this.heading = counter.name + ': ';
50 draw: function(type, viewLWorld, viewRWorld) {
52 case tracing.tracks.DrawType.SLICE:
53 this.drawSlices_(viewLWorld, viewRWorld);
58 drawSlices_: function(viewLWorld, viewRWorld) {
59 var ctx = this.context();
60 var pixelRatio = window.devicePixelRatio || 1;
62 var bounds = this.getBoundingClientRect();
63 var height = bounds.height * pixelRatio;
65 var counter = this.counter_;
68 var vp = this.viewport;
69 var dt = vp.currentDisplayTransform;
70 var pixWidth = dt.xViewVectorToWorld(1);
72 // Drop sampels that are less than skipDistancePix apart.
73 var skipDistancePix = 1;
74 var skipDistanceWorld = dt.xViewVectorToWorld(skipDistancePix);
76 // Begin rendering in world space.
78 dt.applyTransformToCanvas(ctx);
80 // Figure out where drawing should begin.
81 var numSeries = counter.numSeries;
82 var numSamples = counter.numSamples;
83 var startIndex = tvcm.findLowIndexInSortedArray(
85 function(x) { return x; },
87 var timestamps = counter.timestamps;
89 startIndex = startIndex - 1 > 0 ? startIndex - 1 : 0;
90 // Draw indices one by one until we fall off the viewRWorld.
91 var yScale = height / counter.maxTotal;
92 for (var seriesIndex = counter.numSeries - 1;
93 seriesIndex >= 0; seriesIndex--) {
94 var series = counter.series[seriesIndex];
96 // For performance reasons we only check the SelectionState of the first
97 // sample. If it's DIMMED we assume that the whole series is DIMMED.
98 // TODO(egraether): Allow partial highlight.
99 var selectionState = SelectionState.NONE;
100 if (series.samples.length &&
101 series.samples[0].selectionState === SelectionState.DIMMED) {
102 selectionState = SelectionState.DIMMED;
105 ctx.fillStyle = EventPresenter.getCounterSeriesColor(
106 series.color, selectionState);
109 // Set iLast and xLast such that the first sample we draw is the
110 // startIndex sample.
111 var iLast = startIndex - 1;
112 var xLast = iLast >= 0 ?
113 timestamps[iLast] - skipDistanceWorld : -1;
114 var yLastView = height;
116 // Iterate over samples from iLast onward until we either fall off the
117 // viewRWorld or we run out of samples. To avoid drawing too much, after
118 // drawing a sample at xLast, skip subsequent samples that are less than
119 // skipDistanceWorld from xLast.
120 var hasMoved = false;
124 if (i >= numSamples) {
125 ctx.lineTo(xLast, yLastView);
126 ctx.lineTo(xLast + LAST_SAMPLE_PIXELS * pixWidth, yLastView);
127 ctx.lineTo(xLast + LAST_SAMPLE_PIXELS * pixWidth, height);
131 var x = timestamps[i];
132 var y = counter.totals[i * numSeries + seriesIndex];
133 var yView = height - (yScale * y);
135 if (x > viewRWorld) {
136 ctx.lineTo(x, yLastView);
137 ctx.lineTo(x, height);
141 if (i + 1 < numSamples) {
142 var xNext = timestamps[i + 1];
143 if (xNext - xLast <= skipDistanceWorld && xNext < viewRWorld) {
150 ctx.moveTo(viewLWorld, height);
154 if (x - xLast < skipDistanceWorld) {
155 // We know that xNext > xLast + skipDistanceWorld, so we can
156 // safely move this sample's x over that much without passing
157 // xNext. This ensure that the previous sample is visible when
158 // zoomed out very far.
159 x = xLast + skipDistanceWorld;
161 ctx.lineTo(x, yLastView);
162 ctx.lineTo(x, yView);
173 ctx.fillStyle = 'rgba(255, 0, 0, 1)';
174 for (var seriesIndex = counter.numSeries - 1;
175 seriesIndex >= 0; seriesIndex--) {
176 var series = counter.series[seriesIndex];
177 var seriesSamples = series.samples;
178 for (var i = startIndex; timestamps[i] < viewRWorld; i++) {
179 if (!seriesSamples[i].selected)
181 var x = timestamps[i];
182 for (var seriesIndex = counter.numSeries - 1;
183 seriesIndex >= 0; seriesIndex--) {
184 var y = counter.totals[i * numSeries + seriesIndex];
185 var yView = height - (yScale * y);
186 ctx.fillRect(x - pixWidth, yView - 1, 3 * pixWidth, 3);
193 addEventsToTrackMap: function(eventToTrackMap) {
194 var allSeries = this.counter_.series;
195 for (var seriesIndex = 0; seriesIndex < allSeries.length; seriesIndex++) {
196 var samples = allSeries[seriesIndex].samples;
197 for (var i = 0; i < samples.length; i++)
198 eventToTrackMap.addEvent(samples[i], this);
202 addIntersectingItemsInRangeToSelectionInWorldSpace: function(
203 loWX, hiWX, viewPixWidthWorld, selection) {
205 function getSampleWidth(x, i) {
206 if (i === counter.timestamps.length - 1) {
207 var dt = this.viewport.currentDisplayTransform;
208 var pixWidth = dt.xViewVectorToWorld(1);
209 return LAST_SAMPLE_PIXELS * pixWidth;
211 return counter.timestamps[i + 1] - counter.timestamps[i];
214 var counter = this.counter_;
215 var iLo = tvcm.findLowIndexInSortedIntervals(counter.timestamps,
216 function(x) { return x; },
217 getSampleWidth.bind(this),
219 var iHi = tvcm.findLowIndexInSortedIntervals(counter.timestamps,
220 function(x) { return x; },
221 getSampleWidth.bind(this),
224 // Iterate over every sample intersecting..
225 for (var sampleIndex = iLo; sampleIndex <= iHi; sampleIndex++) {
228 if (sampleIndex >= counter.timestamps.length)
231 // TODO(nduca): Pick the seriesIndexHit based on the loY - hiY values.
232 for (var seriesIndex = 0;
233 seriesIndex < this.counter.numSeries;
235 var series = this.counter.series[seriesIndex];
236 selection.push(series.samples[sampleIndex]);
241 addItemNearToProvidedEventToSelection: function(sample, offset, selection) {
242 var index = sample.getSampleIndex();
243 var newIndex = index + offset;
244 if (newIndex < 0 || newIndex >= sample.series.samples.length)
247 selection.push(sample.series.samples[newIndex]);
251 addAllObjectsMatchingFilterToSelection: function(filter, selection) {
254 addClosestEventToSelection: function(worldX, worldMaxDist, loY, hiY,
256 var counter = this.counter;
257 if (!counter.numSeries)
262 for (var i = 0; i < counter.numSeries; i++) {
263 var counterSample = tvcm.findClosestElementInSortedArray(
264 counter.series_[i].samples_,
265 function(x) { return x.timestamp; },
272 selection.push(counterSample);
278 CounterTrack: CounterTrack