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

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

Issue 8359025: Tons of timeline tweaks (Closed)
Patch Set: nits Created 9 years, 1 month 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) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 /** 5 /**
6 * @fileoverview Interactive visualizaiton of TimelineModel objects 6 * @fileoverview Interactive visualizaiton of TimelineModel objects
7 * based loosely on gantt charts. Each thread in the TimelineModel is given a 7 * based loosely on gantt charts. Each thread in the TimelineModel is given a
8 * set of TimelineTracks, one per subrow in the thread. The Timeline class 8 * set of TimelineTracks, one per subrow in the thread. The Timeline class
9 * acts as a controller, creating the individual tracks, while TimelineTracks 9 * acts as a controller, creating the individual tracks, while TimelineTracks
10 * do actual drawing. 10 * do actual drawing.
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
128 get gridStep() { 128 get gridStep() {
129 return this.gridStep_; 129 return this.gridStep_;
130 }, 130 },
131 131
132 applyTransformToCanavs: function(ctx) { 132 applyTransformToCanavs: function(ctx) {
133 ctx.transform(this.scaleX_, 0, 0, 1, this.panX_ * this.scaleX_, 0); 133 ctx.transform(this.scaleX_, 0, 0, 1, this.panX_ * this.scaleX_, 0);
134 } 134 }
135 }; 135 };
136 136
137 /** 137 /**
138 * Uses an embedded iframe to measure provided elements without forcing layout
139 * on the main document.
140 * @constructor
141 * @extends {Object}
142 */
143 function MeasuringStick()
James Hawkins 2011/11/05 17:51:37 Move this into a separate file.
nduca 2011/11/09 22:52:19 Done.
144 {
James Hawkins 2011/11/05 17:51:37 Opening brace should be on the same line as the me
nduca 2011/11/09 22:52:19 Done.
145 var iframe = document.createElement('iframe');
146 iframe.style.cssText = 'width:100%;height:0;border:0;visibility:hidden';
147 document.body.appendChild(iframe);
148 this._doc = iframe.contentDocument;
149 this._window = iframe.contentWindow;
150 this._doc.body.style.cssText = 'padding:0;margin:0;overflow:hidden';
151
152 var stylesheets = document.querySelectorAll('link[rel=stylesheet]');
153 for (var i = 0; i < stylesheets.length; ++i) {
154 var stylesheet = stylesheets[i];
155 var link = this._doc.createElement('link');
156 link.rel = 'stylesheet';
157 link.href = stylesheet.href;
158 this._doc.head.appendChild(link);
159 }
160 }
161
162 MeasuringStick.prototype = {
163 __proto__: Object.prototype,
164
165 /**
166 * Converts measures like 50px to their size in pixels, if possible.
167 */
168 convertMeasureToPixels_: function(str) {
James Hawkins 2011/11/05 17:51:37 No need for this method. parseInt(str, 10);
nduca 2011/11/09 22:52:19 Done.
169 var g = /(\d+)px/.exec(str);
170 if (g)
171 return parseInt(g[0]);
172 throw 'Unrecognized unit on ' + str;
173 },
174
175 /**
176 * Measures the provided element without forcing layout on the main
177 * document.
178 */
179 measure: function(element)
180 {
181 this._doc.body.appendChild(element);
182 var style = this._window.getComputedStyle(element);
183 var width = this.convertMeasureToPixels_(style.width);
184 var height = this.convertMeasureToPixels_(style.height);
185 this._doc.body.removeChild(element);
186 return { width: width, height: height };
187 }
188 };
189
190 /**
138 * Renders a TimelineModel into a div element, making one 191 * Renders a TimelineModel into a div element, making one
139 * TimelineTrack for each subrow in each thread of the model, managing 192 * TimelineTrack for each subrow in each thread of the model, managing
140 * overall track layout, and handling user interaction with the 193 * overall track layout, and handling user interaction with the
141 * viewport. 194 * viewport.
142 * 195 *
143 * @constructor 196 * @constructor
144 * @extends {HTMLDivElement} 197 * @extends {HTMLDivElement}
145 */ 198 */
146 Timeline = cr.ui.define('div'); 199 Timeline = cr.ui.define('div');
147 200
(...skipping 12 matching lines...) Expand all
160 213
161 this.invalidatePending_ = false; 214 this.invalidatePending_ = false;
162 215
163 this.tracks_ = this.ownerDocument.createElement('div'); 216 this.tracks_ = this.ownerDocument.createElement('div');
164 this.tracks_.invalidate = this.invalidate.bind(this); 217 this.tracks_.invalidate = this.invalidate.bind(this);
165 this.appendChild(this.tracks_); 218 this.appendChild(this.tracks_);
166 219
167 this.dragBox_ = this.ownerDocument.createElement('div'); 220 this.dragBox_ = this.ownerDocument.createElement('div');
168 this.dragBox_.className = 'timeline-drag-box'; 221 this.dragBox_.className = 'timeline-drag-box';
169 this.appendChild(this.dragBox_); 222 this.appendChild(this.dragBox_);
223 this.hideDragBox_();
170 224
171 // The following code uses a setInterval to monitor the timeline control 225 // The following code uses a setInterval to monitor the timeline control
172 // for size changes. This is so that we can keep the canvas' bitmap size 226 // for size changes. This is so that we can keep the canvas' bitmap size
173 // correctly synchronized with its presentation size. 227 // correctly synchronized with its presentation size.
174 // TODO(nduca): detect this in a more efficient way, e.g. iframe hack. 228 // TODO(nduca): detect this in a more efficient way, e.g. iframe hack.
175 this.lastSize_ = this.clientWidth + 'x' + this.clientHeight; 229 this.lastSize_ = this.clientWidth + 'x' + this.clientHeight;
176 this.ownerDocument.defaultView.setInterval(function() { 230 this.checkForResizeInterval_ =
231 this.ownerDocument.defaultView.setInterval(function() {
232 if (!this.isAttachedToDocument_)
233 return;
177 var curSize = this.clientWidth + 'x' + this.clientHeight; 234 var curSize = this.clientWidth + 'x' + this.clientHeight;
178 if (this.clientWidth && curSize != this.lastSize_) { 235 if (this.clientWidth && curSize != this.lastSize_) {
179 this.lastSize_ = curSize; 236 this.lastSize_ = curSize;
180 this.onResize(); 237 this.onResize();
181 } 238 }
182 }.bind(this), 250); 239 }.bind(this), 250);
183 240
184 document.addEventListener('keypress', this.onKeypress_.bind(this)); 241 this.safeAddEventListener(document, 'keypress', this.onKeypress_, this);
185 document.addEventListener('keydown', this.onKeydown_.bind(this)); 242 this.safeAddEventListener(document, 'keydown', this.onKeydown_, this);
186 document.addEventListener('mousedown', this.onMouseDown_.bind(this)); 243 this.safeAddEventListener(document, 'mousedown', this.onMouseDown_, this);
187 document.addEventListener('mousemove', this.onMouseMove_.bind(this)); 244 this.safeAddEventListener(document, 'mousemove', this.onMouseMove_, this);
188 document.addEventListener('mouseup', this.onMouseUp_.bind(this)); 245 this.safeAddEventListener(document, 'mouseup', this.onMouseUp_, this);
189 document.addEventListener('dblclick', this.onDblClick_.bind(this)); 246 this.safeAddEventListener(document, 'dblclick', this.onDblClick_, this);
190 247
191 this.lastMouseViewPos_ = {x: 0, y: 0}; 248 this.lastMouseViewPos_ = {x: 0, y: 0};
192 249
193 this.selection_ = []; 250 this.selection_ = [];
194 }, 251 },
195 252
253 safeAddEventListener: function(object, event, func, target) {
James Hawkins 2011/11/05 17:51:37 Document this method and the params. In the comme
James Hawkins 2011/11/05 17:51:37 This method should likely be private.
nduca 2011/11/09 22:52:19 Done.
nduca 2011/11/09 22:52:19 Done.
254 if (!this.boundListeners_)
255 this.boundListeners_ = [];
256 var boundFunc = func.bind(target);
257 this.boundListeners_.push({object: object,
258 event: event,
259 boundFunc: boundFunc});
260 object.addEventListener(event, boundFunc);
261 },
262
263 detach: function() {
264 for (var i = 0; i < this.boundListeners_.length; ++i) {
265 var binding = this.boundListeners_[i];
266 binding.object.removeEventListener(binding.event, binding.boundFunc);
267 }
268 this.boundListeners_ = undefined;
269 window.clearInterval(this.checkForResizeInterval_);
270 this.checkForResizeInterval_ = undefined;
271 },
272
196 get model() { 273 get model() {
197 return this.model_; 274 return this.model_;
198 }, 275 },
199 276
200 set model(model) { 277 set model(model) {
201 if (!model) 278 if (!model)
202 throw Error('Model cannot be null'); 279 throw Error('Model cannot be null');
203 if (this.model) { 280 if (this.model) {
204 throw Error('Cannot set model twice.'); 281 throw Error('Cannot set model twice.');
205 } 282 }
206 this.model_ = model; 283 this.model_ = model;
207 284
208 // Create tracks. 285 // Create tracks and measure their heading size
James Hawkins 2011/11/05 17:51:37 nit: Period at end of sentence.
nduca 2011/11/09 22:52:19 Done.
209 this.tracks_.textContent = '';
210 var threads = model.getAllThreads(); 286 var threads = model.getAllThreads();
211 threads.sort(tracing.TimelineThread.compare); 287 var maxHeadingWidth = 0;
288 var tracks = [];
289 var measuringStick = new MeasuringStick();
290 var headingEl = document.createElement('div');
291 headingEl.style.position = 'fixed';
292 headingEl.className = 'timeline-slice-track-title';
212 for (var tI = 0; tI < threads.length; tI++) { 293 for (var tI = 0; tI < threads.length; tI++) {
213 var thread = threads[tI]; 294 var thread = threads[tI];
214 var track = new TimelineThreadTrack(); 295 var track = new TimelineThreadTrack();
215 track.thread = thread; 296 track.thread = thread;
216 track.viewport = this.viewport_; 297 track.viewport = this.viewport_;
298 tracks.push(track);
299 headingEl.textContent = track.heading;
300 var w = measuringStick.measure(headingEl).width;
301 // limit heading width to 300px
James Hawkins 2011/11/05 17:51:37 Comment sentence should start with a capital lette
nduca 2011/11/09 22:52:19 Done.
302 if (w > 300)
303 w = 300;
304 if (w > maxHeadingWidth)
305 maxHeadingWidth = w;
306 }
307 maxHeadingWidth += maxHeadingWidth + 4
308
309 // Attach tracks and set width
James Hawkins 2011/11/05 17:51:37 Add period.
nduca 2011/11/09 22:52:19 Done.
310 this.tracks_.textContent = '';
311 threads.sort(tracing.TimelineThread.compare);
312 for (var tI = 0; tI < tracks.length; tI++) {
313 var track = tracks[tI];
314 track.headingWidth = maxHeadingWidthWithUnit + 'px';
217 this.tracks_.appendChild(track); 315 this.tracks_.appendChild(track);
218
219 } 316 }
220 317
221 this.needsViewportReset_ = true; 318 if (this.isAttachedToDocument_)
319 this.onResize();
320 else
321 this.needsViewportReset_ = true;
222 }, 322 },
223 323
224 viewportChange_: function() { 324 viewportChange_: function() {
225 this.invalidate(); 325 this.invalidate();
226 }, 326 },
227 327
228 invalidate: function() { 328 invalidate: function() {
229 if (this.invalidatePending_) 329 if (this.invalidatePending_)
230 return; 330 return;
231 this.invalidatePending_ = true; 331 this.invalidatePending_ = true;
232 window.setTimeout(function() { 332 if (this.isAttachedToDocument_)
James Hawkins 2011/11/05 17:51:37 Braces required for multi-line blocks.
nduca 2011/11/09 22:52:19 Done.
233 this.invalidatePending_ = false; 333 window.setTimeout(function() {
234 this.redrawAllTracks_(); 334 this.invalidatePending_ = false;
235 }.bind(this), 0); 335 this.redrawAllTracks_();
336 }.bind(this), 0);
337 },
338
339 get isAttachedToDocument_() {
James Hawkins 2011/11/05 17:51:37 Document return type.
nduca 2011/11/09 22:52:19 Done.
340 var cur = this;
341 while (cur.parentNode)
342 cur = cur.parentNode;
343 return cur == this.ownerDocument;
236 }, 344 },
237 345
238 onResize: function() { 346 onResize: function() {
347 if (!this.isAttachedToDocument_)
348 throw 'Not attached to document!';
239 for (var i = 0; i < this.tracks_.children.length; ++i) { 349 for (var i = 0; i < this.tracks_.children.length; ++i) {
240 var track = this.tracks_.children[i]; 350 var track = this.tracks_.children[i];
241 track.onResize(); 351 track.onResize();
242 } 352 }
353 if (this.invalidatePending_) {
354 this.invalidatePending_ = false;
355 this.redrawAllTracks_();
356 }
243 }, 357 },
244 358
245 redrawAllTracks_: function() { 359 redrawAllTracks_: function() {
246 if (this.needsViewportReset_ && this.clientWidth != 0) { 360 if (this.needsViewportReset_ && this.clientWidth != 0) {
361 if (!this.isAttachedToDocument_)
362 throw 'Not attached to document!';
247 this.needsViewportReset_ = false; 363 this.needsViewportReset_ = false;
248 /* update viewport */ 364 /* update viewport */
249 var rangeTimestamp = this.model_.maxTimestamp - 365 var rangeTimestamp = this.model_.maxTimestamp -
250 this.model_.minTimestamp; 366 this.model_.minTimestamp;
251 var w = this.firstCanvas.width; 367 var w = this.firstCanvas.width;
252 console.log('viewport was reset with w=', w);
253 var scaleX = w / rangeTimestamp; 368 var scaleX = w / rangeTimestamp;
254 var panX = -this.model_.minTimestamp; 369 var panX = -this.model_.minTimestamp;
255 this.viewport_.setPanAndScale(panX, scaleX); 370 this.viewport_.setPanAndScale(panX, scaleX);
256 } 371 }
257 for (var i = 0; i < this.tracks_.children.length; ++i) { 372 for (var i = 0; i < this.tracks_.children.length; ++i) {
258 this.tracks_.children[i].redraw(); 373 this.tracks_.children[i].redraw();
259 } 374 }
260 }, 375 },
261 376
262 updateChildViewports_: function() { 377 updateChildViewports_: function() {
263 for (var cI = 0; cI < this.tracks_.children.length; ++cI) { 378 for (var cI = 0; cI < this.tracks_.children.length; ++cI) {
264 var child = this.tracks_.children[cI]; 379 var child = this.tracks_.children[cI];
265 child.setViewport(this.panX, this.scaleX); 380 child.setViewport(this.panX, this.scaleX);
266 } 381 }
267 }, 382 },
268 383
384 get listenToKeys_() {
385 if (this.parentElement.parentElement.tabIndex >= 0)
386 return document.activeElement == this.parentElement.parentElement;
387 return true;
388 },
389
269 onKeypress_: function(e) { 390 onKeypress_: function(e) {
270 var vp = this.viewport_; 391 var vp = this.viewport_;
271 if (!this.firstCanvas) 392 if (!this.firstCanvas)
272 return; 393 return;
394 if (!this.listenToKeys_)
395 return;
273 var viewWidth = this.firstCanvas.clientWidth; 396 var viewWidth = this.firstCanvas.clientWidth;
274 var curMouseV, curCenterW; 397 var curMouseV, curCenterW;
275 switch (e.keyCode) { 398 switch (e.keyCode) {
276 case 101: // e 399 case 101: // e
277 var vX = this.lastMouseViewPos_.x; 400 var vX = this.lastMouseViewPos_.x;
278 var wX = vp.xViewToWorld(this.lastMouseViewPos_.x); 401 var wX = vp.xViewToWorld(this.lastMouseViewPos_.x);
279 var distFromCenter = vX - (viewWidth / 2); 402 var distFromCenter = vX - (viewWidth / 2);
280 var percFromCenter = distFromCenter / viewWidth; 403 var percFromCenter = distFromCenter / viewWidth;
281 var percFromCenterSq = percFromCenter * percFromCenter; 404 var percFromCenterSq = percFromCenter * percFromCenter;
282 vp.xPanWorldPosToViewPos(wX, 'center', viewWidth); 405 vp.xPanWorldPosToViewPos(wX, 'center', viewWidth);
(...skipping 26 matching lines...) Expand all
309 vp.panX += vp.xViewVectorToWorld(viewWidth * 0.5); 432 vp.panX += vp.xViewVectorToWorld(viewWidth * 0.5);
310 break; 433 break;
311 case 68: // D 434 case 68: // D
312 vp.panX -= vp.xViewVectorToWorld(viewWidth * 0.5); 435 vp.panX -= vp.xViewVectorToWorld(viewWidth * 0.5);
313 break; 436 break;
314 } 437 }
315 }, 438 },
316 439
317 // Not all keys send a keypress. 440 // Not all keys send a keypress.
318 onKeydown_: function(e) { 441 onKeydown_: function(e) {
442 if (!this.listenToKeys_)
443 return;
319 switch (e.keyCode) { 444 switch (e.keyCode) {
320 case 37: // left arrow 445 case 37: // left arrow
321 this.selectPrevious_(e); 446 this.selectPrevious_(e);
322 e.preventDefault(); 447 e.preventDefault();
323 break; 448 break;
324 case 39: // right arrow 449 case 39: // right arrow
325 this.selectNext_(e); 450 this.selectNext_(e);
326 e.preventDefault(); 451 e.preventDefault();
327 break; 452 break;
328 case 9: // TAB 453 case 9: // TAB
329 if (e.shiftKey) 454 if (this.parentElement.parentElement.tabIndex == -1) {
330 this.selectPrevious_(e); 455 if (e.shiftKey)
331 else 456 this.selectPrevious_(e);
332 this.selectNext_(e); 457 else
333 e.preventDefault(); 458 this.selectNext_(e);
459 e.preventDefault();
460 }
334 break; 461 break;
335 } 462 }
336 }, 463 },
337 464
338 /** 465 /**
339 * Zoom in or out on the timeline by the given scale factor. 466 * Zoom in or out on the timeline by the given scale factor.
340 * @param {integer} scale The scale factor to apply. If <1, zooms out. 467 * @param {integer} scale The scale factor to apply. If <1, zooms out.
341 */ 468 */
342 zoomBy_: function(scale) { 469 zoomBy_: function(scale) {
343 if (!this.firstCanvas) 470 if (!this.firstCanvas)
(...skipping 22 matching lines...) Expand all
366 * @param {boolean} forwardp If true, select one forward (next). 493 * @param {boolean} forwardp If true, select one forward (next).
367 * Else, select previous. 494 * Else, select previous.
368 */ 495 */
369 selectAdjoining_: function(e, forwardp) { 496 selectAdjoining_: function(e, forwardp) {
370 var i, track, slice, adjoining; 497 var i, track, slice, adjoining;
371 var selection = []; 498 var selection = [];
372 // Clear old selection; try and select next. 499 // Clear old selection; try and select next.
373 for (i = 0; i < this.selection_.length; ++i) { 500 for (i = 0; i < this.selection_.length; ++i) {
374 adjoining = undefined; 501 adjoining = undefined;
375 this.selection_[i].slice.selected = false; 502 this.selection_[i].slice.selected = false;
376 var track = this.selection_[i].track; 503 track = this.selection_[i].track;
377 var slice = this.selection_[i].slice; 504 slice = this.selection_[i].slice;
378 if (slice) { 505 if (slice) {
379 if (forwardp) 506 if (forwardp)
380 adjoining = track.pickNext(slice); 507 adjoining = track.pickNext(slice);
381 else 508 else
382 adjoining = track.pickPrevious(slice); 509 adjoining = track.pickPrevious(slice);
383 } 510 }
384 if (adjoining != undefined) 511 if (adjoining != undefined)
385 selection.push({track: track, slice: adjoining}); 512 selection.push({track: track, slice: adjoining});
386 } 513 }
387 // Activate the new selection. 514 // Activate the new selection.
388 this.selection_ = selection; 515 this.selection_ = selection;
389 for (i = 0; i < this.selection_.length; ++i) 516 for (i = 0; i < this.selection_.length; ++i)
390 this.selection_[i].slice.selected = true; 517 this.selection_[i].slice.selected = true;
391 cr.dispatchSimpleEvent(this, 'selectionChange'); 518 cr.dispatchSimpleEvent(this, 'selectionChange');
392 this.invalidate(); // Cause tracks to redraw. 519 this.invalidate(); // Cause tracks to redraw.
393 e.preventDefault(); 520 e.preventDefault();
394 }, 521 },
395 522
396 get keyHelp() { 523 get keyHelp() {
397 return 'Keyboard shortcuts:\n' + 524 var help = 'Keyboard shortcuts:\n' +
398 ' w/s : Zoom in/out (with shift: go faster)\n' + 525 ' w/s : Zoom in/out (with shift: go faster)\n' +
399 ' a/d : Pan left/right\n' + 526 ' a/d : Pan left/right\n' +
400 ' e : Center on mouse\n' + 527 ' e : Center on mouse\n' +
401 ' g/G : Shows grid at the start/end of the selected task\n' + 528 ' g/G : Shows grid at the start/end of the selected task\n';
402 ' <-,^TAB : Select previous event on current timeline\n' +
403 ' ->, TAB : Select next event on current timeline\n' +
404 '\n' +
405 'Dbl-click to zoom in; Shift dbl-click to zoom out\n';
406 529
530 if (this.parentElement.parentElement.tabIndex)
531 help += ' <- : Select previous event on current timeline\n' +
532 ' -> : Select next event on current timeline\n';
533 else
534 help += ' <-,^TAB : Select previous event on current timeline\n' +
535 ' ->, TAB : Select next event on current timeline\n';
407 536
537 help +=
538 '\n' +
539 'Dbl-click to zoom in; Shift dbl-click to zoom out\n';
540 return help;
408 }, 541 },
409 542
410 get selection() { 543 get selection() {
411 return this.selection_; 544 return this.selection_;
412 }, 545 },
413 546
414 get firstCanvas() { 547 get firstCanvas() {
415 return this.tracks_.firstChild ? 548 return this.tracks_.firstChild ?
416 this.tracks_.firstChild.firstCanvas : undefined; 549 this.tracks_.firstChild.firstCanvas : undefined;
417 }, 550 },
418 551
419 showDragBox_: function() {
420 this.dragBox_.hidden = false;
421 },
422
423 hideDragBox_: function() { 552 hideDragBox_: function() {
424 this.dragBox_.style.left = '-1000px'; 553 this.dragBox_.style.left = '-1000px';
425 this.dragBox_.style.top = '-1000px'; 554 this.dragBox_.style.top = '-1000px';
426 this.dragBox_.style.width = 0; 555 this.dragBox_.style.width = 0;
427 this.dragBox_.style.height = 0; 556 this.dragBox_.style.height = 0;
428 this.dragBox_.hidden = true;
429 },
430
431 get dragBoxVisible_() {
432 return this.dragBox_.hidden == false;
433 }, 557 },
434 558
435 setDragBoxPosition_: function(eDown, eCur) { 559 setDragBoxPosition_: function(eDown, eCur) {
436 var loX = Math.min(eDown.clientX, eCur.clientX); 560 var loX = Math.min(eDown.clientX, eCur.clientX);
437 var hiX = Math.max(eDown.clientX, eCur.clientX); 561 var hiX = Math.max(eDown.clientX, eCur.clientX);
438 var loY = Math.min(eDown.clientY, eCur.clientY); 562 var loY = Math.min(eDown.clientY, eCur.clientY);
439 var hiY = Math.max(eDown.clientY, eCur.clientY); 563 var hiY = Math.max(eDown.clientY, eCur.clientY);
440 564
441 this.dragBox_.style.left = loX + 'px'; 565 this.dragBox_.style.left = loX + 'px';
442 this.dragBox_.style.top = loY + 'px'; 566 this.dragBox_.style.top = loY + 'px';
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
483 var canv = this.firstCanvas; 607 var canv = this.firstCanvas;
484 var pos = { 608 var pos = {
485 x: e.clientX - canv.offsetLeft, 609 x: e.clientX - canv.offsetLeft,
486 y: e.clientY - canv.offsetTop 610 y: e.clientY - canv.offsetTop
487 }; 611 };
488 612
489 var wX = this.viewport_.xViewToWorld(pos.x); 613 var wX = this.viewport_.xViewToWorld(pos.x);
490 614
491 this.dragBeginEvent_ = e; 615 this.dragBeginEvent_ = e;
492 e.preventDefault(); 616 e.preventDefault();
617 if (this.parentElement.parentElement.tabIndex)
618 this.parentElement.parentElement.focus();
493 }, 619 },
494 620
495 onMouseMove_: function(e) { 621 onMouseMove_: function(e) {
496 if (!this.firstCanvas) 622 if (!this.firstCanvas)
497 return; 623 return;
498 var canv = this.firstCanvas; 624 var canv = this.firstCanvas;
499 var pos = { 625 var pos = {
500 x: e.clientX - canv.offsetLeft, 626 x: e.clientX - canv.offsetLeft,
501 y: e.clientY - canv.offsetTop 627 y: e.clientY - canv.offsetTop
502 }; 628 };
503 629
504 // Remember position. Used during keyboard zooming. 630 // Remember position. Used during keyboard zooming.
505 this.lastMouseViewPos_ = pos; 631 this.lastMouseViewPos_ = pos;
506 632
507 // Initiate the drag box if needed.
508 if (this.dragBeginEvent_ && !this.dragBoxVisible_) {
509 this.showDragBox_();
510 this.setDragBoxPosition_(e, e);
511 }
512
513 // Update the drag box 633 // Update the drag box
514 if (this.dragBeginEvent_) { 634 if (this.dragBeginEvent_) {
515 this.setDragBoxPosition_(this.dragBeginEvent_, e); 635 this.setDragBoxPosition_(this.dragBeginEvent_, e);
516 } 636 }
517 }, 637 },
518 638
519 onMouseUp_: function(e) { 639 onMouseUp_: function(e) {
520 var i; 640 var i;
521 if (this.dragBeginEvent_) { 641 if (this.dragBeginEvent_) {
522 // Stop the dragging. 642 // Stop the dragging.
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
565 this.invalidate(); // Cause tracks to redraw. 685 this.invalidate(); // Cause tracks to redraw.
566 } 686 }
567 }, 687 },
568 688
569 onDblClick_: function(e) { 689 onDblClick_: function(e) {
570 var scale = 4; 690 var scale = 4;
571 if (e.shiftKey) 691 if (e.shiftKey)
572 scale = 1 / scale; 692 scale = 1 / scale;
573 this.zoomBy_(scale); 693 this.zoomBy_(scale);
574 e.preventDefault(); 694 e.preventDefault();
575 }, 695 }
James Hawkins 2011/11/05 17:51:37 Optional: It's generally safer to leave the traili
nduca 2011/11/09 22:52:19 Done.
576 }; 696 };
577 697
578 /** 698 /**
579 * The TimelineModel being viewed by the timeline 699 * The TimelineModel being viewed by the timeline
580 * @type {TimelineModel} 700 * @type {TimelineModel}
581 */ 701 */
582 cr.defineProperty(Timeline, 'model', cr.PropertyKind.JS); 702 cr.defineProperty(Timeline, 'model', cr.PropertyKind.JS);
583 703
584 return { 704 return {
585 Timeline: Timeline 705 Timeline: Timeline
586 }; 706 };
587 }); 707 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698