| OLD | NEW |
| 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 Interactive visualizaiton of TimelineModel objects | 8 * @fileoverview Interactive visualizaiton of TimelineModel objects |
| 9 * based loosely on gantt charts. Each thread in the TimelineModel is given a | 9 * based loosely on gantt charts. Each thread in the TimelineModel is given a |
| 10 * set of TimelineTracks, one per subrow in the thread. The Timeline class | 10 * set of TimelineTracks, one per subrow in the thread. The Timeline class |
| (...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 225 | 225 |
| 226 get gridStep() { | 226 get gridStep() { |
| 227 return this.gridStep_; | 227 return this.gridStep_; |
| 228 }, | 228 }, |
| 229 | 229 |
| 230 applyTransformToCanavs: function(ctx) { | 230 applyTransformToCanavs: function(ctx) { |
| 231 ctx.transform(this.scaleX_, 0, 0, 1, this.panX_ * this.scaleX_, 0); | 231 ctx.transform(this.scaleX_, 0, 0, 1, this.panX_ * this.scaleX_, 0); |
| 232 } | 232 } |
| 233 }; | 233 }; |
| 234 | 234 |
| 235 function TimelineSelectionSliceHit(track, slice) { |
| 236 this.track = track; |
| 237 this.slice = slice; |
| 238 } |
| 239 TimelineSelectionSliceHit.prototype = { |
| 240 get selected() { |
| 241 return this.slice.selected; |
| 242 }, |
| 243 set selected(v) { |
| 244 this.slice.selected = v; |
| 245 } |
| 246 }; |
| 247 |
| 248 function TimelineSelectionCounterSampleHit(track, counter, sampleIndex) { |
| 249 this.track = track; |
| 250 this.counter = counter; |
| 251 this.sampleIndex = sampleIndex; |
| 252 } |
| 253 TimelineSelectionCounterSampleHit.prototype = { |
| 254 get selected() { |
| 255 return this.track.selectedSamples[this.sampleIndex] == true; |
| 256 }, |
| 257 set selected(v) { |
| 258 if (v) |
| 259 this.track.selectedSamples[this.sampleIndex] = true; |
| 260 else |
| 261 this.track.selectedSamples[this.sampleIndex] = false; |
| 262 this.track.invalidate(); |
| 263 } |
| 264 }; |
| 265 |
| 266 |
| 267 /** |
| 268 * Represents a selection within a Timeline and its associated set of tracks. |
| 269 * @constructor |
| 270 */ |
| 271 function TimelineSelection() { |
| 272 this.range_dirty_ = true; |
| 273 this.range_ = {}; |
| 274 this.length_ = 0; |
| 275 } |
| 276 TimelineSelection.prototype = { |
| 277 __proto__: Object.prototype, |
| 278 |
| 279 get range() { |
| 280 if (this.range_dirty_) { |
| 281 var wmin = Infinity; |
| 282 var wmax = -wmin; |
| 283 for (var i = 0; i < this.length_; i++) { |
| 284 var hit = this[i]; |
| 285 if (hit.slice) { |
| 286 wmin = Math.min(wmin, hit.slice.start); |
| 287 wmax = Math.max(wmax, hit.slice.end); |
| 288 } |
| 289 } |
| 290 this.range_ = { |
| 291 min: wmin, |
| 292 max: wmax |
| 293 }; |
| 294 this.range_dirty_ = false; |
| 295 } |
| 296 return this.range_; |
| 297 }, |
| 298 |
| 299 get duration() { |
| 300 return this.range.max - this.range.min; |
| 301 }, |
| 302 |
| 303 get length() { |
| 304 return this.length_; |
| 305 }, |
| 306 |
| 307 clear: function() { |
| 308 for (var i = 0; i < this.length_; ++i) |
| 309 delete this[i]; |
| 310 this.length_ = 0; |
| 311 this.range_dirty_ = true; |
| 312 }, |
| 313 |
| 314 push_: function(hit) { |
| 315 this[this.length_++] = hit; |
| 316 this.range_dirty_ = true; |
| 317 return hit; |
| 318 }, |
| 319 |
| 320 addSlice: function(track, slice) { |
| 321 return this.push_(new TimelineSelectionSliceHit(track, slice)); |
| 322 }, |
| 323 |
| 324 addCounterSample: function(track, counter, sampleIndex) { |
| 325 return this.push_( |
| 326 new TimelineSelectionCounterSampleHit( |
| 327 track, counter, sampleIndex)); |
| 328 }, |
| 329 |
| 330 subSelection: function(index, count) { |
| 331 count = count || 1; |
| 332 |
| 333 var selection = new TimelineSelection(); |
| 334 selection.range_dirty_ = true; |
| 335 if (index < 0 || index + count > this.length_) |
| 336 throw 'Index out of bounds'; |
| 337 |
| 338 for (var i = index; i < index + count; i++) |
| 339 selection.push_(this[i]); |
| 340 |
| 341 return selection; |
| 342 }, |
| 343 |
| 344 getCounterSampleHits: function() { |
| 345 var selection = new TimelineSelection(); |
| 346 for (var i = 0; i < this.length_; i++) |
| 347 if (this[i] instanceof TimelineSelectionCounterSampleHit) |
| 348 selection.push_(this[i]); |
| 349 return selection; |
| 350 }, |
| 351 |
| 352 getSliceHits: function() { |
| 353 var selection = new TimelineSelection(); |
| 354 for (var i = 0; i < this.length_; i++) |
| 355 if (this[i] instanceof TimelineSelectionSliceHit) |
| 356 selection.push_(this[i]); |
| 357 return selection; |
| 358 }, |
| 359 |
| 360 map: function(fn) { |
| 361 for (var i = 0; i < this.length_; i++) |
| 362 fn(this[i]); |
| 363 }, |
| 364 |
| 365 /** |
| 366 * Helper for selection previous or next. |
| 367 * @param {boolean} forwardp If true, select one forward (next). |
| 368 * Else, select previous. |
| 369 * @return {boolean} true if current selection changed. |
| 370 */ |
| 371 getShiftedSelection: function(offset) { |
| 372 var newSelection = new TimelineSelection(); |
| 373 for (var i = 0; i < this.length_; i++) { |
| 374 var hit = this[i]; |
| 375 hit.track.addItemNearToProvidedHitToSelection( |
| 376 hit, offset, newSelection); |
| 377 } |
| 378 |
| 379 if (newSelection.length == 0) |
| 380 return undefined; |
| 381 return newSelection; |
| 382 }, |
| 383 }; |
| 384 |
| 235 /** | 385 /** |
| 236 * Renders a TimelineModel into a div element, making one | 386 * Renders a TimelineModel into a div element, making one |
| 237 * TimelineTrack for each subrow in each thread of the model, managing | 387 * TimelineTrack for each subrow in each thread of the model, managing |
| 238 * overall track layout, and handling user interaction with the | 388 * overall track layout, and handling user interaction with the |
| 239 * viewport. | 389 * viewport. |
| 240 * | 390 * |
| 241 * @constructor | 391 * @constructor |
| 242 * @extends {HTMLDivElement} | 392 * @extends {HTMLDivElement} |
| 243 */ | 393 */ |
| 244 var Timeline = cr.ui.define('div'); | 394 var Timeline = cr.ui.define('div'); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 263 | 413 |
| 264 this.bindEventListener_(document, 'keypress', this.onKeypress_, this); | 414 this.bindEventListener_(document, 'keypress', this.onKeypress_, this); |
| 265 this.bindEventListener_(document, 'keydown', this.onKeydown_, this); | 415 this.bindEventListener_(document, 'keydown', this.onKeydown_, this); |
| 266 this.bindEventListener_(document, 'mousedown', this.onMouseDown_, this); | 416 this.bindEventListener_(document, 'mousedown', this.onMouseDown_, this); |
| 267 this.bindEventListener_(document, 'mousemove', this.onMouseMove_, this); | 417 this.bindEventListener_(document, 'mousemove', this.onMouseMove_, this); |
| 268 this.bindEventListener_(document, 'mouseup', this.onMouseUp_, this); | 418 this.bindEventListener_(document, 'mouseup', this.onMouseUp_, this); |
| 269 this.bindEventListener_(document, 'dblclick', this.onDblClick_, this); | 419 this.bindEventListener_(document, 'dblclick', this.onDblClick_, this); |
| 270 | 420 |
| 271 this.lastMouseViewPos_ = {x: 0, y: 0}; | 421 this.lastMouseViewPos_ = {x: 0, y: 0}; |
| 272 | 422 |
| 273 this.selection_ = []; | 423 this.selection_ = new TimelineSelection(); |
| 274 }, | 424 }, |
| 275 | 425 |
| 276 /** | 426 /** |
| 277 * Wraps the standard addEventListener but automatically binds the provided | 427 * Wraps the standard addEventListener but automatically binds the provided |
| 278 * func to the provided target, tracking the resulting closure. When detach | 428 * func to the provided target, tracking the resulting closure. When detach |
| 279 * is called, these listeners will be automatically removed. | 429 * is called, these listeners will be automatically removed. |
| 280 */ | 430 */ |
| 281 bindEventListener_: function(object, event, func, target) { | 431 bindEventListener_: function(object, event, func, target) { |
| 282 if (!this.boundListeners_) | 432 if (!this.boundListeners_) |
| 283 this.boundListeners_ = []; | 433 this.boundListeners_ = []; |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 423 // Set up a reasonable viewport. | 573 // Set up a reasonable viewport. |
| 424 this.viewport_.setWhenPossible(function() { | 574 this.viewport_.setWhenPossible(function() { |
| 425 var w = this.firstCanvas.width; | 575 var w = this.firstCanvas.width; |
| 426 this.viewport_.xSetWorldRange(this.model_.minTimestamp, | 576 this.viewport_.xSetWorldRange(this.model_.minTimestamp, |
| 427 this.model_.maxTimestamp, | 577 this.model_.maxTimestamp, |
| 428 w); | 578 w); |
| 429 }.bind(this)); | 579 }.bind(this)); |
| 430 }, | 580 }, |
| 431 | 581 |
| 432 /** | 582 /** |
| 583 * @param {TimelineFilter} filter The filter to use for finding matches. |
| 584 * @param {TimelineSelection} selection The selection to add matches to. |
| 433 * @return {Array} An array of objects that match the provided | 585 * @return {Array} An array of objects that match the provided |
| 434 * TimelineFilter. | 586 * TimelineFilter. |
| 435 */ | 587 */ |
| 436 findAllObjectsMatchingFilter: function(filter) { | 588 addAllObjectsMatchingFilterToSelection: function(filter, selection) { |
| 437 var hits = []; | 589 for (var i = 0; i < this.tracks_.children.length; ++i) |
| 438 for (var i = 0; i < this.tracks_.children.length; ++i) { | 590 this.tracks_.children[i].addAllObjectsMatchingFilterToSelection( |
| 439 var trackHits = | 591 filter, selection); |
| 440 this.tracks_.children[i].findAllObjectsMatchingFilter(filter); | |
| 441 Array.prototype.push.apply(hits, trackHits); | |
| 442 } | |
| 443 return hits; | |
| 444 }, | 592 }, |
| 445 | 593 |
| 446 /** | 594 /** |
| 447 * @return {Element} The element whose focused state determines | 595 * @return {Element} The element whose focused state determines |
| 448 * whether to respond to keyboard inputs. | 596 * whether to respond to keyboard inputs. |
| 449 * Defaults to the parent element. | 597 * Defaults to the parent element. |
| 450 */ | 598 */ |
| 451 get focusElement() { | 599 get focusElement() { |
| 452 if (this.focusElement_) | 600 if (this.focusElement_) |
| 453 return this.focusElement_; | 601 return this.focusElement_; |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 519 case 68: // D | 667 case 68: // D |
| 520 vp.panX -= vp.xViewVectorToWorld(viewWidth * 0.5); | 668 vp.panX -= vp.xViewVectorToWorld(viewWidth * 0.5); |
| 521 break; | 669 break; |
| 522 } | 670 } |
| 523 }, | 671 }, |
| 524 | 672 |
| 525 // Not all keys send a keypress. | 673 // Not all keys send a keypress. |
| 526 onKeydown_: function(e) { | 674 onKeydown_: function(e) { |
| 527 if (!this.listenToKeys_) | 675 if (!this.listenToKeys_) |
| 528 return; | 676 return; |
| 677 var sel; |
| 529 switch (e.keyCode) { | 678 switch (e.keyCode) { |
| 530 case 37: // left arrow | 679 case 37: // left arrow |
| 531 this.selectPrevious_(e); | 680 sel = this.selection.getShiftedSelection(-1); |
| 681 if (sel) { |
| 682 this.setSelectionAndMakeVisible(sel); |
| 683 e.preventDefault(); |
| 684 } |
| 532 break; | 685 break; |
| 533 case 39: // right arrow | 686 case 39: // right arrow |
| 534 this.selectNext_(e); | 687 sel = this.selection.getShiftedSelection(1); |
| 688 if (sel) { |
| 689 this.setSelectionAndMakeVisible(sel); |
| 690 e.preventDefault(); |
| 691 } |
| 535 break; | 692 break; |
| 536 case 9: // TAB | 693 case 9: // TAB |
| 537 if (this.focusElement.tabIndex == -1) { | 694 if (this.focusElement.tabIndex == -1) { |
| 538 if (e.shiftKey) | 695 if (e.shiftKey) |
| 539 this.selectPrevious_(e); | 696 this.selectPrevious_(e); |
| 540 else | 697 else |
| 541 this.selectNext_(e); | 698 this.selectNext_(e); |
| 542 e.preventDefault(); | 699 e.preventDefault(); |
| 543 } | 700 } |
| 544 break; | 701 break; |
| 545 } | 702 } |
| 546 }, | 703 }, |
| 547 | 704 |
| 548 /** | 705 /** |
| 549 * Zoom in or out on the timeline by the given scale factor. | 706 * Zoom in or out on the timeline by the given scale factor. |
| 550 * @param {integer} scale The scale factor to apply. If <1, zooms out. | 707 * @param {integer} scale The scale factor to apply. If <1, zooms out. |
| 551 */ | 708 */ |
| 552 zoomBy_: function(scale) { | 709 zoomBy_: function(scale) { |
| 553 if (!this.firstCanvas) | 710 if (!this.firstCanvas) |
| 554 return; | 711 return; |
| 555 var vp = this.viewport_; | 712 var vp = this.viewport_; |
| 556 var viewWidth = this.firstCanvas.clientWidth; | 713 var viewWidth = this.firstCanvas.clientWidth; |
| 557 var curMouseV = this.lastMouseViewPos_.x; | 714 var curMouseV = this.lastMouseViewPos_.x; |
| 558 var curCenterW = vp.xViewToWorld(curMouseV); | 715 var curCenterW = vp.xViewToWorld(curMouseV); |
| 559 vp.scaleX = vp.scaleX * scale; | 716 vp.scaleX = vp.scaleX * scale; |
| 560 vp.xPanWorldPosToViewPos(curCenterW, curMouseV, viewWidth); | 717 vp.xPanWorldPosToViewPos(curCenterW, curMouseV, viewWidth); |
| 561 }, | 718 }, |
| 562 | 719 |
| 563 /** Select the next slice on the timeline. Applies to each track. */ | |
| 564 selectNext_: function(e) { | |
| 565 if (this.selectAdjoining_(true)) | |
| 566 e.preventDefault(); | |
| 567 }, | |
| 568 | |
| 569 /** Select the previous slice on the timeline. Applies to each track. */ | |
| 570 selectPrevious_: function(e) { | |
| 571 if (this.selectAdjoining_(false)) | |
| 572 e.preventDefault(); | |
| 573 }, | |
| 574 | |
| 575 /** | |
| 576 * Helper for selection previous or next. | |
| 577 * @param {boolean} forwardp If true, select one forward (next). | |
| 578 * Else, select previous. | |
| 579 * @return {boolean} true if current selection changed. | |
| 580 */ | |
| 581 selectAdjoining_: function(forwardp) { | |
| 582 var i, track, slice, adjoining; | |
| 583 var selection = []; | |
| 584 var minTime = Number.MAX_VALUE; | |
| 585 var maxTime = -Number.MAX_VALUE; | |
| 586 // Try and select next. | |
| 587 for (i = 0; i < this.selection_.length; i++) { | |
| 588 adjoining = undefined; | |
| 589 track = this.selection_[i].track; | |
| 590 slice = this.selection_[i].slice; | |
| 591 if (slice) { | |
| 592 if (forwardp) | |
| 593 adjoining = track.pickNext(slice); | |
| 594 else | |
| 595 adjoining = track.pickPrevious(slice); | |
| 596 } | |
| 597 if (adjoining != undefined) { | |
| 598 selection.push({track: track, slice: adjoining}); | |
| 599 if (slice.start < minTime) | |
| 600 minTime = slice.start; | |
| 601 if (slice.start + slice.duration > maxTime) | |
| 602 maxTime = slice.start + slice.duration; | |
| 603 } | |
| 604 } | |
| 605 if (selection.length == 0) { | |
| 606 // Nothing adjoining was found; leave the current selection. | |
| 607 return false; | |
| 608 } | |
| 609 this.selection = selection; | |
| 610 | |
| 611 // Potentially move the viewport to keep the new selection in view. | |
| 612 this.viewport_.xPanWorldRangeIntoView(minTime, maxTime, | |
| 613 this.firstCanvas.width); | |
| 614 return true; | |
| 615 }, | |
| 616 | |
| 617 get keyHelp() { | 720 get keyHelp() { |
| 618 var help = 'Keyboard shortcuts:\n' + | 721 var help = 'Keyboard shortcuts:\n' + |
| 619 ' w/s : Zoom in/out (with shift: go faster)\n' + | 722 ' w/s : Zoom in/out (with shift: go faster)\n' + |
| 620 ' a/d : Pan left/right\n' + | 723 ' a/d : Pan left/right\n' + |
| 621 ' e : Center on mouse\n' + | 724 ' e : Center on mouse\n' + |
| 622 ' g/G : Shows grid at the start/end of the selected task\n'; | 725 ' g/G : Shows grid at the start/end of the selected task\n'; |
| 623 | 726 |
| 624 if (this.focusElement.tabIndex) { | 727 if (this.focusElement.tabIndex) { |
| 625 help += ' <- : Select previous event on current timeline\n' + | 728 help += ' <- : Select previous event on current timeline\n' + |
| 626 ' -> : Select next event on current timeline\n'; | 729 ' -> : Select next event on current timeline\n'; |
| 627 } else { | 730 } else { |
| 628 help += ' <-,^TAB : Select previous event on current timeline\n' + | 731 help += ' <-,^TAB : Select previous event on current timeline\n' + |
| 629 ' ->, TAB : Select next event on current timeline\n'; | 732 ' ->, TAB : Select next event on current timeline\n'; |
| 630 } | 733 } |
| 631 help += | 734 help += |
| 632 '\n' + | 735 '\n' + |
| 633 'Dbl-click to zoom in; Shift dbl-click to zoom out\n'; | 736 'Dbl-click to zoom in; Shift dbl-click to zoom out\n'; |
| 634 return help; | 737 return help; |
| 635 }, | 738 }, |
| 636 | 739 |
| 637 get selection() { | 740 get selection() { |
| 638 return this.selection_; | 741 return this.selection_; |
| 639 }, | 742 }, |
| 640 | 743 |
| 641 set selection(selection) { | 744 set selection(selection) { |
| 745 if (!(selection instanceof TimelineSelection)) |
| 746 throw 'Expected TimelineSelection'; |
| 747 |
| 642 // Clear old selection. | 748 // Clear old selection. |
| 643 var i; | 749 var i; |
| 644 for (i = 0; i < this.selection_.length; i++) | 750 for (i = 0; i < this.selection_.length; i++) |
| 645 this.selection_[i].slice.selected = false; | 751 this.selection_[i].selected = false; |
| 646 | 752 |
| 647 this.selection_ = selection; | 753 this.selection_ = selection; |
| 648 | 754 |
| 649 cr.dispatchSimpleEvent(this, 'selectionChange'); | 755 cr.dispatchSimpleEvent(this, 'selectionChange'); |
| 650 for (i = 0; i < this.selection_.length; i++) | 756 for (i = 0; i < this.selection_.length; i++) |
| 651 this.selection_[i].slice.selected = true; | 757 this.selection_[i].selected = true; |
| 652 this.viewport_.dispatchChangeEvent(); // Triggers a redraw. | 758 this.viewport_.dispatchChangeEvent(); // Triggers a redraw. |
| 653 }, | 759 }, |
| 654 | 760 |
| 655 getSelectionRange: function() { | |
| 656 var wmin = Infinity; | |
| 657 var wmax = -wmin; | |
| 658 for (var i = 0; i < this.selection_.length; i++) { | |
| 659 var hit = this.selection_[i]; | |
| 660 if (hit.slice) { | |
| 661 wmin = Math.min(wmin, hit.slice.start); | |
| 662 wmax = Math.max(wmax, hit.slice.end); | |
| 663 } | |
| 664 } | |
| 665 return { | |
| 666 min: wmin, | |
| 667 max: wmax | |
| 668 }; | |
| 669 }, | |
| 670 | |
| 671 setSelectionAndMakeVisible: function(selection, zoomAllowed) { | 761 setSelectionAndMakeVisible: function(selection, zoomAllowed) { |
| 762 if (!(selection instanceof TimelineSelection)) |
| 763 throw 'Expected TimelineSelection'; |
| 672 this.selection = selection; | 764 this.selection = selection; |
| 673 var range = this.getSelectionRange(); | 765 var range = this.selection.range; |
| 674 var size = this.viewport_.xWorldVectorToView(range.max - range.min); | 766 var size = this.viewport_.xWorldVectorToView(range.max - range.min); |
| 675 if (zoomAllowed && size < 50) { | 767 if (zoomAllowed && size < 50) { |
| 676 var worldCenter = range.min + (range.max - range.min) * 0.5; | 768 var worldCenter = range.min + (range.max - range.min) * 0.5; |
| 677 var worldRange = (range.max - range.min) * 5; | 769 var worldRange = (range.max - range.min) * 5; |
| 678 this.viewport_.xSetWorldRange(worldCenter - worldRange * 0.5, | 770 this.viewport_.xSetWorldRange(worldCenter - worldRange * 0.5, |
| 679 worldCenter + worldRange * 0.5, | 771 worldCenter + worldRange * 0.5, |
| 680 this.firstCanvas.width); | 772 this.firstCanvas.width); |
| 681 return; | 773 return; |
| 682 } | 774 } |
| 683 | 775 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 717 | 809 |
| 718 var e = new cr.Event('selectionChanging'); | 810 var e = new cr.Event('selectionChanging'); |
| 719 e.loWX = loWX; | 811 e.loWX = loWX; |
| 720 e.hiWX = hiWX; | 812 e.hiWX = hiWX; |
| 721 this.dispatchEvent(e); | 813 this.dispatchEvent(e); |
| 722 }, | 814 }, |
| 723 | 815 |
| 724 onGridToggle_: function(left) { | 816 onGridToggle_: function(left) { |
| 725 var tb; | 817 var tb; |
| 726 if (left) | 818 if (left) |
| 727 tb = Math.min.apply(Math, this.selection_.map( | 819 tb = this.selection_.range.min; |
| 728 function(x) { return x.slice.start; })); | |
| 729 else | 820 else |
| 730 tb = Math.max.apply(Math, this.selection_.map( | 821 tb = this.selection_.range.max; |
| 731 function(x) { return x.slice.end; })); | |
| 732 | 822 |
| 733 // Shift the timebase left until its just left of minTimestamp. | 823 // Shift the timebase left until its just left of minTimestamp. |
| 734 var numInterfvalsSinceStart = Math.ceil((tb - this.model_.minTimestamp) / | 824 var numInterfvalsSinceStart = Math.ceil((tb - this.model_.minTimestamp) / |
| 735 this.viewport_.gridStep_); | 825 this.viewport_.gridStep_); |
| 736 this.viewport_.gridTimebase = tb - | 826 this.viewport_.gridTimebase = tb - |
| 737 (numInterfvalsSinceStart + 1) * this.viewport_.gridStep_; | 827 (numInterfvalsSinceStart + 1) * this.viewport_.gridStep_; |
| 738 this.viewport_.gridEnabled = true; | 828 this.viewport_.gridEnabled = true; |
| 739 }, | 829 }, |
| 740 | 830 |
| 741 onMouseDown_: function(e) { | 831 onMouseDown_: function(e) { |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 794 var hiX = Math.max(eDown.clientX, e.clientX); | 884 var hiX = Math.max(eDown.clientX, e.clientX); |
| 795 var loY = Math.min(eDown.clientY, e.clientY); | 885 var loY = Math.min(eDown.clientY, e.clientY); |
| 796 var hiY = Math.max(eDown.clientY, e.clientY); | 886 var hiY = Math.max(eDown.clientY, e.clientY); |
| 797 | 887 |
| 798 // Convert to worldspace. | 888 // Convert to worldspace. |
| 799 var canv = this.firstCanvas; | 889 var canv = this.firstCanvas; |
| 800 var loWX = this.viewport_.xViewToWorld(loX - canv.offsetLeft); | 890 var loWX = this.viewport_.xViewToWorld(loX - canv.offsetLeft); |
| 801 var hiWX = this.viewport_.xViewToWorld(hiX - canv.offsetLeft); | 891 var hiWX = this.viewport_.xViewToWorld(hiX - canv.offsetLeft); |
| 802 | 892 |
| 803 // Figure out what has been hit. | 893 // Figure out what has been hit. |
| 804 (function() { | 894 var selection = new TimelineSelection(); |
| 805 var selection = []; | 895 for (i = 0; i < this.tracks_.children.length; i++) { |
| 806 function addHit(type, track, slice) { | 896 var track = this.tracks_.children[i]; |
| 807 selection.push({track: track, slice: slice}); | 897 |
| 898 // Only check tracks that insersect the rect. |
| 899 var trackClientRect = track.getBoundingClientRect(); |
| 900 var a = Math.max(loY, trackClientRect.top); |
| 901 var b = Math.min(hiY, trackClientRect.bottom); |
| 902 if (a <= b) { |
| 903 track.addIntersectingItemsInRangeToSelection( |
| 904 loWX, hiWX, loY, hiY, selection); |
| 808 } | 905 } |
| 809 for (i = 0; i < this.tracks_.children.length; i++) { | 906 } |
| 810 var track = this.tracks_.children[i]; | 907 // Activate the new selection. |
| 811 | 908 this.selection = selection; |
| 812 // Only check tracks that insersect the rect. | |
| 813 var trackClientRect = track.getBoundingClientRect(); | |
| 814 var a = Math.max(loY, trackClientRect.top); | |
| 815 var b = Math.min(hiY, trackClientRect.bottom); | |
| 816 if (a <= b) { | |
| 817 track.pickRange(loWX, hiWX, loY, hiY, addHit); | |
| 818 } | |
| 819 } | |
| 820 // Activate the new selection. | |
| 821 this.selection = selection; | |
| 822 }).call(this); | |
| 823 } | 909 } |
| 824 }, | 910 }, |
| 825 | 911 |
| 826 onDblClick_: function(e) { | 912 onDblClick_: function(e) { |
| 827 var canv = this.firstCanvas; | 913 var canv = this.firstCanvas; |
| 828 if (e.x < canv.offsetLeft) | 914 if (e.x < canv.offsetLeft) |
| 829 return; | 915 return; |
| 830 | 916 |
| 831 var scale = 4; | 917 var scale = 4; |
| 832 if (e.shiftKey) | 918 if (e.shiftKey) |
| 833 scale = 1 / scale; | 919 scale = 1 / scale; |
| 834 this.zoomBy_(scale); | 920 this.zoomBy_(scale); |
| 835 e.preventDefault(); | 921 e.preventDefault(); |
| 836 } | 922 } |
| 837 }; | 923 }; |
| 838 | 924 |
| 839 /** | 925 /** |
| 840 * The TimelineModel being viewed by the timeline | 926 * The TimelineModel being viewed by the timeline |
| 841 * @type {TimelineModel} | 927 * @type {TimelineModel} |
| 842 */ | 928 */ |
| 843 cr.defineProperty(Timeline, 'model', cr.PropertyKind.JS); | 929 cr.defineProperty(Timeline, 'model', cr.PropertyKind.JS); |
| 844 | 930 |
| 845 return { | 931 return { |
| 846 Timeline: Timeline, | 932 Timeline: Timeline, |
| 933 TimelineSelectionSliceHit: TimelineSelectionSliceHit, |
| 934 TimelineSelectionCounterSampleHit: TimelineSelectionCounterSampleHit, |
| 935 TimelineSelection: TimelineSelection, |
| 847 TimelineViewport: TimelineViewport | 936 TimelineViewport: TimelineViewport |
| 848 }; | 937 }; |
| 849 }); | 938 }); |
| OLD | NEW |