OLD | NEW |
1 /** | 1 /** |
2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
61 this._canvas.addEventListener("mousemove", this._onMouseMove.bind(this), fal
se); | 61 this._canvas.addEventListener("mousemove", this._onMouseMove.bind(this), fal
se); |
62 this._canvas.addEventListener("mousewheel", this._onMouseWheel.bind(this), f
alse); | 62 this._canvas.addEventListener("mousewheel", this._onMouseWheel.bind(this), f
alse); |
63 this._canvas.addEventListener("click", this._onClick.bind(this), false); | 63 this._canvas.addEventListener("click", this._onClick.bind(this), false); |
64 WebInspector.installDragHandle(this._canvas, this._startCanvasDragging.bind(
this), this._canvasDragging.bind(this), this._endCanvasDragging.bind(this), "mov
e", null); | 64 WebInspector.installDragHandle(this._canvas, this._startCanvasDragging.bind(
this), this._canvasDragging.bind(this), this._endCanvasDragging.bind(this), "mov
e", null); |
65 | 65 |
66 this._vScrollElement = this.element.createChild("div", "flame-chart-v-scroll
"); | 66 this._vScrollElement = this.element.createChild("div", "flame-chart-v-scroll
"); |
67 this._vScrollContent = this._vScrollElement.createChild("div"); | 67 this._vScrollContent = this._vScrollElement.createChild("div"); |
68 this._vScrollElement.addEventListener("scroll", this.scheduleUpdate.bind(thi
s), false); | 68 this._vScrollElement.addEventListener("scroll", this.scheduleUpdate.bind(thi
s), false); |
69 | 69 |
70 this._entryInfo = this.element.createChild("div", "profile-entry-info"); | 70 this._entryInfo = this.element.createChild("div", "profile-entry-info"); |
| 71 this._markerHighlighElement = this.element.createChild("div", "flame-chart-m
arker-highlight-element"); |
71 this._highlightElement = this.element.createChild("div", "flame-chart-highli
ght-element"); | 72 this._highlightElement = this.element.createChild("div", "flame-chart-highli
ght-element"); |
72 this._selectedElement = this.element.createChild("div", "flame-chart-selecte
d-element"); | 73 this._selectedElement = this.element.createChild("div", "flame-chart-selecte
d-element"); |
73 | 74 |
74 this._dataProvider = dataProvider; | 75 this._dataProvider = dataProvider; |
75 | 76 |
76 this._windowLeft = 0.0; | 77 this._windowLeft = 0.0; |
77 this._windowRight = 1.0; | 78 this._windowRight = 1.0; |
78 this._windowWidth = 1.0; | 79 this._windowWidth = 1.0; |
79 this._timeWindowLeft = 0; | 80 this._timeWindowLeft = 0; |
80 this._timeWindowRight = Infinity; | 81 this._timeWindowRight = Infinity; |
81 this._barHeight = dataProvider.barHeight(); | 82 this._barHeight = dataProvider.barHeight(); |
82 this._barHeightDelta = this._isTopDown ? -this._barHeight : this._barHeight; | 83 this._barHeightDelta = this._isTopDown ? -this._barHeight : this._barHeight; |
83 this._minWidth = 1; | 84 this._minWidth = 1; |
84 this._paddingLeft = this._dataProvider.paddingLeft(); | 85 this._paddingLeft = this._dataProvider.paddingLeft(); |
85 this._markerPadding = 2; | 86 this._markerPadding = 2; |
86 this._markerRadius = this._barHeight / 2 - this._markerPadding; | 87 this._markerRadius = this._barHeight / 2 - this._markerPadding; |
| 88 this._highlightedMarkerIndex = -1; |
87 this._highlightedEntryIndex = -1; | 89 this._highlightedEntryIndex = -1; |
88 this._selectedEntryIndex = -1; | 90 this._selectedEntryIndex = -1; |
89 this._textWidth = {}; | 91 this._textWidth = {}; |
90 } | 92 } |
91 | 93 |
92 WebInspector.FlameChart.DividersBarHeight = 20; | 94 WebInspector.FlameChart.DividersBarHeight = 20; |
93 | 95 |
94 /** | 96 /** |
95 * @interface | 97 * @interface |
96 */ | 98 */ |
97 WebInspector.FlameChartDataProvider = function() | 99 WebInspector.FlameChartDataProvider = function() |
98 { | 100 { |
99 } | 101 } |
100 | 102 |
101 /** @typedef {!{ | 103 /** |
102 entryLevels: (!Array.<number>|!Uint8Array), | 104 * @constructor |
103 entryTotalTimes: (!Array.<number>|!Float32Array), | 105 * @param {!Array.<number>|!Uint8Array} entryLevels |
104 entryStartTimes: (!Array.<number>|!Float64Array) | 106 * @param {!Array.<number>|!Float32Array} entryTotalTimes |
105 }} | 107 * @param {!Array.<number>|!Float64Array} entryStartTimes |
106 */ | 108 */ |
107 WebInspector.FlameChart.TimelineData; | 109 WebInspector.FlameChart.TimelineData = function(entryLevels, entryTotalTimes, en
tryStartTimes) |
| 110 { |
| 111 this.entryLevels = entryLevels; |
| 112 this.entryTotalTimes = entryTotalTimes; |
| 113 this.entryStartTimes = entryStartTimes; |
| 114 /** @type {!Array.<number>} */ |
| 115 this.markerTimestamps = []; |
| 116 } |
108 | 117 |
109 WebInspector.FlameChartDataProvider.prototype = { | 118 WebInspector.FlameChartDataProvider.prototype = { |
110 /** | 119 /** |
111 * @return {number} | 120 * @return {number} |
112 */ | 121 */ |
113 barHeight: function() { }, | 122 barHeight: function() { }, |
114 | 123 |
115 /** | 124 /** |
116 * @param {number} startTime | 125 * @param {number} startTime |
117 * @param {number} endTime | 126 * @param {number} endTime |
118 * @return {?Array.<number>} | 127 * @return {?Array.<number>} |
119 */ | 128 */ |
120 dividerOffsets: function(startTime, endTime) { }, | 129 dividerOffsets: function(startTime, endTime) { }, |
121 | 130 |
122 /** | 131 /** |
| 132 * @param {number} index |
| 133 * @return {string} |
| 134 */ |
| 135 markerColor: function(index) { }, |
| 136 |
| 137 /** |
| 138 * @param {number} index |
| 139 * @return {string} |
| 140 */ |
| 141 markerTitle: function(index) { }, |
| 142 |
| 143 /** |
123 * @return {number} | 144 * @return {number} |
124 */ | 145 */ |
125 minimumBoundary: function() { }, | 146 minimumBoundary: function() { }, |
126 | 147 |
127 /** | 148 /** |
128 * @return {number} | 149 * @return {number} |
129 */ | 150 */ |
130 totalTime: function() { }, | 151 totalTime: function() { }, |
131 | 152 |
132 /** | 153 /** |
(...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
448 this._isDragging = false; | 469 this._isDragging = false; |
449 }, | 470 }, |
450 | 471 |
451 /** | 472 /** |
452 * @param {!Event} event | 473 * @param {!Event} event |
453 */ | 474 */ |
454 _onMouseMove: function(event) | 475 _onMouseMove: function(event) |
455 { | 476 { |
456 if (this._isDragging) | 477 if (this._isDragging) |
457 return; | 478 return; |
| 479 |
| 480 var inDividersBar = event.offsetY < WebInspector.FlameChart.DividersBarH
eight; |
| 481 this._highlightedMarkerIndex = inDividersBar ? this._markerIndexAtPositi
on(event.offsetX) : -1; |
| 482 this._updateMarkerHighlight(); |
| 483 if (inDividersBar) |
| 484 return; |
| 485 |
458 var entryIndex = this._coordinatesToEntryIndex(event.offsetX, event.offs
etY); | 486 var entryIndex = this._coordinatesToEntryIndex(event.offsetX, event.offs
etY); |
459 | 487 |
460 if (this._highlightedEntryIndex === entryIndex) | 488 if (this._highlightedEntryIndex === entryIndex) |
461 return; | 489 return; |
462 | 490 |
463 if (entryIndex === -1 || !this._dataProvider.canJumpToEntry(entryIndex)) | 491 if (entryIndex === -1 || !this._dataProvider.canJumpToEntry(entryIndex)) |
464 this._canvas.style.cursor = "default"; | 492 this._canvas.style.cursor = "default"; |
465 else | 493 else |
466 this._canvas.style.cursor = "pointer"; | 494 this._canvas.style.cursor = "pointer"; |
467 | 495 |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
555 } else { | 583 } else { |
556 cursorLevel = Math.floor((this._canvas.height / window.devicePixelRa
tio - y) / this._barHeight); | 584 cursorLevel = Math.floor((this._canvas.height / window.devicePixelRa
tio - y) / this._barHeight); |
557 offsetFromLevel = this._canvas.height / window.devicePixelRatio - cu
rsorLevel * this._barHeight; | 585 offsetFromLevel = this._canvas.height / window.devicePixelRatio - cu
rsorLevel * this._barHeight; |
558 } | 586 } |
559 var entryStartTimes = timelineData.entryStartTimes; | 587 var entryStartTimes = timelineData.entryStartTimes; |
560 var entryTotalTimes = timelineData.entryTotalTimes; | 588 var entryTotalTimes = timelineData.entryTotalTimes; |
561 var entryIndexes = this._timelineLevels[cursorLevel]; | 589 var entryIndexes = this._timelineLevels[cursorLevel]; |
562 if (!entryIndexes || !entryIndexes.length) | 590 if (!entryIndexes || !entryIndexes.length) |
563 return -1; | 591 return -1; |
564 | 592 |
| 593 /** |
| 594 * @param {number} time |
| 595 * @param {number} entryIndex |
| 596 * @return {number} |
| 597 */ |
565 function comparator(time, entryIndex) | 598 function comparator(time, entryIndex) |
566 { | 599 { |
567 return time - entryStartTimes[entryIndex]; | 600 return time - entryStartTimes[entryIndex]; |
568 } | 601 } |
569 var indexOnLevel = Math.max(entryIndexes.upperBound(cursorTime, comparat
or) - 1, 0); | 602 var indexOnLevel = Math.max(entryIndexes.upperBound(cursorTime, comparat
or) - 1, 0); |
570 | 603 |
571 /** | 604 /** |
572 * @this {WebInspector.FlameChart} | 605 * @this {WebInspector.FlameChart} |
573 * @param {number} entryIndex | 606 * @param {number} entryIndex |
574 * @return {boolean} | 607 * @return {boolean} |
(...skipping 17 matching lines...) Expand all Loading... |
592 var entryIndex = entryIndexes[indexOnLevel]; | 625 var entryIndex = entryIndexes[indexOnLevel]; |
593 if (checkEntryHit.call(this, entryIndex)) | 626 if (checkEntryHit.call(this, entryIndex)) |
594 return entryIndex; | 627 return entryIndex; |
595 entryIndex = entryIndexes[indexOnLevel + 1]; | 628 entryIndex = entryIndexes[indexOnLevel + 1]; |
596 if (checkEntryHit.call(this, entryIndex)) | 629 if (checkEntryHit.call(this, entryIndex)) |
597 return entryIndex; | 630 return entryIndex; |
598 return -1; | 631 return -1; |
599 }, | 632 }, |
600 | 633 |
601 /** | 634 /** |
| 635 * @param {number} x |
| 636 * @return {number} |
| 637 */ |
| 638 _markerIndexAtPosition: function(x) |
| 639 { |
| 640 var markers = this._timelineData().markerTimestamps; |
| 641 if (!markers) |
| 642 return -1; |
| 643 var accurracyOffsetPx = 1; |
| 644 var time = this._cursorTime(x); |
| 645 var leftTime = this._cursorTime(x - accurracyOffsetPx); |
| 646 var rightTime = this._cursorTime(x + accurracyOffsetPx); |
| 647 |
| 648 /** |
| 649 * @param {number} time |
| 650 * @param {number} markerTimestamp |
| 651 * @return {number} |
| 652 */ |
| 653 function comparator(time, markerTimestamp) |
| 654 { |
| 655 return time - markerTimestamp; |
| 656 } |
| 657 var left = markers.lowerBound(leftTime, comparator); |
| 658 var markerIndex = -1; |
| 659 var distance = Infinity; |
| 660 for (var i = left; i < markers.length && markers[i] < rightTime; i++) { |
| 661 var nextDistance = Math.abs(markers[i] - time); |
| 662 if (nextDistance < distance) { |
| 663 markerIndex = i; |
| 664 distance = nextDistance; |
| 665 } |
| 666 } |
| 667 return markerIndex; |
| 668 }, |
| 669 |
| 670 /** |
602 * @param {number} height | 671 * @param {number} height |
603 * @param {number} width | 672 * @param {number} width |
604 */ | 673 */ |
605 _draw: function(width, height) | 674 _draw: function(width, height) |
606 { | 675 { |
607 var timelineData = this._timelineData(); | 676 var timelineData = this._timelineData(); |
608 if (!timelineData) | 677 if (!timelineData) |
609 return; | 678 return; |
610 | 679 |
611 var context = this._canvas.getContext("2d"); | 680 var context = this._canvas.getContext("2d"); |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
739 if (!text || !text.length) | 808 if (!text || !text.length) |
740 continue; | 809 continue; |
741 | 810 |
742 context.fillStyle = this._dataProvider.textColor(entryIndex); | 811 context.fillStyle = this._dataProvider.textColor(entryIndex); |
743 context.fillText(text, barX + textPadding, textBaseHeight - barLevel
* this._barHeightDelta); | 812 context.fillText(text, barX + textPadding, textBaseHeight - barLevel
* this._barHeightDelta); |
744 } | 813 } |
745 context.restore(); | 814 context.restore(); |
746 | 815 |
747 var offsets = this._dataProvider.dividerOffsets(this._calculator.minimum
Boundary(), this._calculator.maximumBoundary()); | 816 var offsets = this._dataProvider.dividerOffsets(this._calculator.minimum
Boundary(), this._calculator.maximumBoundary()); |
748 WebInspector.TimelineGrid.drawCanvasGrid(this._canvas, this._calculator,
offsets); | 817 WebInspector.TimelineGrid.drawCanvasGrid(this._canvas, this._calculator,
offsets); |
| 818 this._drawMarkers(); |
749 | 819 |
750 this._updateElementPosition(this._highlightElement, this._highlightedEnt
ryIndex); | 820 this._updateElementPosition(this._highlightElement, this._highlightedEnt
ryIndex); |
751 this._updateElementPosition(this._selectedElement, this._selectedEntryIn
dex); | 821 this._updateElementPosition(this._selectedElement, this._selectedEntryIn
dex); |
| 822 this._updateMarkerHighlight(); |
| 823 }, |
| 824 |
| 825 _drawMarkers: function() |
| 826 { |
| 827 var markerTimestamps = this._timelineData().markerTimestamps; |
| 828 /** |
| 829 * @param {number} time |
| 830 * @param {number} markerTimestamp |
| 831 * @return {number} |
| 832 */ |
| 833 function compare(time, markerTimestamp) |
| 834 { |
| 835 return time - markerTimestamp; |
| 836 } |
| 837 var left = markerTimestamps.lowerBound(this._calculator.minimumBoundary(
), compare); |
| 838 var rightBoundary = this._calculator.maximumBoundary(); |
| 839 |
| 840 var context = this._canvas.getContext("2d"); |
| 841 context.save(); |
| 842 var ratio = window.devicePixelRatio; |
| 843 context.scale(ratio, ratio); |
| 844 var height = WebInspector.FlameChart.DividersBarHeight - 1; |
| 845 context.lineWidth = 2; |
| 846 for (var i = left; i < markerTimestamps.length; i++) { |
| 847 var timestamp = markerTimestamps[i]; |
| 848 if (timestamp > rightBoundary) |
| 849 break; |
| 850 var position = this._calculator.computePosition(timestamp); |
| 851 context.strokeStyle = this._dataProvider.markerColor(i); |
| 852 context.beginPath(); |
| 853 context.moveTo(position, 0); |
| 854 context.lineTo(position, height); |
| 855 context.stroke(); |
| 856 } |
| 857 context.restore(); |
| 858 }, |
| 859 |
| 860 _updateMarkerHighlight: function() |
| 861 { |
| 862 var element = this._markerHighlighElement; |
| 863 if (element.parentElement) |
| 864 element.remove(); |
| 865 var markerIndex = this._highlightedMarkerIndex; |
| 866 if (markerIndex === -1) |
| 867 return; |
| 868 var barX = this._timeToPosition(this._timelineData().markerTimestamps[ma
rkerIndex]); |
| 869 element.title = this._dataProvider.markerTitle(markerIndex); |
| 870 var style = element.style; |
| 871 style.left = barX + "px"; |
| 872 style.backgroundColor = this._dataProvider.markerColor(markerIndex); |
| 873 this.element.appendChild(element); |
752 }, | 874 }, |
753 | 875 |
754 /** | 876 /** |
755 * @param {?WebInspector.FlameChart.TimelineData} timelineData | 877 * @param {?WebInspector.FlameChart.TimelineData} timelineData |
756 */ | 878 */ |
757 _processTimelineData: function(timelineData) | 879 _processTimelineData: function(timelineData) |
758 { | 880 { |
759 if (!timelineData) { | 881 if (!timelineData) { |
760 this._timelineLevels = null; | 882 this._timelineLevels = null; |
761 this._rawTimelineData = null; | 883 this._rawTimelineData = null; |
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
946 if (!this._timelineData()) | 1068 if (!this._timelineData()) |
947 return; | 1069 return; |
948 this._resetCanvas(); | 1070 this._resetCanvas(); |
949 this._updateBoundaries(); | 1071 this._updateBoundaries(); |
950 this._calculator._updateBoundaries(this); | 1072 this._calculator._updateBoundaries(this); |
951 this._draw(this._offsetWidth, this._offsetHeight); | 1073 this._draw(this._offsetWidth, this._offsetHeight); |
952 }, | 1074 }, |
953 | 1075 |
954 reset: function() | 1076 reset: function() |
955 { | 1077 { |
| 1078 this._highlightedMarkerIndex = -1; |
956 this._highlightedEntryIndex = -1; | 1079 this._highlightedEntryIndex = -1; |
957 this._selectedEntryIndex = -1; | 1080 this._selectedEntryIndex = -1; |
958 this._textWidth = {}; | 1081 this._textWidth = {}; |
959 this.update(); | 1082 this.update(); |
960 }, | 1083 }, |
961 | 1084 |
962 __proto__: WebInspector.HBox.prototype | 1085 __proto__: WebInspector.HBox.prototype |
963 } | 1086 } |
OLD | NEW |