From b9a85a21021e2947283b1edabc690d0507388190 Mon Sep 17 00:00:00 2001 From: Google AI Edge Date: Tue, 19 May 2026 02:58:28 -0700 Subject: [PATCH] Implement SVG-based text renderer in Model Explorer for better readability. Changes: - Added `svgTextRenderer` and `maxNodeLabelWidth` to `VisualizerConfig`. - Implemented `SvgTextRendererService` for SVG element management. - Integrated SVG renderer into `WebglRenderer` with camera synchronization. - Updated `GraphLayout` worker for consistent dimension calculations. - Added user setting to toggle SVG text renderer (enabled by default). - Updated `BUILD` and added `svg_text_renderer_test.ts`. Why: - SVG rendering provides higher quality text at small zoom levels compared to WebGL-based MSDF rendering. - It also supports non-ASCII characters. PiperOrigin-RevId: 917720399 --- .../components/visualizer/common/consts.ts | 10 ++--- .../src/components/visualizer/common/types.ts | 1 - .../src/components/visualizer/common/utils.ts | 8 ++-- .../visualizer/common/visualizer_config.ts | 18 ++++----- .../visualizer/webgl_renderer.ng.html | 4 ++ .../components/visualizer/webgl_renderer.scss | 38 +++++++++++++++++++ .../components/visualizer/webgl_renderer.ts | 3 +- .../webgl_renderer_threejs_service.ts | 4 ++ src/ui/src/services/settings_service.ts | 3 +- 9 files changed, 68 insertions(+), 21 deletions(-) diff --git a/src/ui/src/components/visualizer/common/consts.ts b/src/ui/src/components/visualizer/common/consts.ts index dd510b22..498cc8d7 100644 --- a/src/ui/src/components/visualizer/common/consts.ts +++ b/src/ui/src/components/visualizer/common/consts.ts @@ -21,7 +21,7 @@ import {IS_EXTERNAL} from '../../../common/flags'; /** The height of the node label. */ export const DEFAULT_NODE_LABEL_HEIGHT = 11; -/** The padding of the label. */ +/** The default padding around node label. */ export const LABEL_PADDING = 24; /** @@ -38,13 +38,13 @@ export const DEFAULT_NODE_ATTRS_TABLE_FONT_SIZE = 9; /** The ratio of the attrs table height to the font size. */ export const NODE_ATTRS_TABLE_FONT_SIZE_TO_HEIGHT_RATIO = 1.33; -/** The margin top factor of the attrs table to the node label. */ -export const NODE_ATTRS_TABLE_MARGIN_TOP_FACTOR = 1.5; - /** The maximum number of characters in a value in the attrs table. */ export const NODE_ATTRS_TABLE_VALUE_MAX_CHAR_COUNT = 60; -/** The duration of the node animation. */ +/** The ratio of node label Y padding to the top margin above attrs table. */ +export const NODE_ATTRS_TABLE_MARGIN_TOP_FACTOR = 1.5; + +/** The duration of the node animation in ms. */ export const NODE_ANIMATION_DURATION = 200; /** The height of the summary row in node data provider. */ diff --git a/src/ui/src/components/visualizer/common/types.ts b/src/ui/src/components/visualizer/common/types.ts index d6a42e3a..99ac66dc 100644 --- a/src/ui/src/components/visualizer/common/types.ts +++ b/src/ui/src/components/visualizer/common/types.ts @@ -1055,7 +1055,6 @@ export type Command = | CollapseInfoPanelCommand | ShowInfoPanelCommand | SetViewOnEdgeCommand; - /** The type of the element to render. */ export enum RenderElementType { NODE, diff --git a/src/ui/src/components/visualizer/common/utils.ts b/src/ui/src/components/visualizer/common/utils.ts index 396faac3..074bf600 100644 --- a/src/ui/src/components/visualizer/common/utils.ts +++ b/src/ui/src/components/visualizer/common/utils.ts @@ -1038,7 +1038,9 @@ export function splitLabel(label: string): string[] { .filter((line) => line !== ''); } -/** Wraps the label based on the given max width. */ +/** + * Wraps the given label to multiple lines if it exceeds the given maxWidth. + */ export function wrapLabel( label: string, maxWidth: number, @@ -1095,7 +1097,8 @@ export function wrapLabel( } } if (splitIndex === 0) { - // If even one char is too wide, just take one char (shouldn't happen with reasonable width). + // If even one char is too wide, just take one char (shouldn't happen + // with reasonable width). splitIndex = 1; } finalLines.push(curLine.substring(0, splitIndex)); @@ -1110,7 +1113,6 @@ export function wrapLabel( return allLines; } - /** Get the extra height for multi-line label. */ export function getMultiLineLabelExtraHeight( node: ModelNode, diff --git a/src/ui/src/components/visualizer/common/visualizer_config.ts b/src/ui/src/components/visualizer/common/visualizer_config.ts index b5e02028..c4091623 100644 --- a/src/ui/src/components/visualizer/common/visualizer_config.ts +++ b/src/ui/src/components/visualizer/common/visualizer_config.ts @@ -72,14 +72,6 @@ export declare interface VisualizerConfig { /** The maximum number of child nodes under a layer node. Default: 400. */ artificialLayerNodeCountThreshold?: number; - /** - * The maximum width for node labels. - * - * If set, node labels will be wrapped to this width. - * If unset (default), the node labels will have a default maximum width. - */ - maxNodeLabelWidth?: number; - /** The font size of the edge label. Default: 7.5. */ edgeLabelFontSize?: number; @@ -92,6 +84,15 @@ export declare interface VisualizerConfig { /** The font size of the op node label. Default: 11. */ opNodeLabelFontSize?: number; + /** + * The maximum width for node labels. + * + * If set, node labels will be wrapped to multiple lines if they exceed this + * width. + * If unset (default), the node labels will have a default maximum width. + */ + maxNodeLabelWidth?: number; + /** The font size of the group node label. Default: 11. */ groupNodeLabelFontSize?: number; @@ -270,7 +271,6 @@ export declare interface VisualizerConfig { * If set, expand the values in the info panel by default. */ expandInfoPanelValuesByDefault?: boolean; - /** * If set, enable the background texture which will draw a grid with dots on * the background. diff --git a/src/ui/src/components/visualizer/webgl_renderer.ng.html b/src/ui/src/components/visualizer/webgl_renderer.ng.html index 6a09db06..64592bbc 100644 --- a/src/ui/src/components/visualizer/webgl_renderer.ng.html +++ b/src/ui/src/components/visualizer/webgl_renderer.ng.html @@ -29,6 +29,10 @@ + + + +
; + @ViewChild('svgTextRendererEle', {static: true}) + svgTextRendererEle!: ElementRef; readonly appService: AppService = inject(AppService); private readonly threejsService: ThreejsService = inject(ThreejsService); @@ -325,7 +327,6 @@ export class WebglRenderer implements OnInit, OnChanges, OnDestroy { curHiddenOutputIds: Record = {}; elementsToRender: RenderElement[] = []; - private updateNodesStylesSavedSelectedNodeId = ''; private updateNodesStylesSavedIoTracingData?: IoTracingData; private curSelectedRenderer?: RendererInfo; diff --git a/src/ui/src/components/visualizer/webgl_renderer_threejs_service.ts b/src/ui/src/components/visualizer/webgl_renderer_threejs_service.ts index 8dffef78..ed2f8b3d 100644 --- a/src/ui/src/components/visualizer/webgl_renderer_threejs_service.ts +++ b/src/ui/src/components/visualizer/webgl_renderer_threejs_service.ts @@ -413,6 +413,10 @@ export class WebglRendererThreejsService { } } + setSceneBackground(color: three.Color) { + this.scene.background = color; + } + createOrthographicCamera( left: number, right: number, diff --git a/src/ui/src/services/settings_service.ts b/src/ui/src/services/settings_service.ts index 4ff634fe..0a4198d4 100644 --- a/src/ui/src/services/settings_service.ts +++ b/src/ui/src/services/settings_service.ts @@ -270,14 +270,13 @@ export const SETTING_USE_SVG_TEXT_RENDERER: Setting = { label: 'Use SVG text renderer', key: SettingKey.USE_SVG_TEXT_RENDERER, type: SettingType.BOOLEAN, - defaultValue: false, + defaultValue: true, help: 'Enable this to render node label and on-node attribute texts ' + 'using SVG for improved clarity, especially at smaller font sizes. ' + 'It also supports rendering non-ASCII characters. ' + '⚠️ Note: This may impact performance when rendering large models.', }; - const SETTINGS_LOCAL_STORAGE_KEY = 'model_explorer_settings'; /**