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/object_instance_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/sorted_array_utils.html">
14 <link rel="import" href="/tvcm/ui.html">
19 tvcm.exportTo('tracing.tracks', function() {
21 var SelectionState = tracing.trace_model.SelectionState;
22 var EventPresenter = tracing.EventPresenter;
25 * A track that displays an array of Slice objects.
27 * @extends {HeadingTrack}
30 var ObjectInstanceTrack = tvcm.ui.define(
31 'object-instance-track', tracing.tracks.HeadingTrack);
33 ObjectInstanceTrack.prototype = {
34 __proto__: tracing.tracks.HeadingTrack.prototype,
36 decorate: function(viewport) {
37 tracing.tracks.HeadingTrack.prototype.decorate.call(this, viewport);
38 this.classList.add('object-instance-track');
39 this.objectInstances_ = [];
40 this.objectSnapshots_ = [];
43 get objectInstances() {
44 return this.objectInstances_;
47 set objectInstances(objectInstances) {
48 if (!objectInstances || objectInstances.length == 0) {
50 this.objectInstances_ = [];
51 this.objectSnapshots_ = [];
54 this.heading = objectInstances[0].typeName;
55 this.objectInstances_ = objectInstances;
56 this.objectSnapshots_ = [];
57 this.objectInstances_.forEach(function(instance) {
58 this.objectSnapshots_.push.apply(
59 this.objectSnapshots_, instance.snapshots);
61 this.objectSnapshots_.sort(function(a, b) {
67 return window.getComputedStyle(this).height;
71 this.style.height = height;
74 get snapshotRadiusView() {
75 return 7 * (window.devicePixelRatio || 1);
78 draw: function(type, viewLWorld, viewRWorld) {
80 case tracing.tracks.DrawType.SLICE:
81 this.drawSlices_(viewLWorld, viewRWorld);
86 drawSlices_: function(viewLWorld, viewRWorld) {
87 var ctx = this.context();
88 var pixelRatio = window.devicePixelRatio || 1;
90 var bounds = this.getBoundingClientRect();
91 var height = bounds.height * pixelRatio;
92 var halfHeight = height * 0.5;
93 var twoPi = Math.PI * 2;
95 // Culling parameters.
96 var dt = this.viewport.currentDisplayTransform;
97 var snapshotRadiusView = this.snapshotRadiusView;
98 var snapshotRadiusWorld = dt.xViewVectorToWorld(height);
101 // Begin rendering in world space.
103 dt.applyTransformToCanvas(ctx);
106 var objectInstances = this.objectInstances_;
107 var loI = tvcm.findLowIndexInSortedArray(
110 return instance.deletionTs;
113 ctx.strokeStyle = 'rgb(0,0,0)';
114 for (var i = loI; i < objectInstances.length; ++i) {
115 var instance = objectInstances[i];
116 var x = instance.creationTs;
120 var right = instance.deletionTs == Number.MAX_VALUE ?
121 viewRWorld : instance.deletionTs;
122 ctx.fillStyle = EventPresenter.getObjectInstanceColor(instance);
123 ctx.fillRect(x, pixelRatio, right - x, height - 2 * pixelRatio);
127 // Snapshots. Has to run in worldspace because ctx.arc gets transformed.
128 var objectSnapshots = this.objectSnapshots_;
129 loI = tvcm.findLowIndexInSortedArray(
132 return snapshot.ts + snapshotRadiusWorld;
135 for (var i = loI; i < objectSnapshots.length; ++i) {
136 var snapshot = objectSnapshots[i];
138 if (x - snapshotRadiusWorld > viewRWorld)
140 var xView = dt.xWorldToView(x);
142 ctx.fillStyle = EventPresenter.getObjectSnapshotColor(snapshot);
144 ctx.arc(xView, halfHeight, snapshotRadiusView, 0, twoPi);
146 if (snapshot.selected) {
148 ctx.strokeStyle = 'rgb(100,100,0)';
152 ctx.arc(xView, halfHeight, snapshotRadiusView - 1, 0, twoPi);
154 ctx.strokeStyle = 'rgb(255,255,0)';
158 ctx.strokeStyle = 'rgb(0,0,0)';
164 // For performance reasons we only check the SelectionState of the first
165 // instance. If it's DIMMED we assume that all are DIMMED.
166 // TODO(egraether): Allow partial highlight.
167 var selectionState = SelectionState.NONE;
168 if (objectInstances.length &&
169 objectInstances[0].selectionState === SelectionState.DIMMED) {
170 selectionState = SelectionState.DIMMED;
173 // Dim the track when there is an active highlight.
174 if (selectionState === SelectionState.DIMMED) {
175 var width = bounds.width * pixelRatio;
176 ctx.fillStyle = 'rgba(255,255,255,0.5)';
177 ctx.fillRect(0, 0, width, height);
182 addEventsToTrackMap: function(eventToTrackMap) {
183 if (this.objectInstance_ !== undefined) {
184 this.objectInstance_.forEach(function(obj) {
185 eventToTrackMap.addEvent(obj, this);
189 if (this.objectSnapshots_ !== undefined) {
190 this.objectSnapshots_.forEach(function(obj) {
191 eventToTrackMap.addEvent(obj, this);
196 addIntersectingItemsInRangeToSelectionInWorldSpace: function(
197 loWX, hiWX, viewPixWidthWorld, selection) {
198 // Pick snapshots first.
199 var foundSnapshot = false;
200 function onSnapshot(snapshot) {
201 selection.push(snapshot);
202 foundSnapshot = true;
204 var snapshotRadiusView = this.snapshotRadiusView;
205 var snapshotRadiusWorld = viewPixWidthWorld * snapshotRadiusView;
206 tvcm.iterateOverIntersectingIntervals(
207 this.objectSnapshots_,
208 function(x) { return x.ts - snapshotRadiusWorld; },
209 function(x) { return 2 * snapshotRadiusWorld; },
215 // Try picking instances.
216 tvcm.iterateOverIntersectingIntervals(
217 this.objectInstances_,
218 function(x) { return x.creationTs; },
219 function(x) { return x.deletionTs - x.creationTs; },
221 selection.push.bind(selection));
225 * Add the item to the left or right of the provided event, if any, to the
227 * @param {event} The current event item.
228 * @param {Number} offset Number of slices away from the event to look.
229 * @param {Selection} selection The selection to add an event to,
231 * @return {boolean} Whether an event was found.
234 addItemNearToProvidedEventToSelection: function(event, offset, selection) {
236 if (event instanceof tracing.trace_model.ObjectSnapshot)
237 events = this.objectSnapshots_;
238 else if (event instanceof tracing.trace_model.ObjectInstance)
239 events = this.objectInstances_;
241 throw new Error('Unrecognized event');
243 var index = events.indexOf(event);
244 var newIndex = index + offset;
245 if (newIndex >= 0 && newIndex < events.length) {
246 selection.push(events[newIndex]);
252 addAllObjectsMatchingFilterToSelection: function(filter, selection) {
255 addClosestEventToSelection: function(worldX, worldMaxDist, loY, hiY,
257 var snapshot = tvcm.findClosestElementInSortedArray(
258 this.objectSnapshots_,
259 function(x) { return x.ts; },
266 selection.push(snapshot);
268 // TODO(egraether): Search for object instances as well, which was not
269 // implemented because it makes little sense with the current visual and
270 // needs to take care of overlapping intervals.
274 ObjectInstanceTrack.typeNameToTrackConstructorMap = {};
275 ObjectInstanceTrack.register = function(typeName, constructor) {
276 if (ObjectInstanceTrack.typeNameToTrackConstructorMap[typeName])
277 throw new Error('Handler already registered for ' + typeName);
278 ObjectInstanceTrack.typeNameToTrackConstructorMap[typeName] =
282 ObjectInstanceTrack.getTrackConstructor = function(typeName) {
283 return ObjectInstanceTrack.typeNameToTrackConstructorMap[typeName];
287 ObjectInstanceTrack: ObjectInstanceTrack