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/trace_model_track.css">
10 <link rel="import" href="/tracing/tracks/container_track.html">
11 <link rel="import" href="/tracing/tracks/kernel_track.html">
12 <link rel="import" href="/tracing/tracks/process_track.html">
13 <link rel="import" href="/tracing/draw_helpers.html">
14 <link rel="import" href="/base/measuring_stick.html">
15 <link rel="import" href="/base/ui.html">
20 tv.exportTo('tracing.tracks', function() {
22 * Visualizes a Model by building ProcessTracks and
26 var TraceModelTrack = tv.ui.define(
27 'trace-model-track', tracing.tracks.ContainerTrack);
29 TraceModelTrack.prototype = {
31 __proto__: tracing.tracks.ContainerTrack.prototype,
33 decorate: function(viewport) {
34 tracing.tracks.ContainerTrack.prototype.decorate.call(this, viewport);
35 this.classList.add('model-track');
39 tracing.tracks.ContainerTrack.prototype.detach.call(this);
48 this.updateContents_();
51 get hasVisibleContent() {
52 return this.children.length > 0;
55 updateContents_: function() {
56 this.textContent = '';
60 this.appendKernelTrack_();
62 // Get a sorted list of processes.
63 var processes = this.model_.getAllProcesses();
64 processes.sort(tracing.trace_model.Process.compare);
66 for (var i = 0; i < processes.length; ++i) {
67 var process = processes[i];
69 var track = new tracing.tracks.ProcessTrack(this.viewport);
70 track.process = process;
71 if (!track.hasVisibleContent)
74 this.appendChild(track);
76 this.viewport_.rebuildEventToTrackMap();
79 addEventsToTrackMap: function(eventToTrackMap) {
83 var tracks = this.children;
84 for (var i = 0; i < tracks.length; ++i)
85 tracks[i].addEventsToTrackMap(eventToTrackMap);
87 if (this.instantEvents === undefined)
90 var vp = this.viewport_;
91 this.instantEvents.forEach(function(ev) {
92 eventToTrackMap.addEvent(ev, this);
96 appendKernelTrack_: function() {
97 var kernel = this.model.kernel;
98 var track = new tracing.tracks.KernelTrack(this.viewport);
99 track.kernel = this.model.kernel;
100 if (!track.hasVisibleContent)
102 this.appendChild(track);
105 drawTrack: function(type) {
106 var ctx = this.context();
108 var pixelRatio = window.devicePixelRatio || 1;
109 var bounds = this.getBoundingClientRect();
110 var canvasBounds = ctx.canvas.getBoundingClientRect();
113 ctx.translate(0, pixelRatio * (bounds.top - canvasBounds.top));
115 var dt = this.viewport.currentDisplayTransform;
116 var viewLWorld = dt.xViewToWorld(0);
117 var viewRWorld = dt.xViewToWorld(bounds.width * pixelRatio);
120 case tracing.tracks.DrawType.GRID:
121 this.viewport.drawMajorMarkLines(ctx);
122 // The model is the only thing that draws grid lines.
126 case tracing.tracks.DrawType.FLOW_ARROWS:
127 if (this.model_.flowIntervalTree.size === 0) {
132 this.drawFlowArrows_(viewLWorld, viewRWorld);
136 case tracing.tracks.DrawType.INSTANT_EVENT:
137 if (!this.model_.instantEvents ||
138 this.model_.instantEvents.length === 0)
141 tracing.drawInstantSlicesAsLines(
143 this.viewport.currentDisplayTransform,
147 this.model_.instantEvents,
152 case tracing.tracks.DrawType.MARKERS:
153 if (!this.viewport.interestRange.isEmpty) {
154 this.viewport.interestRange.draw(ctx, viewLWorld, viewRWorld);
155 this.viewport.interestRange.drawIndicators(
156 ctx, viewLWorld, viewRWorld);
163 tracing.tracks.ContainerTrack.prototype.drawTrack.call(this, type);
166 drawFlowArrows_: function(viewLWorld, viewRWorld) {
167 var ctx = this.context();
168 var dt = this.viewport.currentDisplayTransform;
169 dt.applyTransformToCanvas(ctx);
171 var pixWidth = dt.xViewVectorToWorld(1);
173 ctx.strokeStyle = 'rgba(0, 0, 0, 0.4)';
174 ctx.fillStyle = 'rgba(0, 0, 0, 0.4)';
175 ctx.lineWidth = pixWidth > 1.0 ? 1 : pixWidth;
178 this.model_.flowIntervalTree.findIntersection(viewLWorld, viewRWorld);
180 var minWidth = 2 * pixWidth;
181 var canvasBounds = ctx.canvas.getBoundingClientRect();
183 for (var i = 0; i < events.length; ++i) {
184 var startEvent = events[i][0];
185 var endEvent = events[i][1];
187 // Skip lines that will be, essentially, vertical.
188 var distance = endEvent.start - startEvent.start;
189 if (distance <= minWidth)
192 this.drawFlowArrowBetween_(
193 ctx, startEvent, endEvent, canvasBounds, pixWidth);
197 drawFlowArrowBetween_: function(ctx, startEvent, endEvent,
198 canvasBounds, pixWidth) {
199 var pixelRatio = window.devicePixelRatio || 1;
201 var startTrack = this.viewport.trackForEvent(startEvent);
202 var endTrack = this.viewport.trackForEvent(endEvent);
204 var startBounds = startTrack.getBoundingClientRect();
205 var endBounds = endTrack.getBoundingClientRect();
207 if (startEvent.selected || endEvent.selected) {
209 ctx.shadowColor = 'red';
210 ctx.shadowOffsety = 2;
211 ctx.strokeStyle = 'red';
214 var startSize = startBounds.left + startBounds.top +
215 startBounds.bottom + startBounds.right;
216 var endSize = endBounds.left + endBounds.top +
217 endBounds.bottom + endBounds.right;
218 // Nothing to do if both ends of the track are collapsed.
219 if (startSize === 0 && endSize === 0)
222 var startY = this.calculateTrackY_(startTrack, canvasBounds);
223 var endY = this.calculateTrackY_(endTrack, canvasBounds);
225 var pixelStartY = pixelRatio * startY;
226 var pixelEndY = pixelRatio * endY;
227 var half = (endEvent.start - startEvent.start) / 2;
230 ctx.moveTo(startEvent.start, pixelStartY);
232 startEvent.start + half, pixelStartY,
233 startEvent.start + half, pixelEndY,
234 endEvent.start, pixelEndY);
237 if (startEvent.selected || endEvent.selected) {
239 ctx.shadowOffsetX = 0;
240 ctx.strokeStyle = 'rgba(0, 0, 0, 0.4)';
243 var arrowWidth = 5 * pixWidth * pixelRatio;
244 var distance = endEvent.start - startEvent.start;
245 if (distance <= (2 * arrowWidth))
248 var tipX = endEvent.start;
249 var tipY = pixelEndY;
250 var arrowHeight = (endBounds.height / 4) * pixelRatio;
251 tracing.drawTriangle(ctx,
253 tipX - arrowWidth, tipY - arrowHeight,
254 tipX - arrowWidth, tipY + arrowHeight);
258 calculateTrackY_: function(track, canvasBounds) {
259 var bounds = track.getBoundingClientRect();
260 var size = bounds.left + bounds.top + bounds.bottom + bounds.right;
262 return this.calculateTrackY_(track.parentNode, canvasBounds);
264 return bounds.top - canvasBounds.top + (bounds.height / 2);
267 addIntersectingItemsInRangeToSelectionInWorldSpace: function(
268 loWX, hiWX, viewPixWidthWorld, selection) {
269 function onPickHit(instantEvent) {
270 selection.push(instantEvent);
272 tv.iterateOverIntersectingIntervals(this.model_.instantEvents,
273 function(x) { return x.start; },
274 function(x) { return x.duration; },
276 onPickHit.bind(this));
278 tracing.tracks.ContainerTrack.prototype.
279 addIntersectingItemsInRangeToSelectionInWorldSpace.
280 apply(this, arguments);
283 addClosestEventToSelection: function(worldX, worldMaxDist, loY, hiY,
285 this.addClosestInstantEventToSelection(this.model_.instantEvents,
286 worldX, worldMaxDist, selection);
287 tracing.tracks.ContainerTrack.prototype.addClosestEventToSelection.
288 apply(this, arguments);
293 TraceModelTrack: TraceModelTrack