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.object_instance_track');
9 tvcm.require('tvcm.sorted_array_utils');
10 tvcm.require('tracing.trace_model.event');
11 tvcm.require('tracing.tracks.heading_track');
12 tvcm.require('tracing.color_scheme');
13 tvcm.require('tvcm.ui');
15 tvcm.exportTo('tracing.tracks', function() {
17 var SelectionState = tracing.trace_model.SelectionState;
18 var EventPresenter = tracing.EventPresenter;
21 * A track that displays an array of Slice objects.
23 * @extends {HeadingTrack}
26 var ObjectInstanceTrack = tvcm.ui.define(
27 'object-instance-track', tracing.tracks.HeadingTrack);
29 ObjectInstanceTrack.prototype = {
30 __proto__: tracing.tracks.HeadingTrack.prototype,
32 decorate: function(viewport) {
33 tracing.tracks.HeadingTrack.prototype.decorate.call(this, viewport);
34 this.classList.add('object-instance-track');
35 this.objectInstances_ = [];
36 this.objectSnapshots_ = [];
39 get objectInstances() {
40 return this.objectInstances_;
43 set objectInstances(objectInstances) {
44 if (!objectInstances || objectInstances.length == 0) {
46 this.objectInstances_ = [];
47 this.objectSnapshots_ = [];
50 this.heading = objectInstances[0].typeName;
51 this.objectInstances_ = objectInstances;
52 this.objectSnapshots_ = [];
53 this.objectInstances_.forEach(function(instance) {
54 this.objectSnapshots_.push.apply(
55 this.objectSnapshots_, instance.snapshots);
60 return window.getComputedStyle(this).height;
64 this.style.height = height;
67 get snapshotRadiusView() {
68 return 7 * (window.devicePixelRatio || 1);
71 draw: function(type, viewLWorld, viewRWorld) {
73 case tracing.tracks.DrawType.SLICE:
74 this.drawSlices_(viewLWorld, viewRWorld);
79 drawSlices_: function(viewLWorld, viewRWorld) {
80 var ctx = this.context();
81 var pixelRatio = window.devicePixelRatio || 1;
83 var bounds = this.getBoundingClientRect();
84 var height = bounds.height * pixelRatio;
85 var halfHeight = height * 0.5;
86 var twoPi = Math.PI * 2;
88 // Culling parameters.
89 var dt = this.viewport.currentDisplayTransform;
90 var snapshotRadiusView = this.snapshotRadiusView;
91 var snapshotRadiusWorld = dt.xViewVectorToWorld(height);
94 // Begin rendering in world space.
96 dt.applyTransformToCanvas(ctx);
99 var objectInstances = this.objectInstances_;
100 var loI = tvcm.findLowIndexInSortedArray(
103 return instance.deletionTs;
106 ctx.strokeStyle = 'rgb(0,0,0)';
107 for (var i = loI; i < objectInstances.length; ++i) {
108 var instance = objectInstances[i];
109 var x = instance.creationTs;
113 var right = instance.deletionTs == Number.MAX_VALUE ?
114 viewRWorld : instance.deletionTs;
115 ctx.fillStyle = EventPresenter.getObjectInstanceColor(instance);
116 ctx.fillRect(x, pixelRatio, right - x, height - 2 * pixelRatio);
120 // Snapshots. Has to run in worldspace because ctx.arc gets transformed.
121 var objectSnapshots = this.objectSnapshots_;
122 loI = tvcm.findLowIndexInSortedArray(
125 return snapshot.ts + snapshotRadiusWorld;
128 for (var i = loI; i < objectSnapshots.length; ++i) {
129 var snapshot = objectSnapshots[i];
131 if (x - snapshotRadiusWorld > viewRWorld)
133 var xView = dt.xWorldToView(x);
135 ctx.fillStyle = EventPresenter.getObjectSnapshotColor(snapshot);
137 ctx.arc(xView, halfHeight, snapshotRadiusView, 0, twoPi);
139 if (snapshot.selected) {
141 ctx.strokeStyle = 'rgb(100,100,0)';
145 ctx.arc(xView, halfHeight, snapshotRadiusView - 1, 0, twoPi);
147 ctx.strokeStyle = 'rgb(255,255,0)';
151 ctx.strokeStyle = 'rgb(0,0,0)';
157 // For performance reasons we only check the SelectionState of the first
158 // instance. If it's DIMMED we assume that all are DIMMED.
159 // TODO(egraether): Allow partial highlight.
160 var selectionState = SelectionState.NONE;
161 if (objectInstances.length &&
162 objectInstances[0].selectionState === SelectionState.DIMMED) {
163 selectionState = SelectionState.DIMMED;
166 // Dim the track when there is an active highlight.
167 if (selectionState === SelectionState.DIMMED) {
168 var width = bounds.width * pixelRatio;
169 ctx.fillStyle = 'rgba(255,255,255,0.5)';
170 ctx.fillRect(0, 0, width, height);
175 addEventsToTrackMap: function(eventToTrackMap) {
176 if (this.objectInstance_ !== undefined) {
177 this.objectInstance_.forEach(function(obj) {
178 eventToTrackMap.addEvent(obj, this);
182 if (this.objectSnapshots_ !== undefined) {
183 this.objectSnapshots_.forEach(function(obj) {
184 eventToTrackMap.addEvent(obj, this);
189 addIntersectingItemsInRangeToSelectionInWorldSpace: function(
190 loWX, hiWX, viewPixWidthWorld, selection) {
191 // Pick snapshots first.
192 var foundSnapshot = false;
193 function onSnapshot(snapshot) {
194 selection.push(snapshot);
195 foundSnapshot = true;
197 var snapshotRadiusView = this.snapshotRadiusView;
198 var snapshotRadiusWorld = viewPixWidthWorld * snapshotRadiusView;
199 tvcm.iterateOverIntersectingIntervals(
200 this.objectSnapshots_,
201 function(x) { return x.ts - snapshotRadiusWorld; },
202 function(x) { return 2 * snapshotRadiusWorld; },
208 // Try picking instances.
209 tvcm.iterateOverIntersectingIntervals(
210 this.objectInstances_,
211 function(x) { return x.creationTs; },
212 function(x) { return x.deletionTs - x.creationTs; },
214 selection.push.bind(selection));
218 * Add the item to the left or right of the provided event, if any, to the
220 * @param {event} The current event item.
221 * @param {Number} offset Number of slices away from the event to look.
222 * @param {Selection} selection The selection to add an event to,
224 * @return {boolean} Whether an event was found.
227 addItemNearToProvidedEventToSelection: function(event, offset, selection) {
229 if (event instanceof tracing.trace_model.ObjectSnapshot)
230 events = this.objectSnapshots_;
231 else if (event instanceof tracing.trace_model.ObjectInstance)
232 events = this.objectInstances_;
234 throw new Error('Unrecognized event');
236 var index = events.indexOf(event);
237 var newIndex = index + offset;
238 if (newIndex >= 0 && newIndex < events.length) {
239 selection.push(events[newIndex]);
245 addAllObjectsMatchingFilterToSelection: function(filter, selection) {
248 addClosestEventToSelection: function(worldX, worldMaxDist, loY, hiY,
250 var snapshot = tvcm.findClosestElementInSortedArray(
251 this.objectSnapshots_,
252 function(x) { return x.ts; },
259 selection.push(snapshot);
261 // TODO(egraether): Search for object instances as well, which was not
262 // implemented because it makes little sense with the current visual and
263 // needs to take care of overlapping intervals.
267 ObjectInstanceTrack.typeNameToTrackConstructorMap = {};
268 ObjectInstanceTrack.register = function(typeName, constructor) {
269 if (ObjectInstanceTrack.typeNameToTrackConstructorMap[typeName])
270 throw new Error('Handler already registered for ' + typeName);
271 ObjectInstanceTrack.typeNameToTrackConstructorMap[typeName] =
275 ObjectInstanceTrack.getTrackConstructor = function(typeName) {
276 return ObjectInstanceTrack.typeNameToTrackConstructorMap[typeName];
280 ObjectInstanceTrack: ObjectInstanceTrack