/
githubmr
/
facebook-react
Обзор
Документация
Войти
/
githubmr
/
facebook-react
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
main
packages/react-devtools-timeline/src/content-views/ComponentMeasuresView.js
301 строка
8 KB
Jan Kassens
Upgrade prettier (#26081)
31 янв 2023, 16:25
Не верифицирован
31 янв 2023, 16:25
6b30832
Код
Авторство
О чём код?
/** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @flow */ import type {ReactComponentMeasure, TimelineData, ViewState} from '../types'; import type { Interaction, IntrinsicSize, MouseMoveInteraction, Rect, ViewRefs, } from '../view-base'; import { durationToWidth, positioningScaleFactor, positionToTimestamp, timestampToPosition, } from './utils/positioning'; import {drawText} from './utils/text'; import {formatDuration} from '../utils/formatting'; import { View, Surface, rectContainsPoint, rectIntersectsRect, intersectionOfRects, } from '../view-base'; import {BORDER_SIZE, COLORS, NATIVE_EVENT_HEIGHT} from './constants'; const ROW_WITH_BORDER_HEIGHT = NATIVE_EVENT_HEIGHT + BORDER_SIZE; export class ComponentMeasuresView extends View { _cachedSearchMatches: Map<string, boolean>; _cachedSearchRegExp: RegExp | null = null; _hoveredComponentMeasure: ReactComponentMeasure | null = null; _intrinsicSize: IntrinsicSize; _profilerData: TimelineData; _viewState: ViewState; onHover: ((event: ReactComponentMeasure | null) => void) | null = null; constructor( surface: Surface, frame: Rect, profilerData: TimelineData, viewState: ViewState, ) { super(surface, frame); this._profilerData = profilerData; this._viewState = viewState; this._cachedSearchMatches = new Map(); this._cachedSearchRegExp = null; viewState.onSearchRegExpStateChange(() => { this.setNeedsDisplay(); }); this._intrinsicSize = { width: profilerData.duration, height: ROW_WITH_BORDER_HEIGHT, }; } desiredSize(): IntrinsicSize { return this._intrinsicSize; } setHoveredEvent(hoveredEvent: ReactComponentMeasure | null) { if (this._hoveredComponentMeasure === hoveredEvent) { return; } this._hoveredComponentMeasure = hoveredEvent; this.setNeedsDisplay(); } /** * Draw a single `ReactComponentMeasure` as a box/span with text inside of it. */ _drawSingleReactComponentMeasure( context: CanvasRenderingContext2D, rect: Rect, componentMeasure: ReactComponentMeasure, scaleFactor: number, showHoverHighlight: boolean, ): boolean { const {frame} = this; const {componentName, duration, timestamp, type, warning} = componentMeasure; const xStart = timestampToPosition(timestamp, scaleFactor, frame); const xStop = timestampToPosition(timestamp + duration, scaleFactor, frame); const componentMeasureRect: Rect = { origin: { x: xStart, y: frame.origin.y, }, size: {width: xStop - xStart, height: NATIVE_EVENT_HEIGHT}, }; if (!rectIntersectsRect(componentMeasureRect, rect)) { return false; // Not in view } const width = durationToWidth(duration, scaleFactor); if (width < 1) { return false; // Too small to render at this zoom level } let textFillStyle = ((null: any): string); let typeLabel = ((null: any): string); const drawableRect = intersectionOfRects(componentMeasureRect, rect); context.beginPath(); if (warning !== null) { context.fillStyle = showHoverHighlight ? COLORS.WARNING_BACKGROUND_HOVER : COLORS.WARNING_BACKGROUND; } else { switch (type) { case 'render': context.fillStyle = showHoverHighlight ? COLORS.REACT_RENDER_HOVER : COLORS.REACT_RENDER; textFillStyle = COLORS.REACT_RENDER_TEXT; typeLabel = 'rendered'; break; case 'layout-effect-mount': context.fillStyle = showHoverHighlight ? COLORS.REACT_LAYOUT_EFFECTS_HOVER : COLORS.REACT_LAYOUT_EFFECTS; textFillStyle = COLORS.REACT_LAYOUT_EFFECTS_TEXT; typeLabel = 'mounted layout effect'; break; case 'layout-effect-unmount': context.fillStyle = showHoverHighlight ? COLORS.REACT_LAYOUT_EFFECTS_HOVER : COLORS.REACT_LAYOUT_EFFECTS; textFillStyle = COLORS.REACT_LAYOUT_EFFECTS_TEXT; typeLabel = 'unmounted layout effect'; break; case 'passive-effect-mount': context.fillStyle = showHoverHighlight ? COLORS.REACT_PASSIVE_EFFECTS_HOVER : COLORS.REACT_PASSIVE_EFFECTS; textFillStyle = COLORS.REACT_PASSIVE_EFFECTS_TEXT; typeLabel = 'mounted passive effect'; break; case 'passive-effect-unmount': context.fillStyle = showHoverHighlight ? COLORS.REACT_PASSIVE_EFFECTS_HOVER : COLORS.REACT_PASSIVE_EFFECTS; textFillStyle = COLORS.REACT_PASSIVE_EFFECTS_TEXT; typeLabel = 'unmounted passive effect'; break; } } let isMatch = false; const cachedSearchRegExp = this._cachedSearchRegExp; if (cachedSearchRegExp !== null) { const cachedSearchMatches = this._cachedSearchMatches; const cachedValue = cachedSearchMatches.get(componentName); if (cachedValue != null) { isMatch = cachedValue; } else { isMatch = componentName.match(cachedSearchRegExp) !== null; cachedSearchMatches.set(componentName, isMatch); } } if (isMatch) { context.fillStyle = COLORS.SEARCH_RESULT_FILL; } context.fillRect( drawableRect.origin.x, drawableRect.origin.y, drawableRect.size.width, drawableRect.size.height, ); const label = `${componentName} ${typeLabel} - ${formatDuration(duration)}`; drawText(label, context, componentMeasureRect, drawableRect, { fillStyle: textFillStyle, }); return true; } draw(context: CanvasRenderingContext2D) { const { frame, _profilerData: {componentMeasures}, _hoveredComponentMeasure, visibleArea, } = this; const searchRegExp = this._viewState.searchRegExp; if (this._cachedSearchRegExp !== searchRegExp) { this._cachedSearchMatches = new Map(); this._cachedSearchRegExp = searchRegExp; } context.fillStyle = COLORS.BACKGROUND; context.fillRect( visibleArea.origin.x, visibleArea.origin.y, visibleArea.size.width, visibleArea.size.height, ); // Draw events const scaleFactor = positioningScaleFactor( this._intrinsicSize.width, frame, ); let didDrawMeasure = false; componentMeasures.forEach(componentMeasure => { didDrawMeasure = this._drawSingleReactComponentMeasure( context, visibleArea, componentMeasure, scaleFactor, componentMeasure === _hoveredComponentMeasure, ) || didDrawMeasure; }); if (!didDrawMeasure) { drawText( '(zoom or pan to see React components)', context, visibleArea, visibleArea, {fillStyle: COLORS.TEXT_DIM_COLOR, textAlign: 'center'}, ); } context.fillStyle = COLORS.PRIORITY_BORDER; context.fillRect( visibleArea.origin.x, visibleArea.origin.y + ROW_WITH_BORDER_HEIGHT - BORDER_SIZE, visibleArea.size.width, BORDER_SIZE, ); } /** * @private */ _handleMouseMove(interaction: MouseMoveInteraction, viewRefs: ViewRefs) { const {frame, _intrinsicSize, onHover, visibleArea} = this; if (!onHover) { return; } const {location} = interaction.payload; if (!rectContainsPoint(location, visibleArea)) { onHover(null); return; } const scaleFactor = positioningScaleFactor(_intrinsicSize.width, frame); const hoverTimestamp = positionToTimestamp(location.x, scaleFactor, frame); const componentMeasures = this._profilerData.componentMeasures; for (let index = componentMeasures.length - 1; index >= 0; index--) { const componentMeasure = componentMeasures[index]; const {duration, timestamp} = componentMeasure; if ( hoverTimestamp >= timestamp && hoverTimestamp <= timestamp + duration ) { this.currentCursor = 'context-menu'; viewRefs.hoveredView = this; onHover(componentMeasure); return; } } onHover(null); } handleInteraction(interaction: Interaction, viewRefs: ViewRefs) { switch (interaction.type) { case 'mousemove': this._handleMouseMove(interaction, viewRefs); break; } } }