Index: Source/devtools/front_end/components/FlameChart.js |
diff --git a/Source/devtools/front_end/components/FlameChart.js b/Source/devtools/front_end/components/FlameChart.js |
index f4a9c7366e25b9b4a234e4226e703dd6609efa24..06827606e624e67df5fde2ae7f416d6a176eeaed 100644 |
--- a/Source/devtools/front_end/components/FlameChart.js |
+++ b/Source/devtools/front_end/components/FlameChart.js |
@@ -68,6 +68,7 @@ WebInspector.FlameChart = function(dataProvider, flameChartDelegate, isTopDown) |
this._vScrollElement.addEventListener("scroll", this.scheduleUpdate.bind(this), false); |
this._entryInfo = this.element.createChild("div", "profile-entry-info"); |
+ this._markerHighlighElement = this.element.createChild("div", "flame-chart-marker-highlight-element"); |
this._highlightElement = this.element.createChild("div", "flame-chart-highlight-element"); |
this._selectedElement = this.element.createChild("div", "flame-chart-selected-element"); |
@@ -84,6 +85,7 @@ WebInspector.FlameChart = function(dataProvider, flameChartDelegate, isTopDown) |
this._paddingLeft = this._dataProvider.paddingLeft(); |
this._markerPadding = 2; |
this._markerRadius = this._barHeight / 2 - this._markerPadding; |
+ this._highlightedMarkerIndex = -1; |
this._highlightedEntryIndex = -1; |
this._selectedEntryIndex = -1; |
this._textWidth = {}; |
@@ -98,13 +100,20 @@ WebInspector.FlameChartDataProvider = function() |
{ |
} |
-/** @typedef {!{ |
- entryLevels: (!Array.<number>|!Uint8Array), |
- entryTotalTimes: (!Array.<number>|!Float32Array), |
- entryStartTimes: (!Array.<number>|!Float64Array) |
- }} |
+/** |
+ * @constructor |
+ * @param {!Array.<number>|!Uint8Array} entryLevels |
+ * @param {!Array.<number>|!Float32Array} entryTotalTimes |
+ * @param {!Array.<number>|!Float64Array} entryStartTimes |
*/ |
-WebInspector.FlameChart.TimelineData; |
+WebInspector.FlameChart.TimelineData = function(entryLevels, entryTotalTimes, entryStartTimes) |
+{ |
+ this.entryLevels = entryLevels; |
+ this.entryTotalTimes = entryTotalTimes; |
+ this.entryStartTimes = entryStartTimes; |
+ /** @type {!Array.<number>} */ |
+ this.markerTimestamps = []; |
+} |
WebInspector.FlameChartDataProvider.prototype = { |
/** |
@@ -120,6 +129,18 @@ WebInspector.FlameChartDataProvider.prototype = { |
dividerOffsets: function(startTime, endTime) { }, |
/** |
+ * @param {number} index |
+ * @return {string} |
+ */ |
+ markerColor: function(index) { }, |
+ |
+ /** |
+ * @param {number} index |
+ * @return {string} |
+ */ |
+ markerTitle: function(index) { }, |
+ |
+ /** |
* @return {number} |
*/ |
minimumBoundary: function() { }, |
@@ -455,6 +476,13 @@ WebInspector.FlameChart.prototype = { |
{ |
if (this._isDragging) |
return; |
+ |
+ var inDividersBar = event.offsetY < WebInspector.FlameChart.DividersBarHeight; |
+ this._highlightedMarkerIndex = inDividersBar ? this._markerIndexAtPosition(event.offsetX) : -1; |
+ this._updateMarkerHighlight(); |
+ if (inDividersBar) |
+ return; |
+ |
var entryIndex = this._coordinatesToEntryIndex(event.offsetX, event.offsetY); |
if (this._highlightedEntryIndex === entryIndex) |
@@ -562,6 +590,11 @@ WebInspector.FlameChart.prototype = { |
if (!entryIndexes || !entryIndexes.length) |
return -1; |
+ /** |
+ * @param {number} time |
+ * @param {number} entryIndex |
+ * @return {number} |
+ */ |
function comparator(time, entryIndex) |
{ |
return time - entryStartTimes[entryIndex]; |
@@ -599,6 +632,42 @@ WebInspector.FlameChart.prototype = { |
}, |
/** |
+ * @param {number} x |
+ * @return {number} |
+ */ |
+ _markerIndexAtPosition: function(x) |
+ { |
+ var markers = this._timelineData().markerTimestamps; |
+ if (!markers) |
+ return -1; |
+ var accurracyOffsetPx = 1; |
+ var time = this._cursorTime(x); |
+ var leftTime = this._cursorTime(x - accurracyOffsetPx); |
+ var rightTime = this._cursorTime(x + accurracyOffsetPx); |
+ |
+ /** |
+ * @param {number} time |
+ * @param {number} markerTimestamp |
+ * @return {number} |
+ */ |
+ function comparator(time, markerTimestamp) |
+ { |
+ return time - markerTimestamp; |
+ } |
+ var left = markers.lowerBound(leftTime, comparator); |
+ var markerIndex = -1; |
+ var distance = Infinity; |
+ for (var i = left; i < markers.length && markers[i] < rightTime; i++) { |
+ var nextDistance = Math.abs(markers[i] - time); |
+ if (nextDistance < distance) { |
+ markerIndex = i; |
+ distance = nextDistance; |
+ } |
+ } |
+ return markerIndex; |
+ }, |
+ |
+ /** |
* @param {number} height |
* @param {number} width |
*/ |
@@ -746,9 +815,62 @@ WebInspector.FlameChart.prototype = { |
var offsets = this._dataProvider.dividerOffsets(this._calculator.minimumBoundary(), this._calculator.maximumBoundary()); |
WebInspector.TimelineGrid.drawCanvasGrid(this._canvas, this._calculator, offsets); |
+ this._drawMarkers(); |
this._updateElementPosition(this._highlightElement, this._highlightedEntryIndex); |
this._updateElementPosition(this._selectedElement, this._selectedEntryIndex); |
+ this._updateMarkerHighlight(); |
+ }, |
+ |
+ _drawMarkers: function() |
+ { |
+ var markerTimestamps = this._timelineData().markerTimestamps; |
+ /** |
+ * @param {number} time |
+ * @param {number} markerTimestamp |
+ * @return {number} |
+ */ |
+ function compare(time, markerTimestamp) |
+ { |
+ return time - markerTimestamp; |
+ } |
+ var left = markerTimestamps.lowerBound(this._calculator.minimumBoundary(), compare); |
+ var rightBoundary = this._calculator.maximumBoundary(); |
+ |
+ var context = this._canvas.getContext("2d"); |
+ context.save(); |
+ var ratio = window.devicePixelRatio; |
+ context.scale(ratio, ratio); |
+ var height = WebInspector.FlameChart.DividersBarHeight - 1; |
+ context.lineWidth = 2; |
+ for (var i = left; i < markerTimestamps.length; i++) { |
+ var timestamp = markerTimestamps[i]; |
+ if (timestamp > rightBoundary) |
+ break; |
+ var position = this._calculator.computePosition(timestamp); |
+ context.strokeStyle = this._dataProvider.markerColor(i); |
+ context.beginPath(); |
+ context.moveTo(position, 0); |
+ context.lineTo(position, height); |
+ context.stroke(); |
+ } |
+ context.restore(); |
+ }, |
+ |
+ _updateMarkerHighlight: function() |
+ { |
+ var element = this._markerHighlighElement; |
+ if (element.parentElement) |
+ element.remove(); |
+ var markerIndex = this._highlightedMarkerIndex; |
+ if (markerIndex === -1) |
+ return; |
+ var barX = this._timeToPosition(this._timelineData().markerTimestamps[markerIndex]); |
+ element.title = this._dataProvider.markerTitle(markerIndex); |
+ var style = element.style; |
+ style.left = barX + "px"; |
+ style.backgroundColor = this._dataProvider.markerColor(markerIndex); |
+ this.element.appendChild(element); |
}, |
/** |
@@ -953,6 +1075,7 @@ WebInspector.FlameChart.prototype = { |
reset: function() |
{ |
+ this._highlightedMarkerIndex = -1; |
this._highlightedEntryIndex = -1; |
this._selectedEntryIndex = -1; |
this._textWidth = {}; |