Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(77)

Side by Side Diff: chrome/browser/resources/tracing/timeline_view.js

Issue 10170001: Find feature for tracing, at long last. (Closed) Base URL: git://localhost/home/nduca/Local/chrome/src@master
Patch Set: patch for landing Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 'use strict'; 5 'use strict';
6 6
7 /** 7 /**
8 * @fileoverview TimelineView visualizes TRACE_EVENT events using the 8 * @fileoverview TimelineView visualizes TRACE_EVENT events using the
9 * tracing.Timeline component. 9 * tracing.Timeline component and adds in selection summary and control buttons.
10 */ 10 */
11 cr.define('tracing', function() { 11 cr.define('tracing', function() {
12 function tsRound(ts) { 12 function tsRound(ts) {
13 return Math.round(ts * 1000.0) / 1000.0; 13 return Math.round(ts * 1000.0) / 1000.0;
14 } 14 }
15 function getPadding(text, width) { 15 function getPadding(text, width) {
16 width = width || 0; 16 width = width || 0;
17 17
18 if (typeof text != 'string') 18 if (typeof text != 'string')
19 text = String(text); 19 text = String(text);
20 20
21 if (text.length >= width) 21 if (text.length >= width)
22 return ''; 22 return '';
23 23
24 var pad = ''; 24 var pad = '';
25 for (var i = 0; i < width - text.length; i++) 25 for (var i = 0; i < width - text.length; i++)
26 pad += ' '; 26 pad += ' ';
27 return pad; 27 return pad;
28 } 28 }
29 29
30 function leftAlign(text, width) { 30 function leftAlign(text, width) {
31 return text + getPadding(text, width); 31 return text + getPadding(text, width);
32 } 32 }
33 33
34 function rightAlign(text, width) { 34 function rightAlign(text, width) {
35 return getPadding(text, width) + text; 35 return getPadding(text, width) + text;
36 } 36 }
37 37
38 /** 38 /**
39 * TimelineFindControl
40 * @constructor
41 * @extends {tracing.Overlay}
42 */
43 var TimelineFindControl = cr.ui.define('div');
44
45 TimelineFindControl.prototype = {
46 __proto__: tracing.Overlay.prototype,
47
48 decorate: function() {
49 tracing.Overlay.prototype.decorate.call(this);
50
51 this.className = 'timeline-find-control';
52
53 this.hitCountEl_ = document.createElement('span');
54 this.hitCountEl_.className = 'hit-count-label';
55 this.hitCountEl_.textContent = '1 of 7';
56
57 var findPreviousBn = document.createElement('span');
58 findPreviousBn.className = 'find-button find-previous';
59 findPreviousBn.textContent = '\u2190';
60 findPreviousBn.addEventListener('click', function() {
61 this.controller.findPrevious();
62 this.updateHitCountEl_();
63 }.bind(this));
64
65 var findNextBn = document.createElement('span');
66 findNextBn.className = 'find-button find-next';
67 findNextBn.textContent = '\u2192';
68 findNextBn.addEventListener('click', function() {
69 this.controller.findNext();
70 this.updateHitCountEl_();
71 }.bind(this));
72
73 // Filter input element.
74 this.filterEl_ = document.createElement('input');
75 this.filterEl_.type = 'input';
76
77 this.filterEl_.addEventListener('input', function(e) {
78 this.controller.filterText = this.filterEl_.value;
79 this.updateHitCountEl_();
80 }.bind(this));
81
82 this.filterEl_.addEventListener('keydown', function(e) {
83 if (e.keyCode == 13) {
84 findNextBn.click();
85 } else if (e.keyCode == 27) {
86 this.filterEl_.blur();
87 this.updateHitCountEl_();
88 }
89 }.bind(this));
90
91 this.filterEl_.addEventListener('blur', function(e) {
92 this.updateHitCountEl_();
93 }.bind(this));
94
95 this.filterEl_.addEventListener('focus', function(e) {
96 this.updateHitCountEl_();
97 }.bind(this));
98
99 // Attach everything.
100 this.appendChild(this.filterEl_);
101
102 this.appendChild(findPreviousBn);
103 this.appendChild(findNextBn);
104 this.appendChild(this.hitCountEl_);
105
106 this.updateHitCountEl_();
107 },
108
109 get controller() {
110 return this.controller_;
111 },
112
113 set controller(c) {
114 this.controller_ = c;
115 this.updateHitCountEl_();
116 },
117
118 focus: function() {
119 this.filterEl_.selectionStart = 0;
120 this.filterEl_.selectionEnd = this.filterEl_.value.length;
121 this.filterEl_.focus();
122 },
123
124 updateHitCountEl_: function() {
125 if (!this.controller || document.activeElement != this.filterEl_) {
126 this.hitCountEl_.textContent = '';
127 return;
128 }
129 var i = this.controller.currentHitIndex;
130 var n = this.controller.filterHits.length;
131 if (n == 0)
132 this.hitCountEl_.textContent = '0 of 0';
133 else
134 this.hitCountEl_.textContent = (i + 1) + ' of ' + n;
135 }
136 };
137
138 function TimelineFindController() {
139 this.timeline_ = undefined;
140 this.model_ = undefined;
141 this.filterText_ = '';
142 this.filterHitsDirty_ = true;
143 this.currentHitIndex_ = 0;
144 };
145
146 TimelineFindController.prototype = {
147 __proto__: Object.prototype,
148
149 get timeline() {
150 return this.timeline_;
151 },
152
153 set timeline(t) {
154 this.timeline_ = t;
155 this.filterHitsDirty_ = true;
156 },
157
158 get filterText() {
159 return this.filterText_;
160 },
161
162 set filterText(f) {
163 if (f == this.filterText_)
164 return;
165 this.filterText_ = f;
166 this.filterHitsDirty_ = true;
167 this.findNext();
168 },
169
170 get filterHits() {
171 if (this.filterHitsDirty_) {
172 this.filterHitsDirty_ = false;
173 if (this.timeline_) {
174 var filter = new tracing.TimelineFilter(this.filterText);
175 this.filterHits_ = this.timeline.findAllObjectsMatchingFilter(filter);
176 this.currentHitIndex_ = this.filterHits_.length - 1;
177 } else {
178 this.filterHits_ = [];
179 this.currentHitIndex_ = 0;
180 }
181 }
182 return this.filterHits_;
183 },
184
185 get currentHitIndex() {
186 return this.currentHitIndex_;
187 },
188
189 find_: function(dir) {
190 if (!this.timeline)
191 return;
192
193 var N = this.filterHits.length;
194 this.currentHitIndex_ = this.currentHitIndex_ + dir;
195
196 if (this.currentHitIndex_ < 0) this.currentHitIndex_ = N - 1;
197 if (this.currentHitIndex_ >= N) this.currentHitIndex_ = 0;
198
199 if (this.currentHitIndex_ < 0 || this.currentHitIndex_ >= N) {
200 this.timeline.selection = [];
201 return;
202 }
203
204 var hit = this.filterHits[this.currentHitIndex_];
205
206 // We allow the zoom level to change on the first hit level. But, when
207 // then cycling through subsequent changes, restrict it to panning.
208 var zoomAllowed = this.currentHitIndex_ == 0;
209 this.timeline.setSelectionAndMakeVisible([hit], zoomAllowed);
210 },
211
212 findNext: function() {
213 this.find_(1);
214 },
215
216 findPrevious: function() {
217 this.find_(-1);
218 },
219 };
220
221 /**
39 * TimelineView 222 * TimelineView
40 * @constructor 223 * @constructor
41 * @extends {HTMLDivElement} 224 * @extends {HTMLDivElement}
42 */ 225 */
43 var TimelineView = cr.ui.define('div'); 226 var TimelineView = cr.ui.define('div');
44 227
45 TimelineView.prototype = { 228 TimelineView.prototype = {
46 __proto__: HTMLDivElement.prototype, 229 __proto__: HTMLDivElement.prototype,
47 230
48 decorate: function() { 231 decorate: function() {
49 this.classList.add('timeline-view'); 232 this.classList.add('timeline-view');
50 233
234 // Create individual elements.
235 this.titleEl_ = document.createElement('span');
236 this.titleEl_.textContent = 'Tracing: ';
237
238 this.controlDiv_ = document.createElement('div');
239 this.controlDiv_.className = 'control';
240
241 this.leftControlsEl_ = document.createElement('div');
242 this.rightControlsEl_ = document.createElement('div');
243
244 var spacingEl = document.createElement('div');
245 spacingEl.className = 'spacer';
246
51 this.timelineContainer_ = document.createElement('div'); 247 this.timelineContainer_ = document.createElement('div');
52 this.timelineContainer_.className = 'timeline-container'; 248 this.timelineContainer_.className = 'timeline-container';
53 249
54 var summaryContainer_ = document.createElement('div'); 250 var summaryContainer_ = document.createElement('div');
55 summaryContainer_.className = 'summary-container'; 251 summaryContainer_.className = 'summary-container';
56 252
57 this.summaryEl_ = document.createElement('pre'); 253 this.summaryEl_ = document.createElement('pre');
58 this.summaryEl_.className = 'summary'; 254 this.summaryEl_.className = 'summary';
59 255
256 this.findCtl_ = new TimelineFindControl();
257 this.findCtl_.controller = new TimelineFindController();
258
259 // Connect everything up.
260 this.rightControls.appendChild(this.findCtl_);
261 this.controlDiv_.appendChild(this.titleEl_);
262 this.controlDiv_.appendChild(this.leftControlsEl_);
263 this.controlDiv_.appendChild(spacingEl);
264 this.controlDiv_.appendChild(this.rightControlsEl_);
265 this.appendChild(this.controlDiv_);
266
267 this.appendChild(this.timelineContainer_);
268
60 summaryContainer_.appendChild(this.summaryEl_); 269 summaryContainer_.appendChild(this.summaryEl_);
61 this.appendChild(this.timelineContainer_);
62 this.appendChild(summaryContainer_); 270 this.appendChild(summaryContainer_);
63 271
272 // Bookkeeping.
64 this.onSelectionChangedBoundToThis_ = this.onSelectionChanged_.bind(this); 273 this.onSelectionChangedBoundToThis_ = this.onSelectionChanged_.bind(this);
274 document.addEventListener('keypress', this.onKeypress_.bind(this), true);
275 },
276
277 get leftControls() {
278 return this.leftControlsEl_;
279 },
280
281 get rightControls() {
282 return this.rightControlsEl_;
283 },
284
285 get title() {
286 return this.titleEl_.textContent.substring(
287 this.titleEl_.textContent.length - 2);
288 },
289
290 set title(text) {
291 this.titleEl_.textContent = text + ':';
65 }, 292 },
66 293
67 set traceData(traceData) { 294 set traceData(traceData) {
68 this.model = new tracing.TimelineModel(traceData); 295 this.model = new tracing.TimelineModel(traceData);
69 }, 296 },
70 297
71 get model() { 298 get model() {
72 return this.timelineModel_; 299 return this.timelineModel_;
73 }, 300 },
74 301
75 set model(model) { 302 set model(model) {
76 this.timelineModel_ = model; 303 this.timelineModel_ = model;
77 304
78 // remove old timeline 305 // remove old timeline
79 this.timelineContainer_.textContent = ''; 306 this.timelineContainer_.textContent = '';
80 307
81 // create new timeline if needed 308 // create new timeline if needed
82 if (this.timelineModel_.minTimestamp !== undefined) { 309 if (this.timelineModel_.minTimestamp !== undefined) {
83 if (this.timeline_) 310 if (this.timeline_)
84 this.timeline_.detach(); 311 this.timeline_.detach();
85 this.timeline_ = new tracing.Timeline(); 312 this.timeline_ = new tracing.Timeline();
86 this.timeline_.model = this.timelineModel_; 313 this.timeline_.model = this.timelineModel_;
87 this.timeline_.focusElement = this.parentElement; 314 this.timeline_.focusElement =
315 this.focusElement_ ? this.focusElement_ : this.parentElement;
88 this.timelineContainer_.appendChild(this.timeline_); 316 this.timelineContainer_.appendChild(this.timeline_);
89 this.timeline_.addEventListener('selectionChange', 317 this.timeline_.addEventListener('selectionChange',
90 this.onSelectionChangedBoundToThis_); 318 this.onSelectionChangedBoundToThis_);
319
320 this.findCtl_.controller.timeline = this.timeline_;
91 this.onSelectionChanged_(); 321 this.onSelectionChanged_();
92 } else { 322 } else {
93 this.timeline_ = null; 323 this.timeline_ = undefined;
324 this.findCtl_.controller.timeline = undefined;
94 } 325 }
95 }, 326 },
96 327
97 get timeline() { 328 get timeline() {
98 return this.timeline_; 329 return this.timeline_;
99 }, 330 },
100 331
332 /**
333 * Sets the element whose focus state will determine whether
334 * to respond to keybaord input.
335 */
336 set focusElement(value) {
337 this.focusElement_ = value;
338 if (this.timeline_)
339 this.timeline_.focusElement = value;
340 },
341
342 /**
343 * @return {Element} The element whose focused state determines
344 * whether to respond to keyboard inputs.
345 * Defaults to the parent element.
346 */
347 get focusElement() {
348 if (this.focusElement_)
349 return this.focusElement_;
350 return this.parentElement;
351 },
352
353 /**
354 * @return {boolean} Whether the current timeline is attached to the
355 * document.
356 */
357 get isAttachedToDocument_() {
358 var cur = this;
359 while (cur.parentNode)
360 cur = cur.parentNode;
361 return cur == this.ownerDocument;
362 },
363
364 get listenToKeys_() {
365 if (!this.isAttachedToDocument_)
366 return;
367 if (!this.focusElement_)
368 return true;
369 if (this.focusElement.tabIndex >= 0)
370 return document.activeElement == this.focusElement;
371 return true;
372 },
373
374 onKeypress_: function(e) {
375 if (!this.listenToKeys_)
376 return;
377
378 if (event.keyCode == 47) {
379 this.findCtl_.focus();
380 event.preventDefault();
381 return;
382 }
383 },
384
385 beginFind: function() {
386 if (this.findInProgress_)
387 return;
388 this.findInProgress_ = true;
389 var dlg = TimelineFindControl();
390 dlg.controller = new TimelineFindController();
391 dlg.controller.timeline = this.timeline;
392 dlg.visible = true;
393 dlg.addEventListener('close', function() {
394 this.findInProgress_ = false;
395 }.bind(this));
396 dlg.addEventListener('findNext', function() {
397 });
398 dlg.addEventListener('findPrevious', function() {
399 });
400 },
401
101 onSelectionChanged_: function(e) { 402 onSelectionChanged_: function(e) {
102 var timeline = this.timeline_; 403 var timeline = this.timeline_;
103 var selection = timeline.selection; 404 var selection = timeline.selection;
104 if (!selection.length) { 405 if (!selection.length) {
105 var oldScrollTop = this.timelineContainer_.scrollTop; 406 var oldScrollTop = this.timelineContainer_.scrollTop;
106 this.summaryEl_.textContent = timeline.keyHelp; 407 this.summaryEl_.textContent = timeline.keyHelp;
107 this.timelineContainer_.scrollTop = oldScrollTop; 408 this.timelineContainer_.scrollTop = oldScrollTop;
108 return; 409 return;
109 } 410 }
110 411
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
186 } 487 }
187 488
188 // done 489 // done
189 var oldScrollTop = this.timelineContainer_.scrollTop; 490 var oldScrollTop = this.timelineContainer_.scrollTop;
190 this.summaryEl_.textContent = text; 491 this.summaryEl_.textContent = text;
191 this.timelineContainer_.scrollTop = oldScrollTop; 492 this.timelineContainer_.scrollTop = oldScrollTop;
192 } 493 }
193 }; 494 };
194 495
195 return { 496 return {
497 TimelineFindControl: TimelineFindControl,
498 TimelineFindController: TimelineFindController,
196 TimelineView: TimelineView 499 TimelineView: TimelineView
197 }; 500 };
198 }); 501 });
OLDNEW
« no previous file with comments | « chrome/browser/resources/tracing/timeline_view.css ('k') | chrome/browser/resources/tracing/timeline_view_test.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698