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="/tvcm/ui/common.css">
9 <link rel="stylesheet" href="/tracing/timeline_view.css">
11 <link rel="import" href="/tracing/analysis/analysis_view.html">
12 <link rel="import" href="/tracing/analysis/cpu_slice_view.html">
13 <link rel="import" href="/tracing/analysis/thread_time_slice_view.html">
14 <link rel="import" href="/tracing/find_control.html">
15 <link rel="import" href="/tracing/find_controller.html">
16 <link rel="import" href="/tracing/timeline_track_view.html">
17 <link rel="import" href="/tvcm/utils.html">
18 <link rel="import" href="/tvcm/settings.html">
19 <link rel="import" href="/tvcm/ui/dom_helpers.html">
20 <link rel="import" href="/tvcm/ui/overlay.html">
21 <link rel="import" href="/tvcm/ui/drag_handle.html">
22 <link rel="import" href="/tracing/side_panel/input_latency.html">
23 <link rel="import" href="/tracing/side_panel/sampling_summary.html">
24 <link rel="import" href="/tracing/side_panel/time_summary.html">
25 <link rel="import" href="/tracing/side_panel/timeline_view.html">
27 <template id="timeline-view-template">
29 <div id="left-controls" class="controls"></div>
30 <div class="title">^_^</div>
31 <div id="right-controls" class="controls"></div>
34 <track-view-container></track-view-container>
35 <x-timeline-view-side-panel-container></x-timeline-view-side-panel-container>
37 <x-drag-handle></x-drag-handle>
38 <tracing-analysis-view id="analysis"></tracing-analysis-view>
41 <template id="help-btn-template">
42 <div class="button view-help-button">?</div>
43 <div class="view-help-text">
44 <div class="column left">
47 <div class='command'>w/s</div>
48 <div class='action'>Zoom in/out (+shift: faster)</div>
52 <div class='command'>a/d</div>
53 <div class='action'>Pan left/right (+shift: faster)</div>
57 <div class='command'>→/shift-TAB</div>
58 <div class='action'>Select previous event</div>
62 <div class='command'>←/TAB</div>
63 <div class='action'>Select next event</div>
66 <h2>Mouse Controls</h2>
68 <div class='command'>click</div>
69 <div class='action'>Select event</div>
72 <div class='command'>alt-mousewheel</div>
73 <div class='action'>Zoom in/out</div>
77 <span class='mouse-mode-icon select-mode'></span>
81 <div class='command'>drag</div>
82 <div class='action'>Box select</div>
86 <div class='command'>double click</div>
87 <div class='action'>Select all events with same title</div>
91 <span class='mouse-mode-icon pan-mode'></span>
95 <div class='command'>drag</div>
96 <div class='action'>Pan the view</div>
100 <span class='mouse-mode-icon zoom-mode'></span>
104 <div class='command'>drag</div>
105 <div class='action'>Zoom in/out by dragging up/down</div>
109 <span class='mouse-mode-icon timing-mode'></span>
113 <div class='command'>drag</div>
114 <div class='action'>Create or move markers</div>
118 <div class='command'>double click</div>
119 <div class='action'>Set marker range to slice</div>
123 <div class="column right">
126 <div class='command'>1-4</div>
127 <div class='action'>Switch mouse mode</div>
131 <div class='command'>shift</div>
132 <div class='action'>Hold for temporary select</div>
136 <div class='command'>space</div>
137 <div class='action'>Hold for temporary pan</div>
141 <div class='command'><span class='mod'></span></div>
142 <div class='action'>Hold for temporary zoom</div>
146 <div class='command'>/</div>
147 <div class='action'>Search</div>
151 <div class='command'>enter</div>
152 <div class='action'>Step through search results</div>
156 <div class='command'>f</div>
157 <div class='action'>Zoom into selection</div>
161 <div class='command'>z/0</div>
162 <div class='action'>Reset zoom and pan</div>
166 <div class='command'>g/G</div>
167 <div class='action'>Toggle 60hz grid</div>
171 <div class='command'>m</div>
172 <div class='action'>Mark current selection</div>
176 <div class='command'>?</div>
177 <div class='action'>Show help</div>
183 <template id="metadata-btn-template">
184 <div class="button view-metadata-button view-info-button">Metadata</div>
185 <div class="info-button-text metadata-dialog-text"></div>
192 * @fileoverview View visualizes TRACE_EVENT events using the
193 * tracing.Timeline component and adds in selection summary and control buttons.
195 tvcm.exportTo('tracing', function() {
196 var THIS_DOC = document.currentScript.ownerDocument;
201 * @extends {HTMLUnknownElement}
203 var TimelineView = tvcm.ui.define('x-timeline-view');
205 TimelineView.prototype = {
206 __proto__: HTMLUnknownElement.prototype,
208 decorate: function() {
209 var node = tvcm.instantiateTemplate('#timeline-view-template', THIS_DOC);
210 this.appendChild(node);
212 this.titleEl_ = this.querySelector('.title');
213 this.leftControlsEl_ = this.querySelector('#left-controls');
214 this.rightControlsEl_ = this.querySelector('#right-controls');
215 this.timelineViewSidePanelContainer_ = this.querySelector(
216 'x-timeline-view-side-panel-container');
217 this.trackViewContainer_ = this.querySelector('track-view-container');
219 tvcm.ui.decorate(this.timelineViewSidePanelContainer_,
220 tracing.TimelineViewSidePanelContainer);
222 this.findCtl_ = new TracingFindControl();
223 this.findCtl_.controller = new tracing.FindController();
225 this.rightControls.appendChild(this.createMetadataButton_());
226 this.rightControls.appendChild(this.findCtl_);
227 this.rightControls.appendChild(this.createHelpButton_());
229 this.dragEl_ = this.querySelector('x-drag-handle');
230 tvcm.ui.decorate(this.dragEl_, tvcm.ui.DragHandle);
232 this.analysisEl_ = this.querySelector('#analysis');
234 this.addEventListener('requestSelectionChange',
235 this.onRequestSelectionChange_.bind(this));
238 this.onViewportChanged_ = this.onViewportChanged_.bind(this);
239 this.onSelectionChanged_ = this.onSelectionChanged_.bind(this);
240 document.addEventListener('keydown', this.onKeyDown_.bind(this), true);
241 document.addEventListener('keypress', this.onKeypress_.bind(this), true);
243 this.dragEl_.target = this.analysisEl_;
245 // State management on selection change.
246 this.selections_ = {};
247 window.addEventListener('popstate', this.onPopState_.bind(this));
250 createHelpButton_: function() {
251 var node = tvcm.instantiateTemplate('#help-btn-template', THIS_DOC);
252 var showEl = node.querySelector('.view-help-button');
253 var helpTextEl = node.querySelector('.view-help-text');
255 var dlg = new tvcm.ui.Overlay();
256 dlg.title = 'chrome://tracing Help';
257 dlg.classList.add('view-help-overlay');
258 dlg.appendChild(node);
260 function onClick(e) {
261 dlg.visible = !dlg.visible;
263 var mod = tvcm.isMac ? 'cmd ' : 'ctrl';
264 var spans = helpTextEl.querySelectorAll('span.mod');
265 for (var i = 0; i < spans.length; i++) {
266 spans[i].textContent = mod;
269 // Stop event so it doesn't trigger new click listener on document.
273 showEl.addEventListener('click', onClick.bind(this));
278 createMetadataButton_: function() {
279 var node = tvcm.instantiateTemplate('#metadata-btn-template', THIS_DOC);
280 var showEl = node.querySelector('.view-metadata-button');
281 var textEl = node.querySelector('.info-button-text');
283 var dlg = new tvcm.ui.Overlay();
284 dlg.title = 'Metadata for trace';
285 dlg.classList.add('view-metadata-overlay');
286 dlg.appendChild(node);
288 function onClick(e) {
291 var metadataStrings = [];
293 var model = this.model;
294 for (var data in model.metadata) {
295 var meta = model.metadata[data];
296 var name = JSON.stringify(meta.name);
297 var value = JSON.stringify(meta.value, undefined, ' ');
299 metadataStrings.push(name + ': ' + value);
301 textEl.textContent = metadataStrings.join('\n');
306 showEl.addEventListener('click', onClick.bind(this));
308 function updateVisibility() {
309 showEl.style.display =
310 (this.model && this.model.metadata.length) ? '' : 'none';
312 var updateVisibility_ = updateVisibility.bind(this);
314 this.addEventListener('modelChange', updateVisibility_);
320 return this.leftControlsEl_;
323 get rightControls() {
324 return this.rightControlsEl_;
328 return this.titleEl_.textContent.substring(
329 this.titleEl_.textContent.length - 2);
332 set viewTitle(text) {
333 if (text === undefined) {
334 this.titleEl_.textContent = '';
335 this.titleEl_.hidden = true;
338 this.titleEl_.hidden = false;
339 this.titleEl_.textContent = text;
344 return this.trackView_.model;
349 var modelInstanceChanged = model != this.model;
350 var modelValid = model && !model.bounds.isEmpty;
352 // Remove old trackView if the model has completely changed.
353 if (modelInstanceChanged) {
354 this.trackViewContainer_.textContent = '';
355 if (this.trackView_) {
356 this.trackView_.viewport.removeEventListener(
357 'change', this.onViewportChanged_);
358 this.trackView_.removeEventListener(
359 'selectionChange', this.onSelectionChanged_);
360 this.trackView_.detach();
361 this.trackView_ = undefined;
362 this.findCtl_.controller.trackView = undefined;
364 this.timelineViewSidePanelContainer_.model = undefined;
367 // Create new trackView if needed.
368 if (modelValid && !this.trackView_) {
369 this.trackView_ = new tracing.TimelineTrackView();
370 this.trackView_.focusElement =
371 this.focusElement_ ? this.focusElement_ : this.parentElement;
372 this.trackViewContainer_.appendChild(this.trackView_);
373 this.findCtl_.controller.timeline = this.trackView_;
374 this.trackView_.addEventListener(
375 'selectionChange', this.onSelectionChanged_);
376 this.trackView_.viewport.addEventListener(
377 'change', this.onViewportChanged_);
382 this.trackView_.model = model;
383 this.timelineViewSidePanelContainer_.model = model;
384 this.clearSelectionHistory_();
386 tvcm.dispatchSimpleEvent(this, 'modelChange');
388 // Do things that are selection specific
389 if (modelInstanceChanged) {
390 this.onSelectionChanged_();
391 this.onViewportChanged_();
396 return this.trackView_;
401 this.settings_ = new tvcm.Settings();
402 return this.settings_;
406 * Sets the element whose focus state will determine whether
407 * to respond to keybaord input.
409 set focusElement(value) {
410 this.focusElement_ = value;
412 this.trackView_.focusElement = value;
416 * @return {Element} The element whose focused state determines
417 * whether to respond to keyboard inputs.
418 * Defaults to the parent element.
421 if (this.focusElement_)
422 return this.focusElement_;
423 return this.parentElement;
426 get listenToKeys_() {
427 if (!tvcm.ui.isElementAttachedToDocument(this))
429 if (!this.focusElement_)
431 if (this.focusElement.tabIndex >= 0)
432 return document.activeElement == this.focusElement;
436 onKeyDown_: function(e) {
437 if (!this.listenToKeys_)
440 if (e.keyCode === 27) { // ESC
446 onKeypress_: function(e) {
447 if (!this.listenToKeys_)
450 if (e.keyCode === '/'.charCodeAt(0)) {
451 if (this.findCtl_.hasFocus())
454 this.findCtl_.focus();
456 } else if (e.keyCode === '?'.charCodeAt(0)) {
457 this.querySelector('.view-help-button').click();
462 onSelectionChanged_: function(e) {
463 var oldScrollTop = this.trackViewContainer_.scrollTop;
465 var selection = this.trackView_ ?
466 this.trackView_.selectionOfInterest :
467 new tracing.Selection();
468 this.analysisEl_.selection = selection;
469 this.trackViewContainer_.scrollTop = oldScrollTop;
470 this.timelineViewSidePanelContainer_.selection = selection;
473 onRequestSelectionChange_: function(e) {
474 // Save the selection so that when back button is pressed,
475 // it could be retrieved.
476 this.selections_[e.selection.guid] = e.selection;
478 selection_guid: e.selection.guid
480 window.history.pushState(state);
482 this.trackView_.selection = e.selection;
486 onPopState_: function(e) {
487 if (e.state === null)
490 var selection = this.selections_[e.state.selection_guid];
492 this.trackView_.selection = selection;
496 clearSelectionHistory_: function() {
497 this.selections_ = {};
500 onViewportChanged_: function(e) {
501 var spc = this.timelineViewSidePanelContainer_;
502 if (!this.trackView_) {
503 spc.rangeOfInterest.reset();
507 var vr = this.trackView_.viewport.interestRange.asRangeObject();
508 if (!spc.rangeOfInterest.equals(vr))
509 spc.rangeOfInterest = vr;
514 TimelineView: TimelineView