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

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

Issue 8359025: Tons of timeline tweaks (Closed)
Patch Set: Disable eliding due to perf issues 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 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
160 160
161 this.invalidatePending_ = false; 161 this.invalidatePending_ = false;
162 162
163 this.tracks_ = this.ownerDocument.createElement('div'); 163 this.tracks_ = this.ownerDocument.createElement('div');
164 this.tracks_.invalidate = this.invalidate.bind(this); 164 this.tracks_.invalidate = this.invalidate.bind(this);
165 this.appendChild(this.tracks_); 165 this.appendChild(this.tracks_);
166 166
167 this.dragBox_ = this.ownerDocument.createElement('div'); 167 this.dragBox_ = this.ownerDocument.createElement('div');
168 this.dragBox_.className = 'timeline-drag-box'; 168 this.dragBox_.className = 'timeline-drag-box';
169 this.appendChild(this.dragBox_); 169 this.appendChild(this.dragBox_);
170 this.hideDragBox_();
170 171
171 // The following code uses a setInterval to monitor the timeline control 172 // 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 173 // for size changes. This is so that we can keep the canvas' bitmap size
173 // correctly synchronized with its presentation size. 174 // correctly synchronized with its presentation size.
174 // TODO(nduca): detect this in a more efficient way, e.g. iframe hack. 175 // TODO(nduca): detect this in a more efficient way, e.g. iframe hack.
175 this.lastSize_ = this.clientWidth + 'x' + this.clientHeight; 176 this.lastSize_ = this.clientWidth + 'x' + this.clientHeight;
176 this.ownerDocument.defaultView.setInterval(function() { 177 this.checkForResizeInterval_ =
178 this.ownerDocument.defaultView.setInterval(function() {
179 if (!this.isAttachedToDocument_)
180 return;
177 var curSize = this.clientWidth + 'x' + this.clientHeight; 181 var curSize = this.clientWidth + 'x' + this.clientHeight;
178 if (this.clientWidth && curSize != this.lastSize_) { 182 if (this.clientWidth && curSize != this.lastSize_) {
179 this.lastSize_ = curSize; 183 this.lastSize_ = curSize;
180 this.onResize(); 184 this.onResize();
181 } 185 }
182 }.bind(this), 250); 186 }.bind(this), 250);
183 187
184 document.addEventListener('keypress', this.onKeypress_.bind(this)); 188 this.bindEventListener_(document, 'keypress', this.onKeypress_, this);
185 document.addEventListener('keydown', this.onKeydown_.bind(this)); 189 this.bindEventListener_(document, 'keydown', this.onKeydown_, this);
186 document.addEventListener('mousedown', this.onMouseDown_.bind(this)); 190 this.bindEventListener_(document, 'mousedown', this.onMouseDown_, this);
187 document.addEventListener('mousemove', this.onMouseMove_.bind(this)); 191 this.bindEventListener_(document, 'mousemove', this.onMouseMove_, this);
188 document.addEventListener('mouseup', this.onMouseUp_.bind(this)); 192 this.bindEventListener_(document, 'mouseup', this.onMouseUp_, this);
189 document.addEventListener('dblclick', this.onDblClick_.bind(this)); 193 this.bindEventListener_(document, 'dblclick', this.onDblClick_, this);
190 194
191 this.lastMouseViewPos_ = {x: 0, y: 0}; 195 this.lastMouseViewPos_ = {x: 0, y: 0};
192 196
193 this.selection_ = []; 197 this.selection_ = [];
194 }, 198 },
195 199
200 /**
201 * Wraps the standard addEventListener but automatically binds the provided
202 * func to the provided target, tracking the resulting closure. When detach
203 * is called, these listeners will be automatically removed.
204 */
205 bindEventListener_: function(object, event, func, target) {
206 if (!this.boundListeners_)
207 this.boundListeners_ = [];
208 var boundFunc = func.bind(target);
209 this.boundListeners_.push({object: object,
210 event: event,
211 boundFunc: boundFunc});
212 object.addEventListener(event, boundFunc);
213 },
214
215 detach: function() {
216 for (var i = 0; i < this.boundListeners_.length; ++i) {
James Hawkins 2011/11/11 23:37:40 nit: i++
nduca 2011/11/12 01:28:27 Done.
217 var binding = this.boundListeners_[i];
218 binding.object.removeEventListener(binding.event, binding.boundFunc);
219 }
220 this.boundListeners_ = undefined;
221 window.clearInterval(this.checkForResizeInterval_);
222 this.checkForResizeInterval_ = undefined;
223 },
224
196 get model() { 225 get model() {
197 return this.model_; 226 return this.model_;
198 }, 227 },
199 228
200 set model(model) { 229 set model(model) {
201 if (!model) 230 if (!model)
202 throw Error('Model cannot be null'); 231 throw Error('Model cannot be null');
203 if (this.model) { 232 if (this.model) {
204 throw Error('Cannot set model twice.'); 233 throw Error('Cannot set model twice.');
205 } 234 }
206 this.model_ = model; 235 this.model_ = model;
207 236
208 // Create tracks. 237 // Create tracks and measure their heading size.
209 this.tracks_.textContent = '';
210 var threads = model.getAllThreads(); 238 var threads = model.getAllThreads();
211 threads.sort(tracing.TimelineThread.compare); 239 var maxHeadingWidth = 0;
240 var tracks = [];
241 var measuringStick = new tracing.MeasuringStick();
242 var headingEl = document.createElement('div');
243 headingEl.style.position = 'fixed';
244 headingEl.className = 'timeline-slice-track-title';
212 for (var tI = 0; tI < threads.length; tI++) { 245 for (var tI = 0; tI < threads.length; tI++) {
213 var thread = threads[tI]; 246 var thread = threads[tI];
214 var track = new TimelineThreadTrack(); 247 var track = new TimelineThreadTrack();
215 track.thread = thread; 248 track.thread = thread;
216 track.viewport = this.viewport_; 249 track.viewport = this.viewport_;
250 tracks.push(track);
251 headingEl.textContent = track.heading;
252 var w = measuringStick.measure(headingEl).width;
253 // Limit heading width to 300px.
254 if (w > 300)
255 w = 300;
256 if (w > maxHeadingWidth)
257 maxHeadingWidth = w;
258 }
259 var extraHeadingPadding = 4;
260 maxHeadingWidth += maxHeadingWidth + extraHeadingPadding;
261
262 // Attach tracks and set width.
263 this.tracks_.textContent = '';
264 threads.sort(tracing.TimelineThread.compare);
265 for (var tI = 0; tI < tracks.length; tI++) {
266 var track = tracks[tI];
267 track.headingWidth = maxHeadingWidth + 'px';
217 this.tracks_.appendChild(track); 268 this.tracks_.appendChild(track);
218
219 } 269 }
220 270
221 this.needsViewportReset_ = true; 271 if (this.isAttachedToDocument_)
272 this.onResize();
273 else
274 this.needsViewportReset_ = true;
222 }, 275 },
223 276
224 viewportChange_: function() { 277 viewportChange_: function() {
225 this.invalidate(); 278 this.invalidate();
226 }, 279 },
227 280
228 invalidate: function() { 281 invalidate: function() {
229 if (this.invalidatePending_) 282 if (this.invalidatePending_)
230 return; 283 return;
231 this.invalidatePending_ = true; 284 this.invalidatePending_ = true;
232 window.setTimeout(function() { 285 if (this.isAttachedToDocument_)
233 this.invalidatePending_ = false; 286 window.setTimeout(function() {
234 this.redrawAllTracks_(); 287 this.invalidatePending_ = false;
235 }.bind(this), 0); 288 this.redrawAllTracks_();
289 }.bind(this), 0);
290 },
291
292 /**
293 * @return {boolean} Whether the current timeline is attached to the
294 * document.
295 */
296 get isAttachedToDocument_() {
297 var cur = this;
298 while (cur.parentNode)
299 cur = cur.parentNode;
300 return cur == this.ownerDocument;
236 }, 301 },
237 302
238 onResize: function() { 303 onResize: function() {
304 if (!this.isAttachedToDocument_)
305 throw 'Not attached to document!';
239 for (var i = 0; i < this.tracks_.children.length; ++i) { 306 for (var i = 0; i < this.tracks_.children.length; ++i) {
240 var track = this.tracks_.children[i]; 307 var track = this.tracks_.children[i];
241 track.onResize(); 308 track.onResize();
242 } 309 }
310 if (this.invalidatePending_) {
311 this.invalidatePending_ = false;
312 this.redrawAllTracks_();
313 }
243 }, 314 },
244 315
245 redrawAllTracks_: function() { 316 redrawAllTracks_: function() {
246 if (this.needsViewportReset_ && this.clientWidth != 0) { 317 if (this.needsViewportReset_ && this.clientWidth != 0) {
318 if (!this.isAttachedToDocument_)
319 throw 'Not attached to document!';
247 this.needsViewportReset_ = false; 320 this.needsViewportReset_ = false;
248 /* update viewport */ 321 /* update viewport */
249 var rangeTimestamp = this.model_.maxTimestamp - 322 var rangeTimestamp = this.model_.maxTimestamp -
250 this.model_.minTimestamp; 323 this.model_.minTimestamp;
251 var w = this.firstCanvas.width; 324 var w = this.firstCanvas.width;
252 console.log('viewport was reset with w=', w);
253 var scaleX = w / rangeTimestamp; 325 var scaleX = w / rangeTimestamp;
254 var panX = -this.model_.minTimestamp; 326 var panX = -this.model_.minTimestamp;
255 this.viewport_.setPanAndScale(panX, scaleX); 327 this.viewport_.setPanAndScale(panX, scaleX);
256 } 328 }
257 for (var i = 0; i < this.tracks_.children.length; ++i) { 329 for (var i = 0; i < this.tracks_.children.length; ++i) {
258 this.tracks_.children[i].redraw(); 330 this.tracks_.children[i].redraw();
259 } 331 }
260 }, 332 },
261 333
262 updateChildViewports_: function() { 334 updateChildViewports_: function() {
263 for (var cI = 0; cI < this.tracks_.children.length; ++cI) { 335 for (var cI = 0; cI < this.tracks_.children.length; ++cI) {
264 var child = this.tracks_.children[cI]; 336 var child = this.tracks_.children[cI];
265 child.setViewport(this.panX, this.scaleX); 337 child.setViewport(this.panX, this.scaleX);
266 } 338 }
267 }, 339 },
268 340
341 get listenToKeys_() {
342 if (this.parentElement.parentElement.tabIndex >= 0)
343 return document.activeElement == this.parentElement.parentElement;
344 return true;
345 },
346
269 onKeypress_: function(e) { 347 onKeypress_: function(e) {
270 var vp = this.viewport_; 348 var vp = this.viewport_;
271 if (!this.firstCanvas) 349 if (!this.firstCanvas)
272 return; 350 return;
351 if (!this.listenToKeys_)
352 return;
273 var viewWidth = this.firstCanvas.clientWidth; 353 var viewWidth = this.firstCanvas.clientWidth;
274 var curMouseV, curCenterW; 354 var curMouseV, curCenterW;
275 switch (e.keyCode) { 355 switch (e.keyCode) {
276 case 101: // e 356 case 101: // e
277 var vX = this.lastMouseViewPos_.x; 357 var vX = this.lastMouseViewPos_.x;
278 var wX = vp.xViewToWorld(this.lastMouseViewPos_.x); 358 var wX = vp.xViewToWorld(this.lastMouseViewPos_.x);
279 var distFromCenter = vX - (viewWidth / 2); 359 var distFromCenter = vX - (viewWidth / 2);
280 var percFromCenter = distFromCenter / viewWidth; 360 var percFromCenter = distFromCenter / viewWidth;
281 var percFromCenterSq = percFromCenter * percFromCenter; 361 var percFromCenterSq = percFromCenter * percFromCenter;
282 vp.xPanWorldPosToViewPos(wX, 'center', viewWidth); 362 vp.xPanWorldPosToViewPos(wX, 'center', viewWidth);
(...skipping 26 matching lines...) Expand all
309 vp.panX += vp.xViewVectorToWorld(viewWidth * 0.5); 389 vp.panX += vp.xViewVectorToWorld(viewWidth * 0.5);
310 break; 390 break;
311 case 68: // D 391 case 68: // D
312 vp.panX -= vp.xViewVectorToWorld(viewWidth * 0.5); 392 vp.panX -= vp.xViewVectorToWorld(viewWidth * 0.5);
313 break; 393 break;
314 } 394 }
315 }, 395 },
316 396
317 // Not all keys send a keypress. 397 // Not all keys send a keypress.
318 onKeydown_: function(e) { 398 onKeydown_: function(e) {
399 if (!this.listenToKeys_)
400 return;
319 switch (e.keyCode) { 401 switch (e.keyCode) {
320 case 37: // left arrow 402 case 37: // left arrow
321 this.selectPrevious_(e); 403 this.selectPrevious_(e);
322 e.preventDefault(); 404 e.preventDefault();
323 break; 405 break;
324 case 39: // right arrow 406 case 39: // right arrow
325 this.selectNext_(e); 407 this.selectNext_(e);
326 e.preventDefault(); 408 e.preventDefault();
327 break; 409 break;
328 case 9: // TAB 410 case 9: // TAB
329 if (e.shiftKey) 411 if (this.parentElement.parentElement.tabIndex == -1) {
330 this.selectPrevious_(e); 412 if (e.shiftKey)
331 else 413 this.selectPrevious_(e);
332 this.selectNext_(e); 414 else
333 e.preventDefault(); 415 this.selectNext_(e);
416 e.preventDefault();
417 }
334 break; 418 break;
335 } 419 }
336 }, 420 },
337 421
338 /** 422 /**
339 * Zoom in or out on the timeline by the given scale factor. 423 * 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. 424 * @param {integer} scale The scale factor to apply. If <1, zooms out.
341 */ 425 */
342 zoomBy_: function(scale) { 426 zoomBy_: function(scale) {
343 if (!this.firstCanvas) 427 if (!this.firstCanvas)
(...skipping 22 matching lines...) Expand all
366 * @param {boolean} forwardp If true, select one forward (next). 450 * @param {boolean} forwardp If true, select one forward (next).
367 * Else, select previous. 451 * Else, select previous.
368 */ 452 */
369 selectAdjoining_: function(e, forwardp) { 453 selectAdjoining_: function(e, forwardp) {
370 var i, track, slice, adjoining; 454 var i, track, slice, adjoining;
371 var selection = []; 455 var selection = [];
372 // Clear old selection; try and select next. 456 // Clear old selection; try and select next.
373 for (i = 0; i < this.selection_.length; ++i) { 457 for (i = 0; i < this.selection_.length; ++i) {
374 adjoining = undefined; 458 adjoining = undefined;
375 this.selection_[i].slice.selected = false; 459 this.selection_[i].slice.selected = false;
376 var track = this.selection_[i].track; 460 track = this.selection_[i].track;
377 var slice = this.selection_[i].slice; 461 slice = this.selection_[i].slice;
378 if (slice) { 462 if (slice) {
379 if (forwardp) 463 if (forwardp)
380 adjoining = track.pickNext(slice); 464 adjoining = track.pickNext(slice);
381 else 465 else
382 adjoining = track.pickPrevious(slice); 466 adjoining = track.pickPrevious(slice);
383 } 467 }
384 if (adjoining != undefined) 468 if (adjoining != undefined)
385 selection.push({track: track, slice: adjoining}); 469 selection.push({track: track, slice: adjoining});
386 } 470 }
387 // Activate the new selection. 471 // Activate the new selection.
388 this.selection_ = selection; 472 this.selection_ = selection;
389 for (i = 0; i < this.selection_.length; ++i) 473 for (i = 0; i < this.selection_.length; ++i)
390 this.selection_[i].slice.selected = true; 474 this.selection_[i].slice.selected = true;
391 cr.dispatchSimpleEvent(this, 'selectionChange'); 475 cr.dispatchSimpleEvent(this, 'selectionChange');
392 this.invalidate(); // Cause tracks to redraw. 476 this.invalidate(); // Cause tracks to redraw.
393 e.preventDefault(); 477 e.preventDefault();
394 }, 478 },
395 479
396 get keyHelp() { 480 get keyHelp() {
397 return 'Keyboard shortcuts:\n' + 481 var help = 'Keyboard shortcuts:\n' +
398 ' w/s : Zoom in/out (with shift: go faster)\n' + 482 ' w/s : Zoom in/out (with shift: go faster)\n' +
399 ' a/d : Pan left/right\n' + 483 ' a/d : Pan left/right\n' +
400 ' e : Center on mouse\n' + 484 ' e : Center on mouse\n' +
401 ' g/G : Shows grid at the start/end of the selected task\n' + 485 ' 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 486
487 if (this.parentElement.parentElement.tabIndex) {
488 help += ' <- : Select previous event on current timeline\n' +
489 ' -> : Select next event on current timeline\n';
490 } else {
491 help += ' <-,^TAB : Select previous event on current timeline\n' +
492 ' ->, TAB : Select next event on current timeline\n';
493 }
407 494
495 help +=
496 '\n' +
497 'Dbl-click to zoom in; Shift dbl-click to zoom out\n';
498 return help;
408 }, 499 },
409 500
410 get selection() { 501 get selection() {
411 return this.selection_; 502 return this.selection_;
412 }, 503 },
413 504
505 set selection(selection) {
506 // Clear old selection.
507 for (i = 0; i < this.selection_.length; ++i)
James Hawkins 2011/11/11 23:37:40 nit: i++
nduca 2011/11/12 01:28:27 Done.
508 this.selection_[i].slice.selected = false;
509
510 this.selection_ = selection;
511
512 cr.dispatchSimpleEvent(this, 'selectionChange');
513 for (i = 0; i < this.selection_.length; ++i)
James Hawkins 2011/11/11 23:37:40 nit: i++
nduca 2011/11/12 01:28:27 Done.
514 this.selection_[i].slice.selected = true;
515 this.invalidate(); // Cause tracks to redraw.
516 },
517
414 get firstCanvas() { 518 get firstCanvas() {
415 return this.tracks_.firstChild ? 519 return this.tracks_.firstChild ?
416 this.tracks_.firstChild.firstCanvas : undefined; 520 this.tracks_.firstChild.firstCanvas : undefined;
417 }, 521 },
418 522
419 showDragBox_: function() {
420 this.dragBox_.hidden = false;
421 },
422
423 hideDragBox_: function() { 523 hideDragBox_: function() {
424 this.dragBox_.style.left = '-1000px'; 524 this.dragBox_.style.left = '-1000px';
425 this.dragBox_.style.top = '-1000px'; 525 this.dragBox_.style.top = '-1000px';
426 this.dragBox_.style.width = 0; 526 this.dragBox_.style.width = 0;
427 this.dragBox_.style.height = 0; 527 this.dragBox_.style.height = 0;
428 this.dragBox_.hidden = true;
429 },
430
431 get dragBoxVisible_() {
432 return this.dragBox_.hidden == false;
433 }, 528 },
434 529
435 setDragBoxPosition_: function(eDown, eCur) { 530 setDragBoxPosition_: function(eDown, eCur) {
436 var loX = Math.min(eDown.clientX, eCur.clientX); 531 var loX = Math.min(eDown.clientX, eCur.clientX);
437 var hiX = Math.max(eDown.clientX, eCur.clientX); 532 var hiX = Math.max(eDown.clientX, eCur.clientX);
438 var loY = Math.min(eDown.clientY, eCur.clientY); 533 var loY = Math.min(eDown.clientY, eCur.clientY);
439 var hiY = Math.max(eDown.clientY, eCur.clientY); 534 var hiY = Math.max(eDown.clientY, eCur.clientY);
440 535
441 this.dragBox_.style.left = loX + 'px'; 536 this.dragBox_.style.left = loX + 'px';
442 this.dragBox_.style.top = loY + 'px'; 537 this.dragBox_.style.top = loY + 'px';
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
483 var canv = this.firstCanvas; 578 var canv = this.firstCanvas;
484 var pos = { 579 var pos = {
485 x: e.clientX - canv.offsetLeft, 580 x: e.clientX - canv.offsetLeft,
486 y: e.clientY - canv.offsetTop 581 y: e.clientY - canv.offsetTop
487 }; 582 };
488 583
489 var wX = this.viewport_.xViewToWorld(pos.x); 584 var wX = this.viewport_.xViewToWorld(pos.x);
490 585
491 this.dragBeginEvent_ = e; 586 this.dragBeginEvent_ = e;
492 e.preventDefault(); 587 e.preventDefault();
588 if (this.parentElement.parentElement.tabIndex)
589 this.parentElement.parentElement.focus();
493 }, 590 },
494 591
495 onMouseMove_: function(e) { 592 onMouseMove_: function(e) {
496 if (!this.firstCanvas) 593 if (!this.firstCanvas)
497 return; 594 return;
498 var canv = this.firstCanvas; 595 var canv = this.firstCanvas;
499 var pos = { 596 var pos = {
500 x: e.clientX - canv.offsetLeft, 597 x: e.clientX - canv.offsetLeft,
501 y: e.clientY - canv.offsetTop 598 y: e.clientY - canv.offsetTop
502 }; 599 };
503 600
504 // Remember position. Used during keyboard zooming. 601 // Remember position. Used during keyboard zooming.
505 this.lastMouseViewPos_ = pos; 602 this.lastMouseViewPos_ = pos;
506 603
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 604 // Update the drag box
514 if (this.dragBeginEvent_) { 605 if (this.dragBeginEvent_) {
515 this.setDragBoxPosition_(this.dragBeginEvent_, e); 606 this.setDragBoxPosition_(this.dragBeginEvent_, e);
516 } 607 }
517 }, 608 },
518 609
519 onMouseUp_: function(e) { 610 onMouseUp_: function(e) {
520 var i; 611 var i;
521 if (this.dragBeginEvent_) { 612 if (this.dragBeginEvent_) {
522 // Stop the dragging. 613 // Stop the dragging.
523 this.hideDragBox_(); 614 this.hideDragBox_();
524 var eDown = this.dragBeginEvent_; 615 var eDown = this.dragBeginEvent_;
525 this.dragBeginEvent_ = null; 616 this.dragBeginEvent_ = null;
526 617
527 // Figure out extents of the drag. 618 // Figure out extents of the drag.
528 var loX = Math.min(eDown.clientX, e.clientX); 619 var loX = Math.min(eDown.clientX, e.clientX);
529 var hiX = Math.max(eDown.clientX, e.clientX); 620 var hiX = Math.max(eDown.clientX, e.clientX);
530 var loY = Math.min(eDown.clientY, e.clientY); 621 var loY = Math.min(eDown.clientY, e.clientY);
531 var hiY = Math.max(eDown.clientY, e.clientY); 622 var hiY = Math.max(eDown.clientY, e.clientY);
532 623
533 // Convert to worldspace. 624 // Convert to worldspace.
534 var canv = this.firstCanvas; 625 var canv = this.firstCanvas;
535 var loWX = this.viewport_.xViewToWorld(loX - canv.offsetLeft); 626 var loWX = this.viewport_.xViewToWorld(loX - canv.offsetLeft);
536 var hiWX = this.viewport_.xViewToWorld(hiX - canv.offsetLeft); 627 var hiWX = this.viewport_.xViewToWorld(hiX - canv.offsetLeft);
537 628
538 // Clear old selection.
539 for (i = 0; i < this.selection_.length; ++i) {
540 this.selection_[i].slice.selected = false;
541 }
542
543 // Figure out what has been hit. 629 // Figure out what has been hit.
544 var selection = []; 630 var selection = [];
545 function addHit(type, track, slice) { 631 function addHit(type, track, slice) {
546 selection.push({track: track, slice: slice}); 632 selection.push({track: track, slice: slice});
547 } 633 }
548 for (i = 0; i < this.tracks_.children.length; ++i) { 634 for (i = 0; i < this.tracks_.children.length; ++i) {
549 var track = this.tracks_.children[i]; 635 var track = this.tracks_.children[i];
550 636
551 // Only check tracks that insersect the rect. 637 // Only check tracks that insersect the rect.
552 var trackClientRect = track.getBoundingClientRect(); 638 var trackClientRect = track.getBoundingClientRect();
553 var a = Math.max(loY, trackClientRect.top); 639 var a = Math.max(loY, trackClientRect.top);
554 var b = Math.min(hiY, trackClientRect.bottom); 640 var b = Math.min(hiY, trackClientRect.bottom);
555 if (a <= b) { 641 if (a <= b) {
556 track.pickRange(loWX, hiWX, loY, hiY, addHit); 642 track.pickRange(loWX, hiWX, loY, hiY, addHit);
557 } 643 }
558 } 644 }
559 // Activate the new selection. 645 // Activate the new selection.
560 this.selection_ = selection; 646 this.selection = selection;
561 cr.dispatchSimpleEvent(this, 'selectionChange');
562 for (i = 0; i < this.selection_.length; ++i) {
563 this.selection_[i].slice.selected = true;
564 }
565 this.invalidate(); // Cause tracks to redraw.
566 } 647 }
567 }, 648 },
568 649
569 onDblClick_: function(e) { 650 onDblClick_: function(e) {
570 var scale = 4; 651 var scale = 4;
571 if (e.shiftKey) 652 if (e.shiftKey)
572 scale = 1 / scale; 653 scale = 1 / scale;
573 this.zoomBy_(scale); 654 this.zoomBy_(scale);
574 e.preventDefault(); 655 e.preventDefault();
575 }, 656 },
576 }; 657 };
577 658
578 /** 659 /**
579 * The TimelineModel being viewed by the timeline 660 * The TimelineModel being viewed by the timeline
580 * @type {TimelineModel} 661 * @type {TimelineModel}
581 */ 662 */
582 cr.defineProperty(Timeline, 'model', cr.PropertyKind.JS); 663 cr.defineProperty(Timeline, 'model', cr.PropertyKind.JS);
583 664
584 return { 665 return {
585 Timeline: Timeline 666 Timeline: Timeline
586 }; 667 };
587 }); 668 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698