123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- import {mat3} from 'gl-matrix';
- import {FlamegraphSearch} from 'sentry/utils/profiling/flamegraph/flamegraphStateProvider/reducers/flamegraphSearch';
- import {
- computeHighlightedBounds,
- ELLIPSIS,
- getContext,
- lowerBound,
- resizeCanvasToDisplaySize,
- upperBound,
- } from 'sentry/utils/profiling/gl/utils';
- import {TextRenderer} from 'sentry/utils/profiling/renderers/textRenderer';
- import {SpanChart, SpanChartNode} from 'sentry/utils/profiling/spanChart';
- import {FlamegraphTheme} from '../flamegraph/flamegraphTheme';
- import {findRangeBinarySearch, Rect, trimTextCenter} from '../speedscope';
- class SpansTextRenderer extends TextRenderer {
- spanChart: SpanChart;
- constructor(canvas: HTMLCanvasElement, theme: FlamegraphTheme, spanChart: SpanChart) {
- super(canvas, theme);
- this.canvas = canvas;
- this.theme = theme;
- this.spanChart = spanChart;
- this.textCache = {};
- this.context = getContext(canvas, '2d');
- resizeCanvasToDisplaySize(canvas);
- }
- draw(
- configView: Rect,
- configViewToPhysicalSpace: mat3,
- flamegraphSearchResults: FlamegraphSearch['results']['spans']
- ): void {
-
- const FONT_SIZE = this.theme.SIZES.SPANS_FONT_SIZE * window.devicePixelRatio;
- this.context.font = `${FONT_SIZE}px ${this.theme.FONTS.FRAME_FONT}`;
- this.context.textBaseline = 'alphabetic';
- this.maybeInvalidateCache();
- const MIN_WIDTH = this.measureAndCacheText(ELLIPSIS).width;
- const SIDE_PADDING = 2 * this.theme.SIZES.BAR_PADDING * window.devicePixelRatio;
- const HALF_SIDE_PADDING = SIDE_PADDING / 2;
- const BASELINE_OFFSET =
- (this.theme.SIZES.SPANS_BAR_HEIGHT - this.theme.SIZES.SPANS_FONT_SIZE / 2) *
- window.devicePixelRatio;
- const TOP_BOUNDARY = configView.top - 1;
- const BOTTOM_BOUNDARY = configView.bottom + 1;
- const HIGHLIGHT_BACKGROUND_COLOR = `rgb(${this.theme.COLORS.HIGHLIGHTED_LABEL_COLOR.join(
- ', '
- )})`;
- const HAS_SEARCH_RESULTS = flamegraphSearchResults.size > 0;
- const TEXT_Y_POSITION = FONT_SIZE / 2 - BASELINE_OFFSET;
-
-
-
-
-
-
-
-
-
-
-
-
- const spans: SpanChartNode[] = [...this.spanChart.root.children];
- while (spans.length > 0) {
- const span = spans.pop()!;
- if (span.depth > BOTTOM_BOUNDARY) {
- continue;
- }
-
- const pinnedStart = Math.max(span.start, configView.left);
- const pinnedEnd = Math.min(span.end, configView.right);
-
-
- const rectWidth =
- (pinnedEnd - pinnedStart) * configViewToPhysicalSpace[0] +
- configViewToPhysicalSpace[3];
-
-
- const paddedRectangleWidth = rectWidth - SIDE_PADDING;
-
- if (paddedRectangleWidth <= MIN_WIDTH) {
- continue;
- }
- const endChild = upperBound(configView.right, span.children);
- for (let i = lowerBound(configView.left, span.children); i < endChild; i++) {
- spans.push(span.children[i]);
- }
-
-
-
- if (span.depth < TOP_BOUNDARY) {
- continue;
- }
-
-
- const rectHeight =
- (pinnedEnd - pinnedStart) * configViewToPhysicalSpace[1] +
- configViewToPhysicalSpace[4];
- const rectX =
- pinnedStart * configViewToPhysicalSpace[0] +
- span.depth * configViewToPhysicalSpace[3] +
- configViewToPhysicalSpace[6];
- const rectY =
- pinnedStart * configViewToPhysicalSpace[1] +
- span.depth * configViewToPhysicalSpace[4] +
- configViewToPhysicalSpace[7];
-
-
- const x = rectX + (rectWidth < 0 ? rectWidth : 0) + HALF_SIDE_PADDING;
- const y = rectY + (rectHeight < 0 ? rectHeight : 0) + BASELINE_OFFSET;
- const text = span.text;
- const trim = trimTextCenter(
- text,
- findRangeBinarySearch(
- {low: 0, high: paddedRectangleWidth},
- n => this.measureAndCacheText(text.substring(0, n)).width,
- paddedRectangleWidth
- )[0]
- );
- if (HAS_SEARCH_RESULTS) {
- const frameResults = flamegraphSearchResults.get(span.node.span.span_id);
- if (frameResults) {
- this.context.fillStyle = HIGHLIGHT_BACKGROUND_COLOR;
- for (let i = 0; i < frameResults.match.length; i++) {
- const match = frameResults.match[i];
- const highlightedBounds = computeHighlightedBounds(match, trim);
- const frontMatter = trim.text.slice(0, highlightedBounds[0]);
- const highlightWidth = this.measureAndCacheText(
- trim.text.substring(highlightedBounds[0], highlightedBounds[1])
- ).width;
- this.context.fillRect(
- x + this.measureAndCacheText(frontMatter).width,
- y + TEXT_Y_POSITION,
- highlightWidth,
- FONT_SIZE
- );
- }
- }
- }
- this.context.fillStyle = this.theme.COLORS.LABEL_FONT_COLOR;
- this.context.fillText(trim.text, x, y);
- }
- }
- }
- export {SpansTextRenderer};
|