渲染系统
目的与范围
渲染系统负责将图数据(节点、线和连接)转换为屏幕上显示的可视化元素。该系统同时管理基于 SVG 的 DOM 渲染与基于 Canvas 的性能渲染,协调多层视觉合成,并通过视口裁剪为大规模图优化渲染性能。
本页面提供渲染系统的架构概览。关于具体子系统的详细信息,请参见:
- 线渲染与路径生成:线渲染系统
- 连接点计算:连接点(Junction Points)与路径计算
- Canvas 组件架构:Canvas 渲染与 RGCanvas
- 性能优化:性能模式与 EasyView
关于在渲染之前定位节点的布局算法,请参见布局系统。关于渲染元素上的事件处理,请参见用户交互与事件。
渲染架构概览
graph TB
subgraph "数据层"
GraphData["RGGraphData
(nodes, lines)"]
Options["RGOptionsFull
(rendering config)"]
ShouldRender["shouldRenderNodes
shouldRenderLines
(viewport culling)"]
end
subgraph "核心渲染逻辑"
With4Line["RelationGraphWith4Line
createLineDrawInfo()"]
PathGen["线路径生成器
generateLineFor1/4/44/49/6/8"]
JunctionCalc["_getJunctionPoint()
RGGraphMath utilities"]
end
subgraph "组件层"
RGCanvas["RGCanvas
(container)"]
RGCanvasContent["RGCanvasContent
(orchestrates rendering)"]
RGNode["RGNode
(node display)"]
RGLinePath["RGLinePath
(SVG path)"]
RGLineText["RGLineText
(text labels)"]
end
subgraph "渲染模式"
StandardMode["标准 SVG 渲染
(zoom >= 40%)"]
EasyViewMode["EasyView Canvas
(zoom < 40%)"]
end
subgraph "输出层"
BehindLayer["Behind 层
(background plugins)"]
MainLayer["主画布
(nodes & lines)"]
AboveLayer["Above 层
(overlays)"]
end
GraphData --> ShouldRender
Options --> ShouldRender
ShouldRender --> RGCanvasContent
RGCanvasContent --> With4Line
With4Line --> PathGen
With4Line --> JunctionCalc
PathGen --> RGLinePath
JunctionCalc --> RGLinePath
RGCanvasContent --> RGNode
RGCanvasContent --> RGLinePath
RGCanvasContent --> RGLineText
RGCanvas --> BehindLayer
RGCanvas --> MainLayer
RGCanvas --> AboveLayer
MainLayer --> StandardMode
MainLayer --> EasyViewMode
RGNode --> MainLayer
RGLinePath --> MainLayer
RGLineText --> MainLayer图:整体渲染系统架构
渲染系统遵循三层架构:
- 数据层:图数据与配置驱动需要渲染的内容
- 核心逻辑:路径生成与几何计算产出渲染指令
- 组件层:框架特定组件渲染可视化元素
来源:packages/relation-graph-models/models/RelationGraphWith4Line.ts:1-572, packages/platforms/vue2/src/core4vue/RGLinePath.vue:1-104, packages/platforms/react/src/relation-graph/src/core4react/RGCanvas.tsx:1-114
渲染模式
系统支持两种主要渲染模式,会根据缩放级别与性能需求进行选择:
标准 SVG/DOM 渲染
默认渲染模式使用 SVG 元素绘制线条,并使用 DOM 元素绘制节点。这提供了:
- 完整的交互能力(点击、悬停、拖拽事件)
- 在所有缩放级别下清晰锐利的渲染效果
- CSS 样式与动画
- 基于插槽(slot)的自定义
使用时机:当 options.canvasZoom >= 40 或 options.performanceMode 被禁用时。
EasyView Canvas 模式
一种性能优化模式,使用 HTML5 Canvas 2D 上下文进行渲染:
- 面向大图的更低内存占用
- 对数百个节点具备更快的渲染速度
- 交互受限(通过坐标映射检测点击)
- 在低缩放级别下自动启用
使用时机:当 options.canvasZoom < 40 且 options.performanceMode 启用时,或通过 options.showEasyView 显式启用时。
graph LR
ZoomCheck{"canvasZoom >= 40?"}
PerfCheck{"performanceMode enabled?"}
SVGRender["标准 SVG 渲染"]
CanvasRender["EasyView Canvas"]
ZoomCheck -->|Yes| SVGRender
ZoomCheck -->|No| PerfCheck
PerfCheck -->|Yes| CanvasRender
PerfCheck -->|No| SVGRender图:渲染模式选择逻辑
来源:packages/relation-graph-models/models/RelationGraphWith2Data.ts:1-125, packages/platforms/react/src/relation-graph/src/core4react/RGCanvas.tsx:22-42
组件层级结构
渲染系统通过一组框架特定组件的层级结构实现,这些组件共享通用接口:
graph TB
RGCanvas["RGCanvas
Main container, layers, zoom/pan transform"]
RGCanvasContent["RGCanvasContent
Iterates nodes/lines, applies viewport culling"]
RGNode["RGNode
Individual node display"]
RGLinePath["RGLinePath
SVG path for line"]
RGLineText["RGLineText
Text label via teleport"]
RGConnectTarget["RGConnectTarget
Connection points for drag"]
RGEasyView["RGEasyView
Canvas fallback renderer"]
RGCanvas --> RGCanvasContent
RGCanvas --> RGEasyView
RGCanvasContent --> RGNode
RGCanvasContent --> RGLinePath
RGCanvasContent --> RGLineText
RGNode --> RGConnectTarget图:渲染组件层级结构
| 组件 | 目的 | 文件位置 |
|---|---|---|
RGCanvas |
根容器,管理图层与画布变换 | vue2/RGCanvas.vue, vue3/RGCanvas.vue, react/RGCanvas.tsx, svelte/RGCanvas.svelte |
RGCanvasContent |
渲染过滤后的节点与线条,编排子组件 | vue2/RGCanvasContent.vue, vue3/RGCanvasContent.vue, etc. |
RGNode |
显示单个节点,可选插槽 | vue2/RGNode.vue, vue3/RGNode.vue, etc. |
RGLinePath |
为线条渲染 SVG <path> 元素 |
vue2/RGLinePath.vue, vue3/RGLinePath.vue, etc. |
RGLineText |
使用 teleport/portal 渲染线条文本标签 | vue2/RGLineText.vue, vue3/RGLineText.vue, etc. |
RGEasyView |
性能模式下的基于 Canvas 的渲染器 | vue2/RGEasyView.vue, vue3/RGEasyView.vue, etc. |
来源:packages/platforms/vue3/src/relation-graph/src/core4vue3/RGCanvas.vue:1-86, packages/platforms/react/src/relation-graph/src/core4react/RGCanvas.tsx:1-114, packages/platforms/svelte/src/core4svelte/RGCanvas.svelte:1-89
渲染流水线
flowchart TD
DataUpdate["Graph Data Updated
addNode(), updateLine()"]
DataProvider["RGDataProvider
commits changes"]
RequestFrame["_dataUpdated()
requestAnimationFrame"]
ViewportCulling["updateShouldRenderGraphData()
filters visible items"]
RenderCheck{"Rendering Mode?"}
SVGPath["SVG Rendering Path"]
CanvasPath["Canvas Rendering Path"]
CreateLineInfo["createLineDrawInfo()
RelationGraphWith4Line"]
GeneratePath["generateLinePath()
withLineJunctionPoints()"]
PathCalculation["createLinePathData()
generateLineFor1/4/44/49/6/8"]
ComponentRender["Component Render
RGLinePath, RGNode"]
CanvasRender["Canvas 2D Context
drawImage(), fillRect()"]
DOMUpdate["DOM Updated
Browser paints"]
DataUpdate --> DataProvider
DataProvider --> RequestFrame
RequestFrame --> ViewportCulling
ViewportCulling --> RenderCheck
RenderCheck -->|Standard| SVGPath
RenderCheck -->|EasyView| CanvasPath
SVGPath --> CreateLineInfo
CreateLineInfo --> GeneratePath
GeneratePath --> PathCalculation
PathCalculation --> ComponentRender
ComponentRender --> DOMUpdate
CanvasPath --> CanvasRender
CanvasRender --> DOMUpdate图:渲染流水线流程
流水线关键阶段
- 数据更新:应用调用
addNodes(),updateNode(),addLines()等方法 - 数据提供者:变更被批处理并提交到响应式状态
- 帧请求:
_dataUpdated()调度一个requestAnimationFrame回调 - 视口裁剪:
updateShouldRenderGraphData()基于画布偏移与视口大小过滤可见项 - 模式选择:根据缩放与设置选择标准 SVG 或 EasyView canvas
- 路径生成:对于线条,
RelationGraphWith4Line生成 SVG 路径数据 - 组件渲染:框架组件使用响应式数据进行渲染
- 浏览器绘制:原生浏览器渲染完成该帧
来源:packages/relation-graph-models/models/RelationGraphWith4Line.ts:80-114, packages/relation-graph-models/models/RelationGraphWith7Event.ts:1-870
线条渲染概览
线条以 SVG <path> 元素渲染,并支持多种形状:
| 线条形状 | 代码值 | 描述 | 生成函数 |
|---|---|---|---|
| 直线 | 1 |
从起点到终点的直接连线 | generateLineFor1() |
| 简单正交 | 4 |
基本直角连接 | generateLineFor4() |
| 标准正交 | 44 |
具备多个分段的智能正交 | generateLineFor44() |
| 硬正交 | 49 |
用户可调整的正交分段 | generateLineFor49() |
| 标准曲线 | 6 |
贝塞尔曲线连接 | generateLineForCurve6() |
| 曲线变体 | 2, 3, 5, 7 |
不同的曲线样式 | generateLineForCurve() |
| 特殊曲线 | 8 |
另一种曲线算法 | generateLineFor8() |
线条渲染过程:
- 连接点计算:确定线条与节点边界连接的位置
- 路径生成:基于线条形状生成 SVG 路径命令
- 文本定位:计算文本标签的位置与旋转角度
- 箭头标记:应用 SVG marker 作为箭头
graph LR
Link["RGLink
(fromNode, toNode)"]
Line["RGLine
(style, shape)"]
CreateInfo["createLineDrawInfo()"]
WithJunction["withLineJunctionPoints()"]
GetJunction["_getJunctionPoint()"]
CreatePath["createLinePathData()"]
PathInfo["RGLinePathInfo
(pathData, textPosition)"]
Component["RGLinePath Component"]
Link --> CreateInfo
Line --> CreateInfo
CreateInfo --> WithJunction
WithJunction --> GetJunction
WithJunction --> CreatePath
CreatePath --> PathInfo
PathInfo --> Component图:线条渲染数据流
关于线条路径生成与连接点计算的详细信息,请参见线渲染系统与连接点(Junction Points)与路径计算。
来源:packages/relation-graph-models/models/RelationGraphWith4Line.ts:27-571, packages/platforms/vue2/src/core4vue/RGLinePath.vue:1-104, packages/platforms/react/src/relation-graph/src/core4react/RGLinePath.tsx:1-77
节点渲染
节点以 DOM 元素(通常为 <div> 元素)渲染,并在画布内以绝对定位方式放置:
关键节点属性:
- 位置:
node.x,node.y(画布坐标) - 尺寸:
node.width/node.el_W,node.height/node.el_H - 形状:
node.nodeShape(0=circle, 1=rect,默认来自 options) - 样式:
node.color,node.fontColor,node.borderColor,node.borderWidth
节点变换计算:
style.transform = `translate(${node.x}px, ${node.y}px)`
style.width = `${node.el_W}px`
style.height = `${node.el_H}px`
节点可通过以下方式自定义:
- 插槽内容:替换默认节点渲染
- CSS 变量:
--rg-node-color,--rg-node-border-color, etc. - 节点专属样式:
node.cssVars对象
连接目标:每个节点都可以显示用于交互式创建连线的连接点(RGConnectTarget)。这些连接点位于特定的连接位置(上、右、下、左、中)。
来源:packages/relation-graph-models/models/RelationGraphWith7Event.ts:80-190
多层渲染系统
画布使用三层架构以支持灵活的 z 轴顺序:
graph TB
Container["RGCanvas Container"]
subgraph "图层堆栈(从下到上)"
BackgroundSlot["背景插槽
(grid, watermark)"]
BehindLayer["Behind 层
canvas-plug-behind slot"]
MainCanvas["主画布
(nodes & lines)"]
AboveLayer["Above 层
canvas-plug-above slot"]
end
Container --> BackgroundSlot
Container --> BehindLayer
Container --> MainCanvas
Container --> AboveLayer
MainCanvas --> Nodes["已渲染节点"]
MainCanvas --> Lines["已渲染线条"]图:多层画布架构
图层用途
| 图层 | 用途 | CSS 类名 | 是否应用 Transform |
|---|---|---|---|
| 背景 | 静态背景内容 | .rg-map-background |
否 |
| Behind | 图内容下方的自定义内容 | .rg-canvas-slot-behind |
是(zoom/pan) |
| 主层 | 节点与线条 | .rg-map-canvas |
是(zoom/pan) |
| Above | 覆盖层(工具提示、控件) | .rg-canvas-slot-above |
是(zoom/pan) |
除 Background 外的所有图层共享同一变换:
transform: translate(${canvasOffset.x}px, ${canvasOffset.y}px)
scale(${canvasZoom / 100}, ${canvasZoom / 100})
这确保缩放与平移操作会一致地影响所有图内容,同时保持背景静止不动。
来源:packages/platforms/vue3/src/relation-graph/src/core4vue3/RGCanvas.vue:36-83, packages/platforms/react/src/relation-graph/src/core4react/RGCanvas.tsx:58-110, packages/platforms/svelte/src/core4svelte/RGCanvas.svelte:36-88
视口裁剪与性能
渲染系统实现了视口裁剪,以避免渲染屏幕外元素:
裁剪机制:
updateShouldRenderGraphData()计算可见视口边界- 过滤节点:只有处于视口 + 边距范围内的节点才会加入
shouldRenderNodes - 过滤线条:只有连接可见节点的线条才会加入
shouldRenderLines - 组件仅遍历已过滤集合
性能收益:
- 为大图(1000+ 节点)减少 DOM 元素数量
- 在平移/缩放操作期间维持 60fps
- 随视口变化自动调整
EasyView Canvas 模式: 当启用性能模式且缩放低于 40% 时,系统会:
- 禁用精细的 SVG 渲染
- 将简化表示渲染到 canvas
- 通过坐标映射维持交互能力
关于详细的性能优化技术,请参见性能模式与 EasyView。
来源:packages/relation-graph-models/models/RelationGraphWith2Data.ts:31-110, packages/relation-graph-models/models/RelationGraphWith7Event.ts:332-338
框架特定实现
每个平台(Vue2、Vue3、React、Svelte)以各自框架特有的模式实现相同的渲染架构:
Vue 2 & 3:使用基于模板的组件与插槽
- 响应式:Vue 的响应式数据系统(refs/reactive)
- 插槽:
<slot name="node">,<slot name="line"> - Teleport:使用
<teleport>定位线条文本
React:使用 JSX 组件与 render props
- 响应式:
useState与useGraphStore自定义 hook - Children:render prop 函数或 React nodes
- Portal:使用
createPortal()定位线条文本
Svelte:使用 Svelte 组件与插槽
- 响应式:Svelte stores(
writable) - 插槽:
<slot name="node">,<svelte:fragment> - Portal:用于线条文本的自定义
portalaction
所有实现通过 types 包中定义的共享 TypeScript 接口保持 API 兼容性。
来源:packages/platforms/vue2/src/core4vue/RGLinePath.vue:59-100, packages/platforms/vue3/src/relation-graph/src/core4vue3/RGLinePath.vue:1-91, packages/platforms/react/src/relation-graph/src/core4react/RGLinePath.tsx:1-77, packages/platforms/svelte/src/core4svelte/RGLinePath.svelte:1-84
总结
渲染系统通过以下方式将图数据转换为可视化输出:
- 双渲染模式:标准 SVG 追求质量,Canvas 追求性能
- 基于组件的架构:框架特定实现共享核心逻辑
- 多层合成:为插件与覆盖层提供灵活的 z 顺序
- 视口裁剪:面向大图的性能优化
- 路径生成:支持多种线条形状与连接点类型
该系统旨在在不同规模与用例下平衡视觉质量、交互性与性能。