blob: d7ff62717c698e4a6ce3ad1fe547ea0fe056111a [file] [log] [blame]
// Copyright (c) 2012 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.
'use strict';
base.requireStylesheet('tracing.tracks.counter_track');
base.require('tracing.tracks.heading_track');
base.require('tracing.color_scheme');
base.require('ui');
base.exportTo('tracing.tracks', function() {
var palette = tracing.getColorPalette();
/**
* A track that displays a Counter object.
* @constructor
* @extends {HeadingTrack}
*/
var CounterTrack =
ui.define('counter-track', tracing.tracks.HeadingTrack);
CounterTrack.prototype = {
__proto__: tracing.tracks.HeadingTrack.prototype,
decorate: function(viewport) {
tracing.tracks.HeadingTrack.prototype.decorate.call(this, viewport);
this.classList.add('counter-track');
this.selectedSamples_ = {};
this.categoryFilter_ = new tracing.Filter();
},
/**
* Called by all the addToSelection functions on the created selection
* hit objects. Override this function on parent classes to add
* context-specific information to the hit.
*/
decorateHit: function(hit) {
},
get counter() {
return this.counter_;
},
set counter(counter) {
this.counter_ = counter;
this.heading = counter.name + ': ';
},
get categoryFilter() {
return this.categoryFilter_;
},
set categoryFilter(v) {
this.categoryFilter_ = v;
},
/**
* @return {Object} A sparse, mutable map from sample index to bool. Samples
* indices the map that are true are drawn as selected.
*/
get selectedSamples() {
return this.selectedSamples_;
},
draw: function(type, viewLWorld, viewRWorld) {
switch (type) {
case tracing.tracks.DrawType.SLICE:
this.drawSlices_(viewLWorld, viewRWorld);
break;
}
},
drawSlices_: function(viewLWorld, viewRWorld) {
var ctx = this.context();
var pixelRatio = window.devicePixelRatio || 1;
var bounds = this.getBoundingClientRect();
var height = bounds.height * pixelRatio;
var counter = this.counter_;
// Culling parametrs.
var vp = this.viewport;
var pixWidth = vp.xViewVectorToWorld(1);
// Drop sampels that are less than skipDistancePix apart.
var skipDistancePix = 1;
var skipDistanceWorld = vp.xViewVectorToWorld(skipDistancePix);
// Begin rendering in world space.
ctx.save();
vp.applyTransformToCanvas(ctx);
// Figure out where drawing should begin.
var numSeries = counter.numSeries;
var numSamples = counter.numSamples;
var startIndex = base.findLowIndexInSortedArray(
counter.timestamps,
function(x) { return x; },
viewLWorld);
startIndex = startIndex - 1 > 0 ? startIndex - 1 : 0;
// Draw indices one by one until we fall off the viewRWorld.
var yScale = height / counter.maxTotal;
for (var seriesIndex = counter.numSeries - 1;
seriesIndex >= 0; seriesIndex--) {
var colorId = counter.series[seriesIndex].color;
ctx.fillStyle = palette[colorId];
ctx.beginPath();
// Set iLast and xLast such that the first sample we draw is the
// startIndex sample.
var iLast = startIndex - 1;
var xLast = iLast >= 0 ?
counter.timestamps[iLast] - skipDistanceWorld : -1;
var yLastView = height;
// Iterate over samples from iLast onward until we either fall off the
// viewRWorld or we run out of samples. To avoid drawing too much, after
// drawing a sample at xLast, skip subsequent samples that are less than
// skipDistanceWorld from xLast.
var hasMoved = false;
while (true) {
var i = iLast + 1;
if (i >= numSamples) {
ctx.lineTo(xLast, yLastView);
ctx.lineTo(xLast + 8 * pixWidth, yLastView);
ctx.lineTo(xLast + 8 * pixWidth, height);
break;
}
var x = counter.timestamps[i];
var y = counter.totals[i * numSeries + seriesIndex];
var yView = height - (yScale * y);
if (x > viewRWorld) {
ctx.lineTo(x, yLastView);
ctx.lineTo(x, height);
break;
}
if (i + 1 < numSamples) {
var xNext = counter.timestamps[i + 1];
if (xNext - xLast <= skipDistanceWorld && xNext < viewRWorld) {
iLast = i;
continue;
}
}
if (!hasMoved) {
ctx.moveTo(viewLWorld, height);
hasMoved = true;
}
if (x - xLast < skipDistanceWorld) {
// We know that xNext > xLast + skipDistanceWorld, so we can
// safely move this sample's x over that much without passing
// xNext. This ensure that the previous sample is visible when
// zoomed out very far.
x = xLast + skipDistanceWorld;
}
ctx.lineTo(x, yLastView);
ctx.lineTo(x, yView);
iLast = i;
xLast = x;
yLastView = yView;
}
ctx.closePath();
ctx.fill();
}
ctx.fillStyle = 'rgba(255, 0, 0, 1)';
for (var i in this.selectedSamples_) {
if (!this.selectedSamples_[i])
continue;
var x = counter.timestamps[i];
for (var seriesIndex = counter.numSeries - 1;
seriesIndex >= 0; seriesIndex--) {
var y = counter.totals[i * numSeries + seriesIndex];
var yView = height - (yScale * y);
ctx.fillRect(x - pixWidth, yView - 1, 3 * pixWidth, 3);
}
}
ctx.restore();
},
addIntersectingItemsInRangeToSelectionInWorldSpace: function(
loWX, hiWX, viewPixWidthWorld, selection) {
function getSampleWidth(x, i) {
if (i === counter.timestamps.length - 1)
return 0;
return counter.timestamps[i + 1] - counter.timestamps[i];
}
var counter = this.counter_;
var iLo = base.findLowIndexInSortedIntervals(counter.timestamps,
function(x) { return x; },
getSampleWidth,
loWX);
var iHi = base.findLowIndexInSortedIntervals(counter.timestamps,
function(x) { return x; },
getSampleWidth,
hiWX);
// Iterate over every sample intersecting..
for (var i = iLo; i <= iHi; i++) {
if (i < 0)
continue;
if (i >= counter.timestamps.length)
continue;
// TODO(nduca): Pick the seriesIndexHit based on the loY - hiY values.
var hit = selection.addCounterSample(this, this.counter, i);
this.decorateHit(hit);
}
},
addAllObjectsMatchingFilterToSelection: function(filter, selection) {
}
};
return {
CounterTrack: CounterTrack
};
});