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 | 5 |
6 /** | 6 /** |
7 * @fileoverview Renders an array of slices into the provided div, | 7 * @fileoverview Renders an array of slices into the provided div, |
8 * using a child canvas element. Uses a FastRectRenderer to draw only | 8 * using a child canvas element. Uses a FastRectRenderer to draw only |
9 * the visible slices. | 9 * the visible slices. |
10 */ | 10 */ |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
63 this.updateChildTracks_(); | 63 this.updateChildTracks_(); |
64 }, | 64 }, |
65 | 65 |
66 get firstCanvas() { | 66 get firstCanvas() { |
67 if (this.tracks_.length) | 67 if (this.tracks_.length) |
68 return this.tracks_[0].firstCanvas; | 68 return this.tracks_[0].firstCanvas; |
69 return undefined; | 69 return undefined; |
70 }, | 70 }, |
71 | 71 |
72 /** | 72 /** |
73 * Picks a slice, if any, at a given location. | 73 * Adds items intersecting a point to a selection. |
74 * @param {number} wX X location to search at, in worldspace. | 74 * @param {number} wX X location to search at, in worldspace. |
75 * @param {number} wY Y location to search at, in offset space. | 75 * @param {number} wY Y location to search at, in offset space. |
76 * offset space. | 76 * offset space. |
77 * @param {function():*} onHitCallback Callback to call with the slice, | 77 * @param {TimelineSelection} selection Selection to which to add hits. |
78 * if one is found. | |
79 * @return {boolean} true if a slice was found, otherwise false. | 78 * @return {boolean} true if a slice was found, otherwise false. |
80 */ | 79 */ |
81 pick: function(wX, wY, onHitCallback) { | 80 addIntersectingItemsToSelection: function(wX, wY, selection) { |
82 for (var i = 0; i < this.tracks_.length; i++) { | 81 for (var i = 0; i < this.tracks_.length; i++) { |
83 var trackClientRect = this.tracks_[i].getBoundingClientRect(); | 82 var trackClientRect = this.tracks_[i].getBoundingClientRect(); |
84 if (wY >= trackClientRect.top && wY < trackClientRect.bottom) | 83 if (wY >= trackClientRect.top && wY < trackClientRect.bottom) |
85 return this.tracks_[i].pick(wX, onHitCallback); | 84 this.tracks_[i].addIntersectingItemsToSelection(wX, wY, selection); |
86 } | 85 } |
87 return false; | 86 return false; |
88 }, | 87 }, |
89 | 88 |
90 /** | 89 /** |
91 * Finds slices intersecting the given interval. | 90 * Adds items intersecting the given range to a selection. |
92 * @param {number} loWX Lower X bound of the interval to search, in | 91 * @param {number} loWX Lower X bound of the interval to search, in |
93 * worldspace. | 92 * worldspace. |
94 * @param {number} hiWX Upper X bound of the interval to search, in | 93 * @param {number} hiWX Upper X bound of the interval to search, in |
95 * worldspace. | 94 * worldspace. |
96 * @param {number} loY Lower Y bound of the interval to search, in | 95 * @param {number} loY Lower Y bound of the interval to search, in |
97 * offset space. | 96 * offset space. |
98 * @param {number} hiY Upper Y bound of the interval to search, in | 97 * @param {number} hiY Upper Y bound of the interval to search, in |
99 * offset space. | 98 * offset space. |
100 * @param {function():*} onHitCallback Function to call for each slice | 99 * @param {TimelineSelection} selection Selection to which to add hits. |
101 * intersecting the interval. | |
102 */ | 100 */ |
103 pickRange: function(loWX, hiWX, loY, hiY, onHitCallback) { | 101 addIntersectingItemsInRangeToSelection: function( |
| 102 loWX, hiWX, loY, hiY, selection) { |
104 for (var i = 0; i < this.tracks_.length; i++) { | 103 for (var i = 0; i < this.tracks_.length; i++) { |
105 var trackClientRect = this.tracks_[i].getBoundingClientRect(); | 104 var trackClientRect = this.tracks_[i].getBoundingClientRect(); |
106 var a = Math.max(loY, trackClientRect.top); | 105 var a = Math.max(loY, trackClientRect.top); |
107 var b = Math.min(hiY, trackClientRect.bottom); | 106 var b = Math.min(hiY, trackClientRect.bottom); |
108 if (a <= b) | 107 if (a <= b) |
109 this.tracks_[i].pickRange(loWX, hiWX, loY, hiY, onHitCallback); | 108 this.tracks_[i].addIntersectingItemsInRangeToSelection( |
| 109 loWX, hiWX, loY, hiY, selection); |
110 } | 110 } |
111 }, | 111 }, |
112 | 112 |
113 /** | 113 addAllObjectsMatchingFilterToSelection: function(filter, selection) { |
114 * @return {Array} Objects matching the given filter. | 114 for (var i = 0; i < this.tracks_.length; i++) |
115 */ | 115 this.tracks_[i].addAllObjectsMatchingFilterToSelection( |
116 findAllObjectsMatchingFilter: function(filter) { | 116 filter, selection); |
117 var hits = []; | |
118 for (var i = 0; i < this.tracks_.length; i++) { | |
119 var trackHits = this.tracks_[i].findAllObjectsMatchingFilter(filter); | |
120 Array.prototype.push.apply(hits, trackHits); | |
121 } | |
122 return hits; | |
123 } | 117 } |
124 }; | 118 }; |
125 | 119 |
126 function addControlButtonElements(el, canCollapse) { | 120 function addControlButtonElements(el, canCollapse) { |
127 var closeEl = document.createElement('div'); | 121 var closeEl = document.createElement('div'); |
128 closeEl.classList.add('timeline-track-button'); | 122 closeEl.classList.add('timeline-track-button'); |
129 closeEl.classList.add('timeline-track-close-button'); | 123 closeEl.classList.add('timeline-track-close-button'); |
130 closeEl.textContent = String.fromCharCode(215); // × | 124 closeEl.textContent = String.fromCharCode(215); // × |
131 closeEl.addEventListener('click', function() { | 125 closeEl.addEventListener('click', function() { |
132 el.style.display = 'None'; | 126 el.style.display = 'None'; |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
211 }, | 205 }, |
212 | 206 |
213 updateChildTracks_: function() { | 207 updateChildTracks_: function() { |
214 this.detach(); | 208 this.detach(); |
215 this.textContent = ''; | 209 this.textContent = ''; |
216 this.tracks_ = []; | 210 this.tracks_ = []; |
217 if (this.thread_) { | 211 if (this.thread_) { |
218 if (this.thread_.cpuSlices) { | 212 if (this.thread_.cpuSlices) { |
219 var track = this.addTrack_(this.thread_.cpuSlices); | 213 var track = this.addTrack_(this.thread_.cpuSlices); |
220 track.height = '4px'; | 214 track.height = '4px'; |
| 215 track.decorateHit = function(hit) { |
| 216 hit.thread = this.thread_; |
| 217 } |
221 } | 218 } |
222 | 219 |
223 if (this.thread_.asyncSlices.length) { | 220 if (this.thread_.asyncSlices.length) { |
224 var subRows = this.thread_.asyncSlices.subRows; | 221 var subRows = this.thread_.asyncSlices.subRows; |
225 for (var srI = 0; srI < subRows.length; srI++) { | 222 for (var srI = 0; srI < subRows.length; srI++) { |
226 var track = this.addTrack_(subRows[srI]); | 223 var track = this.addTrack_(subRows[srI]); |
| 224 track.decorateHit = function(hit) { |
| 225 // TODO(simonjam): figure out how to associate subSlice hits back |
| 226 // to their parent slice. |
| 227 } |
227 track.asyncStyle = true; | 228 track.asyncStyle = true; |
228 } | 229 } |
229 } | 230 } |
230 | 231 |
231 for (var srI = 0; srI < this.thread_.subRows.length; srI++) { | 232 for (var srI = 0; srI < this.thread_.subRows.length; srI++) { |
232 this.addTrack_(this.thread_.subRows[srI]); | 233 var track = this.addTrack_(this.thread_.subRows[srI]); |
| 234 track.decorateHit = function(hit) { |
| 235 hit.thread = this.thread_; |
| 236 } |
233 } | 237 } |
234 | 238 |
235 if (this.tracks_.length > 0) { | 239 if (this.tracks_.length > 0) { |
236 if (this.thread_.cpuSlices) { | 240 if (this.thread_.cpuSlices) { |
237 this.tracks_[1].heading = this.heading_; | 241 this.tracks_[1].heading = this.heading_; |
238 this.tracks_[1].tooltip = this.tooltip_; | 242 this.tracks_[1].tooltip = this.tooltip_; |
239 } else { | 243 } else { |
240 this.tracks_[0].heading = this.heading_; | 244 this.tracks_[0].heading = this.heading_; |
241 this.tracks_[0].tooltip = this.tooltip_; | 245 this.tracks_[0].tooltip = this.tooltip_; |
242 } | 246 } |
(...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
513 * @const | 517 * @const |
514 */ | 518 */ |
515 SHOULD_ELIDE_TEXT: true, | 519 SHOULD_ELIDE_TEXT: true, |
516 | 520 |
517 decorate: function() { | 521 decorate: function() { |
518 this.classList.add('timeline-slice-track'); | 522 this.classList.add('timeline-slice-track'); |
519 this.elidedTitleCache = new ElidedTitleCache(); | 523 this.elidedTitleCache = new ElidedTitleCache(); |
520 this.asyncStyle_ = false; | 524 this.asyncStyle_ = false; |
521 }, | 525 }, |
522 | 526 |
| 527 /** |
| 528 * Called by all the addToSelection functions on the created selection |
| 529 * hit objects. Override this function on parent classes to add |
| 530 * context-specific information to the hit. |
| 531 */ |
| 532 decorateHit: function(hit) { |
| 533 }, |
| 534 |
523 get asyncStyle() { | 535 get asyncStyle() { |
524 return this.asyncStyle_; | 536 return this.asyncStyle_; |
525 }, | 537 }, |
526 | 538 |
527 set asyncStyle(v) { | 539 set asyncStyle(v) { |
528 this.asyncStyle_ = !!v; | 540 this.asyncStyle_ = !!v; |
529 this.invalidate(); | 541 this.invalidate(); |
530 }, | 542 }, |
531 | 543 |
532 get slices() { | 544 get slices() { |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
661 if (drawnWidth * pixWidth < slice.duration) { | 673 if (drawnWidth * pixWidth < slice.duration) { |
662 var cX = vp.xWorldToView(slice.start + 0.5 * slice.duration); | 674 var cX = vp.xWorldToView(slice.start + 0.5 * slice.duration); |
663 ctx.fillText(drawnTitle, cX, 2.5, drawnWidth); | 675 ctx.fillText(drawnTitle, cX, 2.5, drawnWidth); |
664 } | 676 } |
665 } | 677 } |
666 } | 678 } |
667 } | 679 } |
668 }, | 680 }, |
669 | 681 |
670 /** | 682 /** |
671 * Picks a slice, if any, at a given location. | 683 * Finds slices intersecting the given interval. |
672 * @param {number} wX X location to search at, in worldspace. | 684 * @param {number} wX X location to search at, in worldspace. |
673 * @param {number} wY Y location to search at, in offset space. | 685 * @param {number} wY Y location to search at, in offset space. |
674 * offset space. | 686 * offset space. |
675 * @param {function():*} onHitCallback Callback to call with the slice, | 687 * @param {TimelineSelection} selection Selection to which to add hits. |
676 * if one is found. | |
677 * @return {boolean} true if a slice was found, otherwise false. | 688 * @return {boolean} true if a slice was found, otherwise false. |
678 */ | 689 */ |
679 pick: function(wX, wY, onHitCallback) { | 690 addIntersectingItemsToSelection: function(wX, wY, selection) { |
680 var clientRect = this.getBoundingClientRect(); | 691 var clientRect = this.getBoundingClientRect(); |
681 if (wY < clientRect.top || wY >= clientRect.bottom) | 692 if (wY < clientRect.top || wY >= clientRect.bottom) |
682 return false; | 693 return false; |
683 var x = tracing.findLowIndexInSortedIntervals(this.slices_, | 694 var x = tracing.findLowIndexInSortedIntervals(this.slices_, |
684 function(x) { return x.start; }, | 695 function(x) { return x.start; }, |
685 function(x) { return x.duration; }, | 696 function(x) { return x.duration; }, |
686 wX); | 697 wX); |
687 if (x >= 0 && x < this.slices_.length) { | 698 if (x >= 0 && x < this.slices_.length) { |
688 onHitCallback('slice', this, this.slices_[x]); | 699 var hit = selection.addSlice(this, this.slices_[x]); |
| 700 this.decorateHit(hit); |
689 return true; | 701 return true; |
690 } | 702 } |
691 return false; | 703 return false; |
692 }, | 704 }, |
693 | 705 |
694 /** | 706 /** |
695 * Finds slices intersecting the given interval. | 707 * Adds items intersecting the given range to a selection. |
696 * @param {number} loWX Lower X bound of the interval to search, in | 708 * @param {number} loWX Lower X bound of the interval to search, in |
697 * worldspace. | 709 * worldspace. |
698 * @param {number} hiWX Upper X bound of the interval to search, in | 710 * @param {number} hiWX Upper X bound of the interval to search, in |
699 * worldspace. | 711 * worldspace. |
700 * @param {number} loY Lower Y bound of the interval to search, in | 712 * @param {number} loY Lower Y bound of the interval to search, in |
701 * offset space. | 713 * offset space. |
702 * @param {number} hiY Upper Y bound of the interval to search, in | 714 * @param {number} hiY Upper Y bound of the interval to search, in |
703 * offset space. | 715 * offset space. |
704 * @param {function():*} onHitCallback Function to call for each slice | 716 * @param {TimelineSelection} selection Selection to which to add hits. |
705 * intersecting the interval. | |
706 */ | 717 */ |
707 pickRange: function(loWX, hiWX, loY, hiY, onHitCallback) { | 718 addIntersectingItemsInRangeToSelection: function( |
| 719 loWX, hiWX, loY, hiY, selection) { |
708 var clientRect = this.getBoundingClientRect(); | 720 var clientRect = this.getBoundingClientRect(); |
709 var a = Math.max(loY, clientRect.top); | 721 var a = Math.max(loY, clientRect.top); |
710 var b = Math.min(hiY, clientRect.bottom); | 722 var b = Math.min(hiY, clientRect.bottom); |
711 if (a > b) | 723 if (a > b) |
712 return; | 724 return; |
713 | 725 |
714 var that = this; | 726 var that = this; |
715 function onPickHit(slice) { | 727 function onPickHit(slice) { |
716 onHitCallback('slice', that, slice); | 728 var hit = selection.addSlice(that, slice); |
| 729 that.decorateHit(hit); |
717 } | 730 } |
718 tracing.iterateOverIntersectingIntervals(this.slices_, | 731 tracing.iterateOverIntersectingIntervals(this.slices_, |
719 function(x) { return x.start; }, | 732 function(x) { return x.start; }, |
720 function(x) { return x.duration; }, | 733 function(x) { return x.duration; }, |
721 loWX, hiWX, | 734 loWX, hiWX, |
722 onPickHit); | 735 onPickHit); |
723 }, | 736 }, |
724 | 737 |
725 /** | 738 /** |
726 * Find the index for the given slice. | 739 * Find the index for the given slice. |
727 * @return {index} Index of the given slice, or undefined. | 740 * @return {index} Index of the given slice, or undefined. |
728 * @private | 741 * @private |
729 */ | 742 */ |
730 indexOfSlice_: function(slice) { | 743 indexOfSlice_: function(slice) { |
731 var index = tracing.findLowIndexInSortedArray(this.slices_, | 744 var index = tracing.findLowIndexInSortedArray(this.slices_, |
732 function(x) { return x.start; }, | 745 function(x) { return x.start; }, |
733 slice.start); | 746 slice.start); |
734 while (index < this.slices_.length && | 747 while (index < this.slices_.length && |
735 slice.start == this.slices_[index].start && | 748 slice.start == this.slices_[index].start && |
736 slice.colorId != this.slices_[index].colorId) { | 749 slice.colorId != this.slices_[index].colorId) { |
737 index++; | 750 index++; |
738 } | 751 } |
739 return index < this.slices_.length ? index : undefined; | 752 return index < this.slices_.length ? index : undefined; |
740 }, | 753 }, |
741 | 754 |
742 /** | 755 /** |
743 * Return the next slice, if any, after the given slice. | 756 * Add the item to the left or right of the provided hit, if any, to the |
744 * @param {slice} The previous slice. | 757 * selection. |
745 * @return {slice} The next slice, or undefined. | 758 * @param {slice} The current slice. |
| 759 * @param {Number} offset Number of slices away from the hit to look. |
| 760 * @param {TimelineSelection} selection The selection to add a hit to, |
| 761 * if found. |
| 762 * @return {boolean} Whether a hit was found. |
746 * @private | 763 * @private |
747 */ | 764 */ |
748 pickNext: function(slice) { | 765 addItemNearToProvidedHitToSelection: function(hit, offset, selection) { |
749 var index = this.indexOfSlice_(slice); | 766 if (!hit.slice) |
750 if (index != undefined) { | 767 return false; |
751 if (index < this.slices_.length - 1) | 768 |
752 index++; | 769 var index = this.indexOfSlice_(hit.slice); |
753 else | 770 if (index === undefined) |
754 index = undefined; | 771 return false; |
755 } | 772 |
756 return index != undefined ? this.slices_[index] : undefined; | 773 var newIndex = index + offset; |
| 774 if (newIndex < 0 || newIndex >= this.slices_.length) |
| 775 return false; |
| 776 |
| 777 var hit = selection.addSlice(this, this.slices_[newIndex]); |
| 778 this.decorateHit(hit); |
| 779 return true; |
757 }, | 780 }, |
758 | 781 |
759 /** | 782 addAllObjectsMatchingFilterToSelection: function(filter, selection) { |
760 * Return the previous slice, if any, before the given slice. | 783 for (var i = 0; i < this.slices_.length; ++i) { |
761 * @param {slice} A slice. | 784 if (filter.matchSlice(this.slices_[i])) { |
762 * @return {slice} The previous slice, or undefined. | 785 var hit = selection.addSlice(this, this.slices_[i]); |
763 */ | 786 this.decorateHit(hit); |
764 pickPrevious: function(slice) { | 787 } |
765 var index = this.indexOfSlice_(slice); | 788 } |
766 if (index == 0) | |
767 return undefined; | |
768 else if ((index != undefined) && (index > 0)) | |
769 index--; | |
770 return index != undefined ? this.slices_[index] : undefined; | |
771 }, | |
772 | |
773 findAllObjectsMatchingFilter: function(filter) { | |
774 var hits = []; | |
775 for (var i = 0; i < this.slices_.length; ++i) | |
776 if (filter.matchSlice(this.slices_[i])) | |
777 hits.push({track: this, | |
778 slice: this.slices_[i]}); | |
779 return hits; | |
780 } | 789 } |
781 }; | 790 }; |
782 | 791 |
783 /** | 792 /** |
784 * A track that displays the viewport size and scale. | 793 * A track that displays the viewport size and scale. |
785 * @constructor | 794 * @constructor |
786 * @extends {CanvasBasedTrack} | 795 * @extends {CanvasBasedTrack} |
787 */ | 796 */ |
788 | 797 |
789 var TimelineViewportTrack = cr.ui.define(CanvasBasedTrack); | 798 var TimelineViewportTrack = cr.ui.define(CanvasBasedTrack); |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
889 var xView = Math.floor(curXView + minorMarkDistancePx * i); | 898 var xView = Math.floor(curXView + minorMarkDistancePx * i); |
890 ctx.moveTo(xView, canvasH - minorTickH); | 899 ctx.moveTo(xView, canvasH - minorTickH); |
891 ctx.lineTo(xView, canvasH); | 900 ctx.lineTo(xView, canvasH); |
892 } | 901 } |
893 | 902 |
894 ctx.stroke(); | 903 ctx.stroke(); |
895 } | 904 } |
896 }, | 905 }, |
897 | 906 |
898 /** | 907 /** |
899 * Picks a slice, if any, at a given location. | 908 * Adds items intersecting a point to a selection. |
900 * @param {number} wX X location to search at, in worldspace. | 909 * @param {number} wX X location to search at, in worldspace. |
901 * @param {number} wY Y location to search at, in offset space. | 910 * @param {number} wY Y location to search at, in offset space. |
902 * offset space. | 911 * offset space. |
903 * @param {function():*} onHitCallback Callback to call with the slice, | 912 * @param {TimelineSelection} selection Selection to which to add hits. |
904 * if one is found. | |
905 * @return {boolean} true if a slice was found, otherwise false. | 913 * @return {boolean} true if a slice was found, otherwise false. |
906 */ | 914 */ |
907 pick: function(wX, wY, onHitCallback) { | 915 addIntersectingItemsToSelection: function(wX, wY, selection) { |
908 // Does nothing. There's nothing interesting to pick on the viewport | 916 // Does nothing. There's nothing interesting to pick on the viewport |
909 // track. | 917 // track. |
910 }, | 918 }, |
911 | 919 |
912 /** | 920 /** |
913 * Finds slices intersecting the given interval. | 921 * Adds items intersecting the given range to a selection. |
914 * @param {number} loWX Lower X bound of the interval to search, in | 922 * @param {number} loWX Lower X bound of the interval to search, in |
915 * worldspace. | 923 * worldspace. |
916 * @param {number} hiWX Upper X bound of the interval to search, in | 924 * @param {number} hiWX Upper X bound of the interval to search, in |
917 * worldspace. | 925 * worldspace. |
918 * @param {number} loY Lower Y bound of the interval to search, in | 926 * @param {number} loY Lower Y bound of the interval to search, in |
919 * offset space. | 927 * offset space. |
920 * @param {number} hiY Upper Y bound of the interval to search, in | 928 * @param {number} hiY Upper Y bound of the interval to search, in |
921 * offset space. | 929 * offset space. |
922 * @param {function():*} onHitCallback Function to call for each slice | 930 * @param {TimelineSelection} selection Selection to which to add hits. |
923 * intersecting the interval. | |
924 */ | 931 */ |
925 pickRange: function(loWX, hiWX, loY, hiY, onHitCallback) { | 932 addIntersectingItemsInRangeToSelection: function( |
| 933 loWX, hiWX, loY, hiY, selection) { |
926 // Does nothing. There's nothing interesting to pick on the viewport | 934 // Does nothing. There's nothing interesting to pick on the viewport |
927 // track. | 935 // track. |
928 }, | 936 }, |
929 | 937 |
930 findAllObjectsMatchingFilter: function(filter) { | 938 addAllObjectsMatchingFilterToSelection: function(filter, selection) { |
931 return []; | |
932 } | 939 } |
933 | 940 |
934 }; | 941 }; |
935 | 942 |
936 /** | 943 /** |
937 * A track that displays a TimelineCounter object. | 944 * A track that displays a TimelineCounter object. |
938 * @constructor | 945 * @constructor |
939 * @extends {CanvasBasedTrack} | 946 * @extends {CanvasBasedTrack} |
940 */ | 947 */ |
941 | 948 |
942 var TimelineCounterTrack = cr.ui.define(CanvasBasedTrack); | 949 var TimelineCounterTrack = cr.ui.define(CanvasBasedTrack); |
943 | 950 |
944 TimelineCounterTrack.prototype = { | 951 TimelineCounterTrack.prototype = { |
945 | 952 |
946 __proto__: CanvasBasedTrack.prototype, | 953 __proto__: CanvasBasedTrack.prototype, |
947 | 954 |
948 decorate: function() { | 955 decorate: function() { |
949 this.classList.add('timeline-counter-track'); | 956 this.classList.add('timeline-counter-track'); |
950 addControlButtonElements(this, false); | 957 addControlButtonElements(this, false); |
| 958 this.selectedSamples_ = {}; |
| 959 }, |
| 960 |
| 961 /** |
| 962 * Called by all the addToSelection functions on the created selection |
| 963 * hit objects. Override this function on parent classes to add |
| 964 * context-specific information to the hit. |
| 965 */ |
| 966 decorateHit: function(hit) { |
951 }, | 967 }, |
952 | 968 |
953 get counter() { | 969 get counter() { |
954 return this.counter_; | 970 return this.counter_; |
955 }, | 971 }, |
956 | 972 |
957 set counter(counter) { | 973 set counter(counter) { |
958 this.counter_ = counter; | 974 this.counter_ = counter; |
959 this.invalidate(); | 975 this.invalidate(); |
960 }, | 976 }, |
961 | 977 |
| 978 /** |
| 979 * @return {Object} A sparce, mutable map from sample index to bool. Samples |
| 980 * indices the map that are true are drawn as selected. Callers that mutate |
| 981 * the map must manually call invalidate on the track to trigger a redraw. |
| 982 */ |
| 983 get selectedSamples() { |
| 984 return this.selectedSamples_; |
| 985 }, |
| 986 |
962 redraw: function() { | 987 redraw: function() { |
963 var ctr = this.counter_; | 988 var ctr = this.counter_; |
964 var ctx = this.ctx_; | 989 var ctx = this.ctx_; |
965 var canvasW = this.canvas_.width; | 990 var canvasW = this.canvas_.width; |
966 var canvasH = this.canvas_.height; | 991 var canvasH = this.canvas_.height; |
967 | 992 |
968 ctx.clearRect(0, 0, canvasW, canvasH); | 993 ctx.clearRect(0, 0, canvasW, canvasH); |
969 | 994 |
970 // Culling parametrs. | 995 // Culling parametrs. |
971 var vp = this.viewport_; | 996 var vp = this.viewport_; |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1039 } | 1064 } |
1040 ctx.lineTo(x, yLastView); | 1065 ctx.lineTo(x, yLastView); |
1041 ctx.lineTo(x, yView); | 1066 ctx.lineTo(x, yView); |
1042 iLast = i; | 1067 iLast = i; |
1043 xLast = x; | 1068 xLast = x; |
1044 yLastView = yView; | 1069 yLastView = yView; |
1045 } | 1070 } |
1046 ctx.closePath(); | 1071 ctx.closePath(); |
1047 ctx.fill(); | 1072 ctx.fill(); |
1048 } | 1073 } |
| 1074 ctx.fillStyle = 'rgba(255, 0, 0, 1)'; |
| 1075 for (var i in this.selectedSamples_) { |
| 1076 if (!this.selectedSamples_[i]) |
| 1077 continue; |
| 1078 |
| 1079 var x = ctr.timestamps[i]; |
| 1080 for (var seriesIndex = ctr.numSeries - 1; |
| 1081 seriesIndex >= 0; seriesIndex--) { |
| 1082 var y = ctr.totals[i * numSeries + seriesIndex]; |
| 1083 var yView = canvasH - (yScale * y); |
| 1084 ctx.fillRect(x - pixWidth, yView - 1, 3 * pixWidth, 3); |
| 1085 } |
| 1086 } |
1049 ctx.restore(); | 1087 ctx.restore(); |
1050 }, | 1088 }, |
1051 | 1089 |
1052 /** | 1090 /** |
1053 * Picks a slice, if any, at a given location. | 1091 * Adds items intersecting a point to a selection. |
1054 * @param {number} wX X location to search at, in worldspace. | 1092 * @param {number} wX X location to search at, in worldspace. |
1055 * @param {number} wY Y location to search at, in offset space. | 1093 * @param {number} wY Y location to search at, in offset space. |
1056 * offset space. | 1094 * offset space. |
1057 * @param {function():*} onHitCallback Callback to call with the slice, | 1095 * @param {TimelineSelection} selection Selection to which to add hits. |
1058 * if one is found. | |
1059 * @return {boolean} true if a slice was found, otherwise false. | 1096 * @return {boolean} true if a slice was found, otherwise false. |
1060 */ | 1097 */ |
1061 pick: function(wX, wY, onHitCallback) { | 1098 addIntersectingItemsToSelection: function(wX, wY, selection) { |
| 1099 var clientRect = this.getBoundingClientRect(); |
| 1100 if (wY < clientRect.top || wY >= clientRect.bottom) |
| 1101 return false; |
| 1102 var ctr = this.counter_; |
| 1103 if (wX < this.counter_.timestamps[0]) |
| 1104 return false; |
| 1105 var i = tracing.findLowIndexInSortedArray(ctr.timestamps, |
| 1106 function(x) { return x; }, |
| 1107 wX); |
| 1108 if (i < 0 || i >= ctr.timestamps.length) |
| 1109 return false; |
| 1110 |
| 1111 // Sample i is going to either be exactly at wX or slightly above it, |
| 1112 // E.g. asking for 7.5 in [7,8] gives i=1. So bump i back by 1 if needed. |
| 1113 if (i > 0 && wX > this.counter_.timestamps[i - 1]) |
| 1114 i--; |
| 1115 |
| 1116 // Some preliminaries. |
| 1117 var canvasH = this.getBoundingClientRect().height; |
| 1118 var yScale = canvasH / ctr.maxTotal; |
| 1119 |
| 1120 /* |
| 1121 // Figure out which sample we hit |
| 1122 var seriesIndexHit; |
| 1123 for (var seriesIndex = 0; seriesIndex < ctr.numSeries; seriesIndex++) { |
| 1124 var y = ctr.totals[i * ctr.numSeries + seriesIndex]; |
| 1125 var yView = canvasH - (yScale * y) + clientRect.top; |
| 1126 if (wY >= yView) { |
| 1127 seriesIndexHit = seriesIndex; |
| 1128 break; |
| 1129 } |
| 1130 } |
| 1131 if (seriesIndexHit === undefined) |
| 1132 return false; |
| 1133 */ |
| 1134 var hit = selection.addCounterSample(this, this.counter, i); |
| 1135 this.decorateHit(hit); |
| 1136 return true; |
1062 }, | 1137 }, |
1063 | 1138 |
1064 /** | 1139 /** |
1065 * Finds slices intersecting the given interval. | 1140 * Adds items intersecting the given range to a selection. |
1066 * @param {number} loWX Lower X bound of the interval to search, in | 1141 * @param {number} loWX Lower X bound of the interval to search, in |
1067 * worldspace. | 1142 * worldspace. |
1068 * @param {number} hiWX Upper X bound of the interval to search, in | 1143 * @param {number} hiWX Upper X bound of the interval to search, in |
1069 * worldspace. | 1144 * worldspace. |
1070 * @param {number} loY Lower Y bound of the interval to search, in | 1145 * @param {number} loY Lower Y bound of the interval to search, in |
1071 * offset space. | 1146 * offset space. |
1072 * @param {number} hiY Upper Y bound of the interval to search, in | 1147 * @param {number} hiY Upper Y bound of the interval to search, in |
1073 * offset space. | 1148 * offset space. |
1074 * @param {function():*} onHitCallback Function to call for each slice | 1149 * @param {TimelineSelection} selection Selection to which to add hits. |
1075 * intersecting the interval. | |
1076 */ | 1150 */ |
1077 pickRange: function(loWX, hiWX, loY, hiY, onHitCallback) { | 1151 addIntersectingItemsInRangeToSelection: function( |
| 1152 loWX, hiWX, loY, hiY, selection) { |
| 1153 |
| 1154 var clientRect = this.getBoundingClientRect(); |
| 1155 var a = Math.max(loY, clientRect.top); |
| 1156 var b = Math.min(hiY, clientRect.bottom); |
| 1157 if (a > b) |
| 1158 return; |
| 1159 |
| 1160 var ctr = this.counter_; |
| 1161 |
| 1162 var iLo = tracing.findLowIndexInSortedArray(ctr.timestamps, |
| 1163 function(x) { return x; }, |
| 1164 loWX); |
| 1165 var iHi = tracing.findLowIndexInSortedArray(ctr.timestamps, |
| 1166 function(x) { return x; }, |
| 1167 hiWX); |
| 1168 |
| 1169 // Sample i is going to either be exactly at wX or slightly above it, |
| 1170 // E.g. asking for 7.5 in [7,8] gives i=1. So bump i back by 1 if needed. |
| 1171 if (iLo > 0 && loWX > ctr.timestamps[iLo - 1]) |
| 1172 iLo--; |
| 1173 if (iHi > 0 && hiWX > ctr.timestamps[iHi - 1]) |
| 1174 iHi--; |
| 1175 |
| 1176 // Iterate over every sample intersecting.. |
| 1177 for (var i = iLo; i <= iHi; i++) { |
| 1178 if (i >= ctr.timestamps.length) |
| 1179 continue; |
| 1180 |
| 1181 // TODO(nduca): Pick the seriesIndexHit based on the loY - hiY values. |
| 1182 var hit = selection.addCounterSample(this, this.counter, i); |
| 1183 this.decorateHit(hit); |
| 1184 } |
1078 }, | 1185 }, |
1079 | 1186 |
1080 findAllObjectsMatchingFilter: function(filter) { | 1187 addAllObjectsMatchingFilterToSelection: function(filter, selection) { |
1081 return []; | |
1082 } | 1188 } |
1083 | 1189 |
1084 }; | 1190 }; |
1085 | 1191 |
1086 return { | 1192 return { |
1087 TimelineCounterTrack: TimelineCounterTrack, | 1193 TimelineCounterTrack: TimelineCounterTrack, |
1088 TimelineSliceTrack: TimelineSliceTrack, | 1194 TimelineSliceTrack: TimelineSliceTrack, |
1089 TimelineThreadTrack: TimelineThreadTrack, | 1195 TimelineThreadTrack: TimelineThreadTrack, |
1090 TimelineViewportTrack: TimelineViewportTrack, | 1196 TimelineViewportTrack: TimelineViewportTrack, |
1091 TimelineCpuTrack: TimelineCpuTrack | 1197 TimelineCpuTrack: TimelineCpuTrack |
1092 }; | 1198 }; |
1093 }); | 1199 }); |
OLD | NEW |