diff --git a/src/components/timeline/TrackCustomMarkerGraph.js b/src/components/timeline/TrackCustomMarkerGraph.js index 04b1bfab93..5ddbf74b6e 100644 --- a/src/components/timeline/TrackCustomMarkerGraph.js +++ b/src/components/timeline/TrackCustomMarkerGraph.js @@ -58,6 +58,7 @@ import { assertExhaustiveCheck } from 'firefox-profiler/utils/flow'; import type { SizeProps } from 'firefox-profiler/components/shared/WithSize'; import type { ConnectedProps } from 'firefox-profiler/utils/connect'; +import { timeCode } from 'firefox-profiler/utils/time-code'; import './TrackCustomMarker.css'; @@ -226,6 +227,22 @@ class TrackCustomMarkerCanvas extends React.PureComponent { // ctx.strokeStyle = _getStrokeColor(color || TRACK_MARKER_DEFAULT_COLOR); + const getX = (marker) => + Math.round((marker.start - rangeStart) * millisecondWidth); + const getY = (i) => { + const unitValue = _calculateUnitValue( + type, + minNumber, + maxNumber, + samples[i] + ); + // Add on half the stroke's line width so that it won't be cut + // off the edge of the graph. + return Math.round( + deviceHeight - deviceHeight * unitValue - deviceLineHalfWidth + ); + }; + switch (type) { case 'line': case 'line-filled': { @@ -247,16 +264,8 @@ class TrackCustomMarkerCanvas extends React.PureComponent { const marker = getMarker(collectedSamples.markerIndexes[i]); // Create a path for the top of the chart. This is the line that // will have a stroke applied to it. - x = (marker.start - rangeStart) * millisecondWidth; - // Add on half the stroke's line width so that it won't be cut - // off the edge of the graph. - const unitValue = _calculateUnitValue( - type, - minNumber, - maxNumber, - samples[i] - ); - y = deviceHeight - deviceHeight * unitValue - deviceLineHalfWidth; + x = getX(marker); + y = getY(i); if (i === sampleStart) { // This is the first iteration, only move the line, do not draw it. // Also remember this first X, as the bottom of the graph will need @@ -301,32 +310,32 @@ class TrackCustomMarkerCanvas extends React.PureComponent { ctx.fillStyle = ctx.strokeStyle; for (let i = sampleStart; i < sampleEnd; i++) { - const marker = getMarker(collectedSamples.markerIndexes[i]); - const x = Math.round( - (marker.start - rangeStart) * millisecondWidth - ); - - const unitValue = _calculateUnitValue( - type, - minNumber, - maxNumber, - samples[i] - ); - const y = - deviceHeight - deviceHeight * unitValue - deviceLineHalfWidth; - - if (marker.end) { - const x2 = Math.round( - (marker.end - rangeStart) * millisecondWidth + let marker = getMarker(collectedSamples.markerIndexes[i]); + const x = getX(marker); + let y = getY(i); + + // If we have multiple markers to draw on the same horizontal pixel, + // draw only the one with the maximum value to save time. + while (i + 1 < sampleEnd) { + const nextMarker = getMarker( + collectedSamples.markerIndexes[i + 1] ); - if (x2 >= x + 1) { - ctx.fillRect(x, y, x2 - x, deviceHeight - y); - continue; + if (getX(nextMarker) !== x) { + break; } + + marker = nextMarker; + y = Math.min(y, getY(++i)); } - ctx.moveTo(x, deviceHeight); - ctx.lineTo(x, y); - ctx.stroke(); + + const x2 = marker.end + ? Math.max( + x + 1, + Math.round((marker.end - rangeStart) * millisecondWidth) + ) + : x + 1; + + ctx.fillRect(x, y, x2 - x, deviceHeight - y); } break; default: @@ -353,7 +362,9 @@ class TrackCustomMarkerCanvas extends React.PureComponent { this._requestedAnimationFrame = false; const canvas = this._canvas; if (canvas) { - this.drawCanvas(canvas); + timeCode('TrackCustomMarkerCanvas render', () => { + this.drawCanvas(canvas); + }); } }); } diff --git a/src/test/components/__snapshots__/TrackCustomMarker.test.js.snap b/src/test/components/__snapshots__/TrackCustomMarker.test.js.snap index a8258f61d6..f70dccdc55 100644 --- a/src/test/components/__snapshots__/TrackCustomMarker.test.js.snap +++ b/src/test/components/__snapshots__/TrackCustomMarker.test.js.snap @@ -94,72 +94,72 @@ Array [ Array [ "lineTo", 10, - 22.482142857142858, + 22, ], Array [ "lineTo", 20, - 22.482142857142858, + 22, ], Array [ "lineTo", 20, - 20.964285714285715, + 21, ], Array [ "lineTo", 30, - 20.964285714285715, + 21, ], Array [ "lineTo", 30, - 19.446428571428573, + 19, ], Array [ "lineTo", 40, - 19.446428571428573, + 19, ], Array [ "lineTo", 40, - 17.92857142857143, + 18, ], Array [ "lineTo", 50, - 17.92857142857143, + 18, ], Array [ "lineTo", 50, - 16.410714285714285, + 16, ], Array [ "lineTo", 60, - 16.410714285714285, + 16, ], Array [ "lineTo", 60, - 14.892857142857144, + 15, ], Array [ "lineTo", 70, - 14.892857142857144, + 15, ], Array [ "lineTo", 70, - 13.375, + 13, ], Array [ "lineTo", 80, - 13.375, + 13, ], Array [ "stroke", @@ -182,51 +182,51 @@ Array [ Array [ "fillRect", 10, - 20.964285714285715, + 21, 10, - 4.035714285714285, + 4, ], Array [ "fillRect", 20, - 17.92857142857143, + 18, 10, - 7.071428571428569, + 7, ], Array [ "fillRect", 30, - 14.892857142857144, + 15, + 10, 10, - 10.107142857142856, ], Array [ "fillRect", 40, - 11.85714285714286, + 12, 10, - 13.14285714285714, + 13, ], Array [ "fillRect", 50, - 8.821428571428573, + 9, 10, - 16.178571428571427, + 16, ], Array [ "fillRect", 60, - 5.785714285714288, + 6, 10, - 19.21428571428571, + 19, ], Array [ "fillRect", 70, - 2.75, + 3, 10, - 22.25, + 22, ], ] `;