From cd3decd487d641738229a8c5a4213d60ff191d57 Mon Sep 17 00:00:00 2001 From: lumix Date: Sat, 8 Mar 2025 10:58:17 +0800 Subject: [PATCH] perf: remove unnecessary `ctx.font =` calls, and avoid drawing glyphs outside the viewBounds (#4775) --- e2e/perf/scroll.spec.ts | 15 +++++--- package.json | 2 +- .../src/controllers/e2e/e2e.controller.ts | 1 + packages/core/src/sheets/sheet-skeleton.ts | 8 +++- .../src/components/docs/doc-component.ts | 4 +- .../src/components/docs/document.ts | 6 ++- .../docs/extensions/font-and-base-line.ts | 38 +++++++++++++++++-- .../docs/layout/shaping-engine/font-cache.ts | 9 +++-- .../engine-render/src/components/extension.ts | 2 +- .../src/components/sheets/extensions/font.ts | 31 ++++++++++----- .../sheets/extensions/sheet-extension.ts | 15 -------- .../sheets/sheet.render-skeleton.ts | 16 ++++++-- .../src/components/sheets/spreadsheet.ts | 1 + packages/engine-render/src/context.ts | 16 +++++++- .../sheet.render-controller.ts | 30 ++++++++++----- packages/sheets-ui/src/index.ts | 2 +- 16 files changed, 136 insertions(+), 60 deletions(-) diff --git a/e2e/perf/scroll.spec.ts b/e2e/perf/scroll.spec.ts index 27fa41b685bc..dd6c5259075e 100644 --- a/e2e/perf/scroll.spec.ts +++ b/e2e/perf/scroll.spec.ts @@ -21,6 +21,7 @@ import { sheetData as emptySheetData } from '../__testing__/emptysheet'; import { sheetData as freezeData } from '../__testing__/freezesheet'; import { sheetData as mergeCellData } from '../__testing__/mergecell'; import { sheetData as overflowData } from '../__testing__/overflow'; +import { reportToPosthog } from '../utils/report-performance'; export interface IFPSData { fpsData: number[]; @@ -39,7 +40,7 @@ interface IFPSResult { maxFrameTimes: number[]; } -const isCI = !!process.env.CI; +// const isCI = !!process.env.CI; /** * measure FPS of scrolling time. * @param page Page from playwright @@ -132,7 +133,7 @@ async function measureFPS(page: Page, testDuration = 5, deltaX: number, deltaY: return fpsCounterPromise as Promise; } -const createTest = (title: string, sheetData: IJsonObject, minFpsValue: number, deltaX = 0, deltaY = 0) => { +const createTest = (title: string, telemetryName: string, sheetData: IJsonObject, minFpsValue: number, deltaX = 0, deltaY = 0) => { // Default Size Of browser: 1280x720 pixels. And default DPR is 1. test(title, async ({ page }) => { await page.goto('http://localhost:3000/sheets/'); @@ -154,6 +155,8 @@ const createTest = (title: string, sheetData: IJsonObject, minFpsValue: number, console.log('FPS', resultOfFPS.fps); console.log('medianFrameTime', resultOfFPS.medianFrameTime); console.log('max10FrameTimes', resultOfFPS.maxFrameTimes); + + await reportToPosthog(telemetryName, resultOfFPS); expect(resultOfFPS.fps).toBeGreaterThan(minFpsValue); }); } catch (error) { @@ -165,7 +168,7 @@ const createTest = (title: string, sheetData: IJsonObject, minFpsValue: number, }); }; -createTest('sheet scroll empty', emptySheetData, 50, 10, 100); -createTest('sheet scroll after freeze', freezeData, 10, 10, 100); -createTest('sheet scroll in a lots of merge cell', mergeCellData, 10, 10, 50); -createTest('sheet X scroll in a lots of overflow', overflowData, 10, 50, 5); +createTest('sheet scroll empty', 'perf.sheet.scroll.empty', emptySheetData, 50, 10, 100); +createTest('sheet scroll after freeze', 'perf.sheet.scroll.freeze', freezeData, 10, 10, 100); +createTest('sheet scroll in a lots of merge cell', 'perf.sheet.scroll.mergeCell', mergeCellData, 10, 10, 50); +createTest('sheet X scroll in a lots of overflow', 'perf.sheet.scroll.overflow', overflowData, 10, 50, 5); diff --git a/package.json b/package.json index b4416762ca78..fe400cac8b35 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "scripts": { "prepare": "husky", "pre-commit": "lint-staged", - "dev": "turbo dev:demo", + "dev": "turbo dev:demo -- --host 0.0.0.0", "dev:libs": "pnpm --filter univer-examples dev:demo-libs", "dev:e2e": "pnpm --filter univer-examples dev:e2e", "lint:types": "turbo lint:types", diff --git a/packages-experimental/debugger/src/controllers/e2e/e2e.controller.ts b/packages-experimental/debugger/src/controllers/e2e/e2e.controller.ts index f11f2ea07415..d1a7fdd8a0ac 100644 --- a/packages-experimental/debugger/src/controllers/e2e/e2e.controller.ts +++ b/packages-experimental/debugger/src/controllers/e2e/e2e.controller.ts @@ -15,6 +15,7 @@ */ import { awaitTime, Disposable, ICommandService, IUniverInstanceService, UniverInstanceType } from '@univerjs/core'; + import { DEFAULT_WORKBOOK_DATA_DEMO, DEFAULT_WORKBOOK_DATA_DEMO_DEFAULT_STYLE } from '@univerjs/mockdata'; import { DisposeUniverCommand } from '../../commands/commands/unit.command'; import { getDefaultDocData } from './data/default-doc'; diff --git a/packages/core/src/sheets/sheet-skeleton.ts b/packages/core/src/sheets/sheet-skeleton.ts index f73c057af5bc..27e70839095a 100644 --- a/packages/core/src/sheets/sheet-skeleton.ts +++ b/packages/core/src/sheets/sheet-skeleton.ts @@ -97,7 +97,7 @@ export class SheetSkeleton extends Skeleton { this._isRowStylePrecedeColumnStyle = this._configService.getConfig(IS_ROW_STYLE_PRECEDE_COLUMN_STYLE) ?? false; } - _resetCache() { + resetCache() { // } @@ -447,12 +447,16 @@ export class SheetSkeleton extends Skeleton { * @param bounds */ calculate(): Nullable { - this._resetCache(); + this.resetCache(); this._updateLayout(); return this; } + resetRangeCache(_ranges: IRange[]): void { + // ... + } + private _dynamicallyUpdateRowHeaderWidth(rowHeader: { width: number; }): number { diff --git a/packages/engine-render/src/components/docs/doc-component.ts b/packages/engine-render/src/components/docs/doc-component.ts index 83b0abc0d075..ff4980349cd0 100644 --- a/packages/engine-render/src/components/docs/doc-component.ts +++ b/packages/engine-render/src/components/docs/doc-component.ts @@ -82,7 +82,7 @@ export abstract class DocComponent extends RenderComponent< } } - override render(mainCtx: UniverRenderingContext, bounds?: IViewportInfo) { + override render(mainCtx: UniverRenderingContext, bounds?: Partial) { if (!this.visible) { this.makeDirty(false); return this; @@ -146,5 +146,5 @@ export abstract class DocComponent extends RenderComponent< return false; } - protected abstract _draw(ctx: UniverRenderingContext, bounds?: IViewportInfo): void; + protected abstract _draw(ctx: UniverRenderingContext, bounds?: Partial): void; } diff --git a/packages/engine-render/src/components/docs/document.ts b/packages/engine-render/src/components/docs/document.ts index 1725fa4e27e6..ea136bf9d9be 100644 --- a/packages/engine-render/src/components/docs/document.ts +++ b/packages/engine-render/src/components/docs/document.ts @@ -21,7 +21,7 @@ import type { Transform } from '../../basics/transform'; import type { IBoundRectNoAngle, IViewportInfo } from '../../basics/vector2'; import type { UniverRenderingContext } from '../../context'; import type { Scene } from '../../scene'; -import type { ComponentExtension, IExtensionConfig } from '../extension'; +import type { ComponentExtension, IDrawInfo, IExtensionConfig } from '../extension'; import type { IDocumentsConfig, IPageMarginLayout } from './doc-component'; import type { DocumentSkeleton } from './layout/doc-skeleton'; import { CellValueType, HorizontalAlign, VerticalAlign, WrapStrategy } from '@univerjs/core'; @@ -432,7 +432,9 @@ export class Documents extends DocComponent { for (const extension of glyphExtensionsExcludeBackground) { extension.extensionOffset = extensionOffset; - extension.draw(ctx, parentScale, glyph); + extension.draw(ctx, parentScale, glyph, [], { + viewBound: bounds?.viewBound, + } as IDrawInfo); } } diff --git a/packages/engine-render/src/components/docs/extensions/font-and-base-line.ts b/packages/engine-render/src/components/docs/extensions/font-and-base-line.ts index 16f216665f37..97dc670aa40d 100644 --- a/packages/engine-render/src/components/docs/extensions/font-and-base-line.ts +++ b/packages/engine-render/src/components/docs/extensions/font-and-base-line.ts @@ -15,8 +15,10 @@ */ import type { IScale } from '@univerjs/core'; +import type { IBoundRectNoAngle } from '../../../basics'; import type { IDocumentSkeletonGlyph } from '../../../basics/i-document-skeleton-cached'; import type { UniverRenderingContext } from '../../../context'; +import type { IDrawInfo } from '../../extension'; import { BaselineOffset, getColorStyle } from '@univerjs/core'; import { GlyphType, hasCJK } from '../../../basics'; import { COLOR_BLACK_RGB } from '../../../basics/const'; @@ -29,6 +31,9 @@ const UNIQUE_KEY = 'DefaultDocsFontAndBaseLineExtension'; const DOC_EXTENSION_Z_INDEX = 20; +/** + * Singleton + */ export class FontAndBaseLine extends docExtension { override uKey = UNIQUE_KEY; @@ -36,7 +41,21 @@ export class FontAndBaseLine extends docExtension { private _preFontColor = ''; - override draw(ctx: UniverRenderingContext, parentScale: IScale, glyph: IDocumentSkeletonGlyph) { + /** + * ctx.font = val; then ctx.font is not exactly the same as val + * that is because canvas would normalize the font string, remove default value and convert pt to px. + * so we need a map to store actual value and set value + */ + actualFontMap: Record = {}; + + constructor() { + super(); + } + + // invoked by document.ts + override draw(ctx: UniverRenderingContext, _parentScale: IScale, glyph: IDocumentSkeletonGlyph, _?: IBoundRectNoAngle, more?: IDrawInfo) { + // _parentScale: IScale, _skeleton: T, _diffBounds?: V, _more?: IDrawInfo + const line = glyph.parent?.parent; if (!line) { return; @@ -46,6 +65,14 @@ export class FontAndBaseLine extends docExtension { const { spanPointWithFont = Vector2.create(0, 0) } = this.extensionOffset; + if (more) { + if (more.viewBound) { + if (spanPointWithFont.x > more.viewBound.right || spanPointWithFont.y > more.viewBound.bottom) { + return; + } + } + } + if (content == null) { return; } @@ -55,8 +82,12 @@ export class FontAndBaseLine extends docExtension { return; } - if (ctx.font !== fontStyle?.fontString) { - ctx.font = fontStyle?.fontString || ''; + const fontStringPxStr = fontStyle?.fontString || ''; + if (fontStringPxStr) { + if (ctx.font !== this.actualFontMap[fontStringPxStr]) { + ctx.font = fontStringPxStr; + this.actualFontMap[fontStringPxStr] = ctx.font; + } } const { cl: colorStyle, va: baselineOffset } = textStyle; @@ -71,7 +102,6 @@ export class FontAndBaseLine extends docExtension { } else if (baselineOffset === BaselineOffset.SUBSCRIPT) { spanPointWithFont.y += bBox.sbo; } - this._fillText(ctx, glyph, spanPointWithFont); } diff --git a/packages/engine-render/src/components/docs/layout/shaping-engine/font-cache.ts b/packages/engine-render/src/components/docs/layout/shaping-engine/font-cache.ts index 4f4315ae6523..10aa5e5e422d 100644 --- a/packages/engine-render/src/components/docs/layout/shaping-engine/font-cache.ts +++ b/packages/engine-render/src/components/docs/layout/shaping-engine/font-cache.ts @@ -218,8 +218,12 @@ export class FontCache { }, fontStyle); } - // 获取有值单元格文本大小 - // let measureTextCache = {}, measureTextCacheTimeOut = null; + /** + * Measure text on another canvas. + * @param content + * @param fontString + * @returns IMeasureTextCache + */ static getMeasureText(content: string, fontString: string): IMeasureTextCache { if (!this._context) { const canvas = document.createElement('canvas'); @@ -242,7 +246,6 @@ export class FontCache { if (mtc != null) { return mtc; } - ctx.font = fontString; const textMetrics = ctx.measureText(content); diff --git a/packages/engine-render/src/components/extension.ts b/packages/engine-render/src/components/extension.ts index 4a380150b238..2ec06110d129 100644 --- a/packages/engine-render/src/components/extension.ts +++ b/packages/engine-render/src/components/extension.ts @@ -56,7 +56,7 @@ export class ComponentExtension { return this.Z_INDEX; } - draw(ctx: UniverRenderingContext, parentScale: IScale, skeleton: T, diffBounds?: V, more?: IDrawInfo) { + draw(_ctx: UniverRenderingContext, _parentScale: IScale, _skeleton: T, _diff?: V, _more?: IDrawInfo) { /* abstract */ } diff --git a/packages/engine-render/src/components/sheets/extensions/font.ts b/packages/engine-render/src/components/sheets/extensions/font.ts index c9945f0f8ffd..6da1942ad76d 100644 --- a/packages/engine-render/src/components/sheets/extensions/font.ts +++ b/packages/engine-render/src/components/sheets/extensions/font.ts @@ -17,7 +17,8 @@ /* eslint-disable max-lines-per-function */ /* eslint-disable complexity */ -import type { ICellWithCoord, IDocDrawingBase, ImageSourceType, IRange, IScale, Nullable, ObjectMatrix } from '@univerjs/core'; +import type { ICellDataForSheetInterceptor, ICellWithCoord, IDocDrawingBase, ImageSourceType, IRange, IScale, Nullable, ObjectMatrix } from '@univerjs/core'; +import type { IBoundRectNoAngle, IViewportInfo } from '../../../basics'; import type { UniverRenderingContext } from '../../../context'; import type { Documents } from '../../docs/document'; import type { IDrawInfo } from '../../extension'; @@ -190,8 +191,10 @@ export class Font extends SheetExtension { renderFontCtx.fontCache = fontCache; //#region overflow - // If the cell is overflowing, but the overflowRectangle has not been set, - // then overflowRectangle is set to undefined. + // e.g. cell(12, 5)'s textwrap value is overflow(which is default), and text ends at column 9, + // the overflowRange would be startRow: 12, startColumn: 5, endRow: 12, endColumn: 9 + // and if column 9 is not empty, then the overflowRang e endColumn would be 8 + // and if column 7 is not empty, the endColumn would be 6 const overflowRange = spreadsheetSkeleton.overflowCache.getValue(row, col); // If it's neither an overflow nor within the current range, @@ -209,8 +212,11 @@ export class Font extends SheetExtension { const visibleCol = spreadsheetSkeleton.worksheet.getColVisible(col); if (!visibleRow || !visibleCol) return true; - // const cellData = spreadsheetSkeleton.worksheet.getCell(row, col) as ICellDataForSheetInterceptor || {}; - if (renderFontCtx.fontCache?.cellData?.fontRenderExtension?.isSkip) { + // Since we cannot predict when fontRenderExtension?.isSkip might change, + // we must check it every time and retrieve cell data directly from the worksheet, + // not from the cache to ensure accuracy. + const cellData = spreadsheetSkeleton.worksheet.getCell(row, col) as ICellDataForSheetInterceptor || {}; + if (cellData?.fontRenderExtension?.isSkip) { return true; } @@ -219,7 +225,7 @@ export class Font extends SheetExtension { //#region text overflow renderFontCtx.overflowRectangle = overflowRange; - this._setFontRenderBounds(renderFontCtx, row, col); + this._clipByRenderBounds(renderFontCtx, row, col); //#endregion ctx.translate(renderFontCtx.startX + FIX_ONE_PIXEL_BLUR_OFFSET, renderFontCtx.startY + FIX_ONE_PIXEL_BLUR_OFFSET); @@ -232,7 +238,7 @@ export class Font extends SheetExtension { if (documentDataModel.getDrawingsOrder()?.length) { ctx.save(); ctx.beginPath(); - this._setFontRenderBounds(renderFontCtx, row, col, 1); + this._clipByRenderBounds(renderFontCtx, row, col, 1); this._renderImages(ctx, fontCache, renderFontCtx.startX, renderFontCtx.startY, renderFontCtx.endX, renderFontCtx.endY); ctx.closePath(); ctx.restore(); @@ -324,7 +330,7 @@ export class Font extends SheetExtension { * @param col * @param fontCache */ - private _setFontRenderBounds(renderFontContext: IRenderFontContext, row: number, col: number, padding = 0) { + private _clipByRenderBounds(renderFontContext: IRenderFontContext, row: number, col: number, padding = 0) { const { ctx, scale, overflowRectangle, rowHeightAccumulation, columnWidthAccumulation, fontCache } = renderFontContext; let { startX, endX, startY, endY } = renderFontContext; @@ -470,7 +476,14 @@ export class Font extends SheetExtension { documentSkeleton.makeDirty(false); documents.resize(cellWidth, cellHeight); - documents.changeSkeleton(documentSkeleton).render(ctx); + documents.changeSkeleton(documentSkeleton).render(ctx, { + viewBound: { + left: 0, + top: 0, + right: cellWidth, + bottom: cellHeight, + } as IBoundRectNoAngle, + } as Partial); } private _clipRectangleForOverflow( diff --git a/packages/engine-render/src/components/sheets/extensions/sheet-extension.ts b/packages/engine-render/src/components/sheets/extensions/sheet-extension.ts index 9cba5c18fde9..154afc42aa7b 100644 --- a/packages/engine-render/src/components/sheets/extensions/sheet-extension.ts +++ b/packages/engine-render/src/components/sheets/extensions/sheet-extension.ts @@ -54,21 +54,6 @@ export class SheetExtension extends ComponentExtension= startColumn && column <= endColumn) { - // return true; - // } - // } - - // return false; - // } - isRenderDiffRangesByColumn(curStartColumn: number, curEndColumn: number, diffRanges?: IRange[]) { if (diffRanges == null || diffRanges.length === 0) { return true; diff --git a/packages/engine-render/src/components/sheets/sheet.render-skeleton.ts b/packages/engine-render/src/components/sheets/sheet.render-skeleton.ts index 2942c2f7f4c9..2a361d6ae6bc 100644 --- a/packages/engine-render/src/components/sheets/sheet.render-skeleton.ts +++ b/packages/engine-render/src/components/sheets/sheet.render-skeleton.ts @@ -60,6 +60,7 @@ import { isWhiteColor, LocaleService, ObjectMatrix, + Range, searchArray, SheetSkeleton, Tools, @@ -1127,15 +1128,14 @@ export class SpreadsheetSkeleton extends SheetSkeleton { return this.worksheet.getSpanModel().getMergedCellRangeForSkeleton(range.startRow, range.startColumn, range.endRow, range.endColumn); } - resetCache(): void { + override resetCache(): void { this._resetCache(); } /** * Any changes to sheet model would reset cache. */ - override _resetCache(): void { - super._resetCache(); + _resetCache(): void { this._stylesCache = { background: {}, backgroundPositions: new ObjectMatrix(), @@ -1149,6 +1149,16 @@ export class SpreadsheetSkeleton extends SheetSkeleton { this._overflowCache?.reset(); } + override resetRangeCache(ranges: IRange[]): void { + for (let i = 0; i < ranges.length; i++) { + const range = ranges[i]; + Range.foreach(range, (row, col) => { + this._stylesCache.fontMatrix.realDeleteValue(row, col); + }); + } + this.makeDirty(true); + } + _setBorderStylesCache(row: number, col: number, style: Nullable, options: { mergeRange?: IRange; cacheItem?: ICacheItem; diff --git a/packages/engine-render/src/components/sheets/spreadsheet.ts b/packages/engine-render/src/components/sheets/spreadsheet.ts index 9a8e035d083c..ce35da8942e3 100644 --- a/packages/engine-render/src/components/sheets/spreadsheet.ts +++ b/packages/engine-render/src/components/sheets/spreadsheet.ts @@ -133,6 +133,7 @@ export class Spreadsheet extends SheetComponent { checkOutOfViewBound: true, viewportKey: viewportInfo.viewportKey, viewBound: viewportInfo.cacheBound, + diffBounds: viewportInfo.diffBounds, } as IDrawInfo); this.addRenderFrameTimeMetricToScene(timeKey, Tools.now() - st, scene); } diff --git a/packages/engine-render/src/context.ts b/packages/engine-render/src/context.ts index 5377680f2c1b..e6bfcbe4f9df 100644 --- a/packages/engine-render/src/context.ts +++ b/packages/engine-render/src/context.ts @@ -210,13 +210,22 @@ export class UniverRenderingContext2D implements CanvasRenderingContext2D { this._context.direction = val; } - // font: string; get font() { - return this._context.font; + if (this._normalizedCachedFont) { + return this._normalizedCachedFont; + } + const fontStr = this._context.font; + this._normalizedCachedFont = fontStr; + return fontStr; } + _normalizedCachedFont: string; set font(val: string) { this._context.font = val; + // set font called too many times, even get font from context is time consuming. + // this.fontStyleStr = this._context.font; + // DO NOT use val to cachedStyleStr, Actual font string may change after set to context. + this._normalizedCachedFont = ''; } // fontKerning: CanvasFontKerning; @@ -862,6 +871,8 @@ export class UniverRenderingContext2D implements CanvasRenderingContext2D { * @method */ restore() { + this._transformCache = null; + this._normalizedCachedFont = ''; this._context.restore(); } @@ -930,6 +941,7 @@ export class UniverRenderingContext2D implements CanvasRenderingContext2D { setTransform(...args: [any]) { this._transformCache = null; + this._normalizedCachedFont = ''; this._context.setTransform(...args); } diff --git a/packages/sheets-ui/src/controllers/render-controllers/sheet.render-controller.ts b/packages/sheets-ui/src/controllers/render-controllers/sheet.render-controller.ts index 278075ea40c9..592f8600f1f7 100644 --- a/packages/sheets-ui/src/controllers/render-controllers/sheet.render-controller.ts +++ b/packages/sheets-ui/src/controllers/render-controllers/sheet.render-controller.ts @@ -16,7 +16,7 @@ import type { ICommandInfo, IRange, Nullable, Workbook, Worksheet } from '@univerjs/core'; import type { ISetFormulaCalculationNotificationMutation } from '@univerjs/engine-formula'; -import type { IAfterRender$Info, IBasicFrameInfo, IExtendFrameInfo, IRenderContext, IRenderModule, ISummaryFrameInfo, ITimeMetric, IViewportInfos, Scene } from '@univerjs/engine-render'; +import type { IAfterRender$Info, IBasicFrameInfo, IExtendFrameInfo, IRenderContext, IRenderModule, ISummaryFrameInfo, ISummaryMetric, ITimeMetric, IViewportInfos, Scene } from '@univerjs/engine-render'; import { CommandType, ICommandService, Inject, Optional, Rectangle, RxDisposable } from '@univerjs/core'; import { SetFormulaCalculationNotificationMutation } from '@univerjs/engine-formula'; import { @@ -46,9 +46,19 @@ interface ISetWorksheetMutationParams { subUnitId: string; } +export interface ITelemetryData { + unitId: string; + sheetId: string; + FPS: ISummaryMetric; + frameTime: ISummaryMetric; + elapsedTimeToStart: number; +} + const FRAME_STACK_THRESHOLD = 60; export class SheetRenderController extends RxDisposable implements IRenderModule { + private _renderMetric$: Subject = new Subject(); + renderMetric$ = this._renderMetric$.asObservable(); constructor( private readonly _context: IRenderContext, @Inject(SheetSkeletonManagerService) private readonly _sheetSkeletonManagerService: SheetSkeletonManagerService, @@ -57,7 +67,6 @@ export class SheetRenderController extends RxDisposable implements IRenderModule @Optional(ITelemetryService) private readonly _telemetryService?: ITelemetryService ) { super(); - this._addNewRender(); this._initRenderMetricSubscriber(); } @@ -94,8 +103,6 @@ export class SheetRenderController extends RxDisposable implements IRenderModule private _afterRenderMetric$: Subject = new Subject(); private _initRenderMetricSubscriber() { - if (!this._telemetryService) return; - const { engine } = this._context; engine.beginFrame$.subscribe(() => { @@ -139,14 +146,17 @@ export class SheetRenderController extends RxDisposable implements IRenderModule ...sceneRenderDetail.tags, }); if (frameInfoList.length > FRAME_STACK_THRESHOLD) { - this._renderMetricCapture(frameInfoList); + this._captureRenderMetric(frameInfoList); frameInfoList.length = 0; } }); } - private _renderMetricCapture(frameInfoList: IExtendFrameInfo[]) { - if (!this._telemetryService) return; + /** + * Send render metric to telemetry service + * @param frameInfoList + */ + private _captureRenderMetric(frameInfoList: IExtendFrameInfo[]) { const filteredFrameInfo = frameInfoList;//.filter((info) => info.scrolling); if (filteredFrameInfo.length === 0) return; @@ -207,8 +217,10 @@ export class SheetRenderController extends RxDisposable implements IRenderModule const elapsedTimeToStart = filteredFrameInfo[filteredFrameInfo.length - 1].elapsedTime; const sheetId = this._context.unit.getActiveSheet().getSheetId(); const unitId = this._context.unit.getUnitId(); - const telemetryData = { sheetId, unitId, elapsedTimeToStart, ...summaryFrameStats }; - this._telemetryService.capture('sheet_render_cost', telemetryData); + const telemetryData: ITelemetryData = { sheetId, unitId, elapsedTimeToStart, ...summaryFrameStats }; + this._renderMetric$.next(telemetryData); + + this._telemetryService?.capture('sheet_render_cost', telemetryData); } private _addComponent(workbook: Workbook) { diff --git a/packages/sheets-ui/src/index.ts b/packages/sheets-ui/src/index.ts index 34cc9c262f5d..73251e720ef6 100644 --- a/packages/sheets-ui/src/index.ts +++ b/packages/sheets-ui/src/index.ts @@ -29,7 +29,7 @@ export { HeaderFreezeRenderController } from './controllers/render-controllers/f export { HeaderMoveRenderController } from './controllers/render-controllers/header-move.render-controller'; export { HeaderResizeRenderController } from './controllers/render-controllers/header-resize.render-controller'; export { SheetsScrollRenderController } from './controllers/render-controllers/scroll.render-controller'; -export { SheetRenderController } from './controllers/render-controllers/sheet.render-controller'; +export { type ITelemetryData, SheetRenderController } from './controllers/render-controllers/sheet.render-controller'; export { SheetUIController } from './controllers/sheet-ui.controller'; export { whenFormulaEditorActivated, whenSheetEditorFocused } from './controllers/shortcuts/utils'; export { getCoordByCell, getCoordByOffset, getSheetObject, getTransformCoord } from './controllers/utils/component-tools';