blob: 4cf94ce7234370d0f10ea62bd76ae74cf71235d1 [file] [log] [blame]
Jamie Gennis66a37682013-07-15 18:29:18 -07001// 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.
4
5'use strict';
6
7base.requireStylesheet('tracing.tracks.object_instance_track');
8
9base.require('base.sorted_array_utils');
Jamie Gennis6833e182013-07-19 14:00:49 -070010base.require('tracing.tracks.heading_track');
Jamie Gennis66a37682013-07-15 18:29:18 -070011base.require('tracing.color_scheme');
12base.require('ui');
13
14base.exportTo('tracing.tracks', function() {
15
16 var palette = tracing.getColorPalette();
17 var highlightIdBoost = tracing.getColorPaletteHighlightIdBoost();
18
19 /**
20 * A track that displays an array of Slice objects.
21 * @constructor
Jamie Gennis6833e182013-07-19 14:00:49 -070022 * @extends {HeadingTrack}
Jamie Gennis66a37682013-07-15 18:29:18 -070023 */
24
25 var ObjectInstanceTrack = ui.define(
Jamie Gennis6833e182013-07-19 14:00:49 -070026 'object-instance-track', tracing.tracks.HeadingTrack);
Jamie Gennis66a37682013-07-15 18:29:18 -070027
28 ObjectInstanceTrack.prototype = {
Jamie Gennis6833e182013-07-19 14:00:49 -070029 __proto__: tracing.tracks.HeadingTrack.prototype,
Jamie Gennis66a37682013-07-15 18:29:18 -070030
31 decorate: function(viewport) {
Jamie Gennis6833e182013-07-19 14:00:49 -070032 tracing.tracks.HeadingTrack.prototype.decorate.call(this, viewport);
Jamie Gennis66a37682013-07-15 18:29:18 -070033 this.classList.add('object-instance-track');
34 this.objectInstances_ = [];
35 this.objectSnapshots_ = [];
36 },
37
38 get objectInstances() {
39 return this.objectInstances_;
40 },
41
42 set objectInstances(objectInstances) {
Jamie Gennis66a37682013-07-15 18:29:18 -070043 if (!objectInstances || objectInstances.length == 0) {
44 this.heading = '';
45 this.objectInstances_ = [];
46 this.objectSnapshots_ = [];
47 return;
48 }
49 this.heading = objectInstances[0].typeName;
50 this.objectInstances_ = objectInstances;
51 this.objectSnapshots_ = [];
52 this.objectInstances_.forEach(function(instance) {
53 this.objectSnapshots_.push.apply(
54 this.objectSnapshots_, instance.snapshots);
55 }, this);
56 },
57
58 get height() {
59 return window.getComputedStyle(this).height;
60 },
61
62 set height(height) {
63 this.style.height = height;
Jamie Gennis66a37682013-07-15 18:29:18 -070064 },
65
66 get snapshotRadiusView() {
67 return 7 * (window.devicePixelRatio || 1);
68 },
69
Jamie Gennis6833e182013-07-19 14:00:49 -070070 draw: function(type, viewLWorld, viewRWorld) {
71 switch (type) {
72 case tracing.tracks.DrawType.SLICE:
73 this.drawSlices_(viewLWorld, viewRWorld);
74 break;
75 }
76 },
77
78 drawSlices_: function(viewLWorld, viewRWorld) {
Jamie Gennis66a37682013-07-15 18:29:18 -070079 var ctx = this.context();
80 var pixelRatio = window.devicePixelRatio || 1;
81
82 var bounds = this.getBoundingClientRect();
83 var height = bounds.height * pixelRatio;
84 var halfHeight = height * 0.5;
85 var twoPi = Math.PI * 2;
86
87 // Culling parameters.
88 var vp = this.viewport;
89 var snapshotRadiusView = this.snapshotRadiusView;
90 var snapshotRadiusWorld = vp.xViewVectorToWorld(height);
91 var loI;
92
93 // Begin rendering in world space.
94 ctx.save();
95 vp.applyTransformToCanvas(ctx);
96
97 // Instances
98 var objectInstances = this.objectInstances_;
99 var loI = base.findLowIndexInSortedArray(
100 objectInstances,
101 function(instance) {
102 return instance.deletionTs;
103 },
104 viewLWorld);
105 ctx.globalAlpha = 0.25;
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;
110 if (x > viewRWorld)
111 break;
112
113 var colorId = instance.selected ?
114 instance.colorId + highlightIdBoost :
115 instance.colorId;
116
117 var right = instance.deletionTs == Number.MAX_VALUE ?
118 viewRWorld : instance.deletionTs;
119 ctx.fillStyle = palette[colorId];
120 ctx.fillRect(x, pixelRatio, right - x, height - 2 * pixelRatio);
121 }
122 ctx.globalAlpha = 1;
123 ctx.restore();
124
125 // Snapshots. Has to run in worldspace because ctx.arc gets transformed.
126 var objectSnapshots = this.objectSnapshots_;
127 loI = base.findLowIndexInSortedArray(
128 objectSnapshots,
129 function(snapshot) {
130 return snapshot.ts +
131 snapshotRadiusWorld;
132 },
133 viewLWorld);
134 for (var i = loI; i < objectSnapshots.length; ++i) {
135 var snapshot = objectSnapshots[i];
136 var x = snapshot.ts;
137 if (x - snapshotRadiusWorld > viewRWorld)
138 break;
139 var xView = vp.xWorldToView(x);
140
141 var colorId = snapshot.selected ?
142 snapshot.objectInstance.colorId + highlightIdBoost :
143 snapshot.objectInstance.colorId;
144
145 ctx.fillStyle = palette[colorId];
146 ctx.beginPath();
147 ctx.arc(xView, halfHeight, snapshotRadiusView, 0, twoPi);
148 ctx.fill();
149 if (snapshot.selected) {
150 ctx.lineWidth = 5;
151 ctx.strokeStyle = 'rgb(100,100,0)';
152 ctx.stroke();
153
154 ctx.beginPath();
155 ctx.arc(xView, halfHeight, snapshotRadiusView - 1, 0, twoPi);
156 ctx.lineWidth = 2;
157 ctx.strokeStyle = 'rgb(255,255,0)';
158 ctx.stroke();
159 } else {
160 ctx.lineWidth = 1;
161 ctx.strokeStyle = 'rgb(0,0,0)';
162 ctx.stroke();
163 }
164 }
165 ctx.lineWidth = 1;
166 },
167
168 addIntersectingItemsInRangeToSelectionInWorldSpace: function(
169 loWX, hiWX, viewPixWidthWorld, selection) {
170 var that = this;
171
172 // Pick snapshots first.
173 var foundSnapshot = false;
174 function onSnapshotHit(snapshot) {
175 selection.addObjectSnapshot(that, snapshot);
176 foundSnapshot = true;
177 }
178 var snapshotRadiusView = this.snapshotRadiusView;
179 var snapshotRadiusWorld = viewPixWidthWorld * snapshotRadiusView;
180 base.iterateOverIntersectingIntervals(
181 this.objectSnapshots_,
182 function(x) { return x.ts - snapshotRadiusWorld; },
183 function(x) { return 2 * snapshotRadiusWorld; },
184 loWX, hiWX,
185 onSnapshotHit);
186 if (foundSnapshot)
187 return;
188
189 // Try picking instances.
190 function onInstanceHit(instance) {
191 selection.addObjectInstance(that, instance);
192 }
193 base.iterateOverIntersectingIntervals(
194 this.objectInstances_,
195 function(x) { return x.creationTs; },
196 function(x) { return x.deletionTs - x.creationTs; },
197 loWX, hiWX,
198 onInstanceHit);
199 },
200
201 /**
202 * Add the item to the left or right of the provided hit, if any, to the
203 * selection.
204 * @param {slice} The current slice.
205 * @param {Number} offset Number of slices away from the hit to look.
206 * @param {Selection} selection The selection to add a hit to,
207 * if found.
208 * @return {boolean} Whether a hit was found.
209 * @private
210 */
211 addItemNearToProvidedHitToSelection: function(hit, offset, selection) {
212 if (hit instanceof tracing.SelectionObjectSnapshotHit) {
213 var index = this.objectSnapshots_.indexOf(hit.objectSnapshot);
214 var newIndex = index + offset;
215 if (newIndex >= 0 && newIndex < this.objectSnapshots_.length) {
216 selection.addObjectSnapshot(this, this.objectSnapshots_[newIndex]);
217 return true;
218 }
219 } else if (hit instanceof tracing.SelectionObjectInstanceHit) {
220 var index = this.objectInstances_.indexOf(hit.objectInstance);
221 var newIndex = index + offset;
222 if (newIndex >= 0 && newIndex < this.objectInstances_.length) {
223 selection.addObjectInstance(this, this.objectInstances_[newIndex]);
224 return true;
225 }
226 } else {
227 throw new Error('Unrecognized hit');
228 }
229 return false;
230 },
231
232 addAllObjectsMatchingFilterToSelection: function(filter, selection) {
233 }
234 };
235
236 ObjectInstanceTrack.typeNameToTrackConstructorMap = {};
237 ObjectInstanceTrack.register = function(typeName, constructor) {
238 if (ObjectInstanceTrack.typeNameToTrackConstructorMap[typeName])
239 throw new Error('Handler already registered for ' + typeName);
240 ObjectInstanceTrack.typeNameToTrackConstructorMap[typeName] =
241 constructor;
242 };
243
244 ObjectInstanceTrack.getTrackConstructor = function(typeName) {
245 return ObjectInstanceTrack.typeNameToTrackConstructorMap[typeName];
246 };
247
248 return {
249 ObjectInstanceTrack: ObjectInstanceTrack
250 };
251});