1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 tvcm.requireStylesheet('tracing.tracks.counter_track');
9 tvcm.require('tracing.trace_model.event');
10 tvcm.require('tracing.tracks.heading_track');
11 tvcm.require('tracing.color_scheme');
12 tvcm.require('tvcm.ui');
14 tvcm.exportTo('tracing.tracks', function() {
16 var SelectionState = tracing.trace_model.SelectionState;
17 var EventPresenter = tracing.EventPresenter;
18 var LAST_SAMPLE_PIXELS = 8;
21 * A track that displays a Counter object.
23 * @extends {HeadingTrack}
27 tvcm.ui.define('counter-track', tracing.tracks.HeadingTrack);
29 CounterTrack.prototype = {
30 __proto__: tracing.tracks.HeadingTrack.prototype,
32 decorate: function(viewport) {
33 tracing.tracks.HeadingTrack.prototype.decorate.call(this, viewport);
34 this.classList.add('counter-track');
41 set counter(counter) {
42 this.counter_ = counter;
43 this.heading = counter.name + ': ';
46 draw: function(type, viewLWorld, viewRWorld) {
48 case tracing.tracks.DrawType.SLICE:
49 this.drawSlices_(viewLWorld, viewRWorld);
54 drawSlices_: function(viewLWorld, viewRWorld) {
55 var ctx = this.context();
56 var pixelRatio = window.devicePixelRatio || 1;
58 var bounds = this.getBoundingClientRect();
59 var height = bounds.height * pixelRatio;
61 var counter = this.counter_;
64 var vp = this.viewport;
65 var dt = vp.currentDisplayTransform;
66 var pixWidth = dt.xViewVectorToWorld(1);
68 // Drop sampels that are less than skipDistancePix apart.
69 var skipDistancePix = 1;
70 var skipDistanceWorld = dt.xViewVectorToWorld(skipDistancePix);
72 // Begin rendering in world space.
74 dt.applyTransformToCanvas(ctx);
76 // Figure out where drawing should begin.
77 var numSeries = counter.numSeries;
78 var numSamples = counter.numSamples;
79 var startIndex = tvcm.findLowIndexInSortedArray(
81 function(x) { return x; },
83 var timestamps = counter.timestamps;
85 startIndex = startIndex - 1 > 0 ? startIndex - 1 : 0;
86 // Draw indices one by one until we fall off the viewRWorld.
87 var yScale = height / counter.maxTotal;
88 for (var seriesIndex = counter.numSeries - 1;
89 seriesIndex >= 0; seriesIndex--) {
90 var series = counter.series[seriesIndex];
92 // For performance reasons we only check the SelectionState of the first
93 // sample. If it's DIMMED we assume that the whole series is DIMMED.
94 // TODO(egraether): Allow partial highlight.
95 var selectionState = SelectionState.NONE;
96 if (series.samples.length &&
97 series.samples[0].selectionState === SelectionState.DIMMED) {
98 selectionState = SelectionState.DIMMED;
101 ctx.fillStyle = EventPresenter.getCounterSeriesColor(
102 series.color, selectionState);
105 // Set iLast and xLast such that the first sample we draw is the
106 // startIndex sample.
107 var iLast = startIndex - 1;
108 var xLast = iLast >= 0 ?
109 timestamps[iLast] - skipDistanceWorld : -1;
110 var yLastView = height;
112 // Iterate over samples from iLast onward until we either fall off the
113 // viewRWorld or we run out of samples. To avoid drawing too much, after
114 // drawing a sample at xLast, skip subsequent samples that are less than
115 // skipDistanceWorld from xLast.
116 var hasMoved = false;
120 if (i >= numSamples) {
121 ctx.lineTo(xLast, yLastView);
122 ctx.lineTo(xLast + LAST_SAMPLE_PIXELS * pixWidth, yLastView);
123 ctx.lineTo(xLast + LAST_SAMPLE_PIXELS * pixWidth, height);
127 var x = timestamps[i];
128 var y = counter.totals[i * numSeries + seriesIndex];
129 var yView = height - (yScale * y);
131 if (x > viewRWorld) {
132 ctx.lineTo(x, yLastView);
133 ctx.lineTo(x, height);
137 if (i + 1 < numSamples) {
138 var xNext = timestamps[i + 1];
139 if (xNext - xLast <= skipDistanceWorld && xNext < viewRWorld) {
146 ctx.moveTo(viewLWorld, height);
150 if (x - xLast < skipDistanceWorld) {
151 // We know that xNext > xLast + skipDistanceWorld, so we can
152 // safely move this sample's x over that much without passing
153 // xNext. This ensure that the previous sample is visible when
154 // zoomed out very far.
155 x = xLast + skipDistanceWorld;
157 ctx.lineTo(x, yLastView);
158 ctx.lineTo(x, yView);
169 ctx.fillStyle = 'rgba(255, 0, 0, 1)';
170 for (var seriesIndex = counter.numSeries - 1;
171 seriesIndex >= 0; seriesIndex--) {
172 var series = counter.series[seriesIndex];
173 var seriesSamples = series.samples;
174 for (var i = startIndex; timestamps[i] < viewRWorld; i++) {
175 if (!seriesSamples[i].selected)
177 var x = timestamps[i];
178 for (var seriesIndex = counter.numSeries - 1;
179 seriesIndex >= 0; seriesIndex--) {
180 var y = counter.totals[i * numSeries + seriesIndex];
181 var yView = height - (yScale * y);
182 ctx.fillRect(x - pixWidth, yView - 1, 3 * pixWidth, 3);
189 addEventsToTrackMap: function(eventToTrackMap) {
190 var allSeries = this.counter_.series;
191 for (var seriesIndex = 0; seriesIndex < allSeries.length; seriesIndex++) {
192 var samples = allSeries[seriesIndex].samples;
193 for (var i = 0; i < samples.length; i++)
194 eventToTrackMap.addEvent(samples[i], this);
198 addIntersectingItemsInRangeToSelectionInWorldSpace: function(
199 loWX, hiWX, viewPixWidthWorld, selection) {
201 function getSampleWidth(x, i) {
202 if (i === counter.timestamps.length - 1) {
203 var dt = this.viewport.currentDisplayTransform;
204 var pixWidth = dt.xViewVectorToWorld(1);
205 return LAST_SAMPLE_PIXELS * pixWidth;
207 return counter.timestamps[i + 1] - counter.timestamps[i];
210 var counter = this.counter_;
211 var iLo = tvcm.findLowIndexInSortedIntervals(counter.timestamps,
212 function(x) { return x; },
213 getSampleWidth.bind(this),
215 var iHi = tvcm.findLowIndexInSortedIntervals(counter.timestamps,
216 function(x) { return x; },
217 getSampleWidth.bind(this),
220 // Iterate over every sample intersecting..
221 for (var sampleIndex = iLo; sampleIndex <= iHi; sampleIndex++) {
224 if (sampleIndex >= counter.timestamps.length)
227 // TODO(nduca): Pick the seriesIndexHit based on the loY - hiY values.
228 for (var seriesIndex = 0;
229 seriesIndex < this.counter.numSeries;
231 var series = this.counter.series[seriesIndex];
232 selection.push(series.samples[sampleIndex]);
237 addItemNearToProvidedEventToSelection: function(sample, offset, selection) {
238 var index = sample.getSampleIndex();
239 var newIndex = index + offset;
240 if (newIndex < 0 || newIndex >= sample.series.samples.length)
243 selection.push(sample.series.samples[newIndex]);
247 addAllObjectsMatchingFilterToSelection: function(filter, selection) {
250 addClosestEventToSelection: function(worldX, worldMaxDist, loY, hiY,
252 var counter = this.counter;
253 if (!counter.numSeries)
258 for (var i = 0; i < counter.numSeries; i++) {
259 var counterSample = tvcm.findClosestElementInSortedArray(
260 counter.series_[i].samples_,
261 function(x) { return x.timestamp; },
268 selection.push(counterSample);
274 CounterTrack: CounterTrack