JavaScript is required

核心架构

目的与范围

本文档说明了 relation-graph 系统的基础架构,包括其类结构、核心设计模式和组件组织方式。它概述了系统如何在保持统一核心逻辑的同时实现框架无关性。

有关特定方面的详细信息:

架构概览

relation-graph 系统采用了核心-适配器架构,将与框架无关的图逻辑与特定平台的 UI 实现分离。该设计使单一代码库能够支持 Vue 2、Vue 3、React、Svelte 和 Web Components。

graph TB
    subgraph "核心层(框架无关)"
        CORE["RelationGraphCore
packages/relation-graph-models/models/RelationGraphCore.ts"] DATA_PROV["RGDataProvider
packages/relation-graph-models/data/RGDataProvider.ts"] TYPES["类型系统
packages/relation-graph-models/types.ts"] LAYOUTS["布局引擎
packages/relation-graph-models/layouts/*"] UTILS["工具集
packages/relation-graph-models/utils/*"] end subgraph "适配器层(平台特定)" DP_VUE2["RGDataProvider4Vue2"] DP_VUE3["RGDataProvider4Vue3"] DP_REACT["RGDataProvider4React"] DP_SVELTE["RGDataProvider4Svelte"] end subgraph "UI 层(框架组件)" VUE2_UI["Vue 2 组件
packages/platforms/vue2/"] VUE3_UI["Vue 3 组件
packages/platforms/vue3/"] REACT_UI["React 组件
packages/platforms/react/"] SVELTE_UI["Svelte 组件
packages/platforms/svelte/"] end CORE --> DATA_PROV CORE --> LAYOUTS CORE --> UTILS CORE --> TYPES DATA_PROV -.extends.-> DP_VUE2 DATA_PROV -.extends.-> DP_VUE3 DATA_PROV -.extends.-> DP_REACT DATA_PROV -.extends.-> DP_SVELTE DP_VUE2 --> VUE2_UI DP_VUE3 --> VUE3_UI DP_REACT --> REACT_UI DP_SVELTE --> SVELTE_UI VUE2_UI -.uses.-> CORE VUE3_UI -.uses.-> CORE REACT_UI -.uses.-> CORE SVELTE_UI -.uses.-> CORE

渐进增强继承模式

核心系统使用一种渐进增强模式,其中 RelationGraphCore 通过一条由专门化类组成的链来继承能力。每个 RelationGraphWithX 类都增加一组聚焦的能力。

graph TB
    RGB["RelationGraphBase
核心工具、事件、UUID 生成
packages/.../RelationGraphBase.ts"] RGB --> RGW1["RelationGraphWith1View
DOM 协调、坐标转换
packages/.../RelationGraphWith1View.ts"] RGW1 --> RGW2["RelationGraphWith2Data
响应式数据集成
setReactiveData4Vue2/Vue3/React/Svelte
packages/.../RelationGraphWith2Data.ts"] RGW2 --> RGW3O1["RelationGraphWith3Options1Update
选项管理、加载状态
_updateOptions, setCanvasOffset
packages/.../RelationGraphWith3Options1Update.ts"] RGW3O1 --> RGW3O2["RelationGraphWith3Options2API
选项 API,创建线/节点状态
getCreatingLine, getCreatingNode
packages/.../RelationGraphWith3Options2API.ts"] RGW3O2 --> RGW4["RelationGraphWith4Line
线路径生成
createLineDrawInfo, generateLinePath
packages/.../RelationGraphWith4Line.ts"] RGW4 --> RGW5["RelationGraphWith5Zoom
缩放操作
zoom, setZoom
packages/.../RelationGraphWith5Zoom.ts"] RGW5 --> RGW6E["RelationGraphWith6Effect
视觉效果、居中
zoomToFit, moveToCenter
packages/.../RelationGraphWith6Effect.ts"] RGW6E --> RGW6L["RelationGraphWith6Layout
布局算法
doLayout, createLayout
packages/.../RelationGraphWith6Layout.ts"] RGW6L --> RGW7["RelationGraphWith7Event
用户交互
onNodeClick, onNodeDragStart
packages/.../RelationGraphWith7Event.ts"] RGW7 --> RGW9["RelationGraphWith9EasyView
性能模式渲染
updateEasyView, evDrawNode
packages/.../RelationGraphWith9EasyView.ts"] RGW9 --> RGW91["RelationGraphWith91Editing
节点/线编辑
setEditingNodes, onResizeStart
packages/.../RelationGraphWith91Editing.ts"] RGW91 --> RGW92["RelationGraphWith92MiniView
小地图概览
updateMiniView, mvDrawNode
packages/.../RelationGraphWith92MiniView.ts"] RGW92 --> RGW93["RelationGraphWith93Image
图像生成准备
prepareForImageGeneration
packages/.../RelationGraphWith93Image.ts"] RGW93 --> RGW95["RelationGraphWith95Dom
DOM 观察器
setDom, initDom
packages/.../RelationGraphWith95Dom.ts"] RGW95 --> RGW99["RelationGraphWith99API
公共 API 表面
setJsonData, updateNode, getNodes
packages/.../RelationGraphWith99API.ts"] RGW99 --> CORE["RelationGraphCore
最终实例
ready, beforeUnmount
packages/.../RelationGraphCore.ts"] style RGB fill:#f9f9f9 style RGW2 fill:#f9f9f9 style RGW7 fill:#f9f9f9 style CORE fill:#e0e0e0

能力层

主要职责 关键方法
基础 RelationGraphBase 事件系统、UUID 生成 emitEvent(), generateNewUUID()
视图 RelationGraphWith1View 坐标变换 getCanvasXyByViewXy(), getViewXyByCanvasXy()
数据 RelationGraphWith2Data 框架响应式集成 setReactiveData4Vue2(), setReactiveData4React()
选项 RelationGraphWith3Options1Update 配置管理 _updateOptions(), setCheckedNode()
线绘制 RelationGraphWith4Line 线路径计算 createLineDrawInfo(), generateLinePath()
缩放 RelationGraphWith5Zoom 缩放操作 zoom(), setZoom()
效果 RelationGraphWith6Effect 视觉效果 zoomToFit(), moveToCenter()
布局 RelationGraphWith6Layout 布局算法 doLayout(), createLayout()
事件 RelationGraphWith7Event 用户交互处理 onNodeClick(), onNodeDragStart()
性能 RelationGraphWith9EasyView Canvas 渲染 updateEasyView(), evDrawNode()
编辑 RelationGraphWith91Editing 交互式编辑 setEditingNodes(), onResizeStart()
MiniView RelationGraphWith92MiniView 小地图渲染 updateMiniView(), mvDrawNode()
图像 RelationGraphWith93Image 图像导出准备 prepareForImageGeneration()
DOM RelationGraphWith95Dom DOM 观察 setDom(), initDom()
API RelationGraphWith99API 公共 API setJsonData(), getGraphJsonData()
核心 RelationGraphCore 实例生命周期 ready(), beforeUnmount()

核心组件

RelationGraphCore 实例

RelationGraphCore 是聚合所有能力的中央实例。每个 <RelationGraph /> 组件都会创建并绑定一个实例。

graph LR
    subgraph "RelationGraphCore 实例"
        CORE_INST["graphInstance
RelationGraphCore"] subgraph "内部组件" DP["dataProvider
RGDataProvider"] OPTIONS["options
RGOptionsFull"] LISTENERS["listeners
RGListeners"] EVENT_HANDLERS["eventHandlers
RGEventHandler[]"] end subgraph "DOM 引用" DOM["$dom
HTMLDivElement"] CANVAS_DOM["$canvasDom
HTMLDivElement"] end end CORE_INST --> DP CORE_INST --> OPTIONS CORE_INST --> LISTENERS CORE_INST --> EVENT_HANDLERS CORE_INST --> DOM CORE_INST --> CANVAS_DOM DP -.references.-> OPTIONS

关键实例属性:

属性 类型 用途
dataProvider RGDataProvider 管理图数据、节点、线
options RGOptionsFull 配置状态
listeners RGListeners 事件处理回调
eventHandlers RGEventHandler[] 自定义事件处理器
$dom HTMLDivElement 根容器元素
$canvasDom HTMLDivElement Canvas 容器元素
instanceId string 唯一实例标识符

RGDataProvider 系统

RGDataProvider 充当图数据的单一事实来源。特定平台的数据提供器通过扩展它来集成框架的响应式系统。

graph TB
    subgraph "基础数据提供器"
        BASE["RGDataProvider
基础数据管理
packages/.../data/RGDataProvider.ts"] BASE_PROPS["属性:
- graphData: RGGraphData
- options: RGOptionsFull
- commits: DataCommits
- nodeMap: Map
- linkMap: Map"] BASE --> BASE_PROPS end subgraph "平台适配器" VUE2_DP["RGDataProvider4Vue2
Vue.set() 集成
packages/.../data/RGDataProvider4Vue2.ts"] VUE3_DP["RGDataProvider4Vue3
ref() 存储
packages/.../data/RGDataProvider4Vue3.ts"] REACT_DP["RGDataProvider4React
setState() 钩子
packages/.../data/RGDataProvider4React.ts"] SVELTE_DP["RGDataProvider4Svelte
Svelte stores
packages/.../data/RGDataProvider4Svelte.ts"] end BASE -.extends.-> VUE2_DP BASE -.extends.-> VUE3_DP BASE -.extends.-> REACT_DP BASE -.extends.-> SVELTE_DP VUE2_DP --> VUE2_UPDATE["updateViewHook()
触发 Vue 2 响应式"] VUE3_DP --> VUE3_UPDATE["updateViewHook()
更新 ref() stores"] REACT_DP --> REACT_UPDATE["updateViewHook()
调用 setState()"] SVELTE_DP --> SVELTE_UPDATE["updateViewHook()
更新 Svelte stores"]

数据提供器方法:

// 核心数据访问
getNodes(): RGNode[]
getLines(): RGLine[]
getLinks(): RGLink[]
getNodeById(id: string): RGNode | undefined

// 数据操作
updateNode(nodeId: string, props: Partial<RGNode>): void
updateLine(lineId: string, props: Partial<RGLine>): void
addNodes(nodes: JsonNode[]): void
addLines(lines: JsonLine[]): void
removeNode(nodeId: string): void

// 状态管理
updateOptions(options: Partial<RGOptionsFull>): void
getOptions(): RGOptionsFull
dataUpdated(): void // 触发视图更新

数据流架构

系统实现了带有响应式更新的单向数据流。

graph TB
    subgraph "用户操作"
        USER["用户交互
点击、拖拽、缩放"] end subgraph "事件层" EVENTS["RelationGraphWith7Event
onNodeClick()
onNodeDragStart()
onLineClick()"] end subgraph "核心实例" CORE["RelationGraphCore
业务逻辑"] UPDATE_OPS["更新操作
updateNode()
updateLine()
updateOptions()"] end subgraph "数据提供器" DP["RGDataProvider
数据存储"] COMMITS["DataCommits
变更跟踪
- nodesListChanged
- linesListChanged
- changedNodes[]"] end subgraph "平台层" FW_DP["平台 DataProvider
Vue2/Vue3/React/Svelte"] STORES["响应式存储
- optionsStore
- nodesStore
- linesStore"] end subgraph "视图层" COMPONENTS["UI 组件
RGCanvas
RGNodePeel
RGLinePath"] DOM["渲染后的 DOM"] end USER -->|触发| EVENTS EVENTS -->|调用方法| CORE CORE -->|委托| UPDATE_OPS UPDATE_OPS -->|修改| DP DP -->|跟踪| COMMITS DP -->|调用 updateViewHook| FW_DP FW_DP -->|更新| STORES STORES -.reactive binding.-> COMPONENTS COMPONENTS -->|渲染| DOM DOM -.user interaction.-> USER

提交系统

数据提供器使用提交系统来跟踪变更,以优化更新:

interface DataCommits {
    nodesListChanged: boolean;      // 完整节点列表已更改
    linesListChanged: boolean;      // 完整线列表已更改
    changedNodes: RGNode[];         // 被修改的特定节点
    changedLines: RGLine[];         // 被修改的特定线
}

只有发生变更的数据才会触发响应式更新,从而避免不必要的重复渲染。

平台抽象层

该架构通过 updateViewHook 模式实现框架无关性。

graph LR
    subgraph "核心逻辑(框架无关)"
        CORE_METHOD["核心方法
updateNode()"] DP_UPDATE["RGDataProvider
updateNode()"] end subgraph "抽象点" HOOK["updateViewHook()
平台特定实现"] end subgraph "Vue 2 实现" VUE2_IMPL["RGDataProvider4Vue2
Vue.set(node, prop, value)"] end subgraph "Vue 3 实现" VUE3_IMPL["RGDataProvider4Vue3
ref.value = newValue"] end subgraph "React 实现" REACT_IMPL["RGDataProvider4React
setState(newState)"] end subgraph "Svelte 实现" SVELTE_IMPL["RGDataProvider4Svelte
store.set(newValue)"] end CORE_METHOD --> DP_UPDATE DP_UPDATE --> HOOK HOOK -.implements.-> VUE2_IMPL HOOK -.implements.-> VUE3_IMPL HOOK -.implements.-> REACT_IMPL HOOK -.implements.-> SVELTE_IMPL

平台特定初始化

每个平台初始化响应式的方式不同:

Vue 2:

// packages/relation-graph-models/models/RelationGraphWith2Data.ts:31-36
setReactiveData4Vue2(graphData, reactiveOptions, runtimeData, initRawPropertyFn)

Vue 3:

// packages/relation-graph-models/models/RelationGraphWith2Data.ts:44-60
setReactiveData4Vue3(dataStores, graphData, reactiveOptions, runtimeData, initRawPropertyFn)

React:

// packages/relation-graph-models/models/RelationGraphWith2Data.ts:68-78
setReactiveData4React(dataStores, updateViewHook)

Svelte:

// packages/relation-graph-models/models/RelationGraphWith2Data.ts:95-105
setReactiveData4Svelte(dataStores, updaters)

类型系统

类型系统为整个架构提供了强约束契约。

核心数据类型

类型 用途 位置
RGNode 带布局数据的运行时节点 packages/relation-graph-models/types.ts:245-275
JsonNode 可序列化节点 packages/relation-graph-models/types.ts:206-241
RGLine 运行时线 packages/relation-graph-models/types.ts:355-358
JsonLine 可序列化线 packages/relation-graph-models/types.ts:295-339
RGLink 带节点引用的线 packages/relation-graph-models/types.ts:371-380
RGOptions 用户配置 packages/relation-graph-models/types.ts:688
RGOptionsFull 完整配置 packages/relation-graph-models/types.ts:641-684
RelationGraphInstance 核心实例类型 packages/relation-graph-models/types.ts:30

类型关系

graph TB
    JSON_NODE["JsonNode
用户输入格式
可序列化"] RG_NODE["RGNode
运行时格式
+ lot (layout)
+ rgShouldRender
+ rgCalcedVisibility"] JSON_LINE["JsonLine
用户输入格式
from: string
to: string"] RG_LINE["RGLine
运行时格式
+ id
+ isReverse"] RG_LINK["RGLink
链接对象
+ fromNode: RGNode
+ toNode: RGNode
+ line: RGLine"] JSON_NODE -->|json2Node| RG_NODE RG_NODE -->|transNodeToJson| JSON_NODE JSON_LINE -->|json2Line| RG_LINE RG_LINE --> RG_LINK RG_NODE --> RG_LINK

事件系统

事件系统通过分层事件发射模型提供可扩展性。

graph TB
    subgraph "事件源"
        USER_ACTION["用户操作
例如,节点点击"] INTERNAL["内部事件
例如,布局完成"] end subgraph "事件发射(RelationGraphBase)" EMIT["emitEvent(eventName, ...args)"] DEFAULT["defaultEventHandler()
检查 listeners 属性"] CUSTOM["自定义事件处理器
eventHandlers: RGEventHandler[]"] HOOK["_emitHook
Vue emit 集成"] end subgraph "事件处理器" LISTENER["RGListeners
onNodeClick
onNodeDragStart
onLineClick
等等"] HANDLER["自定义处理器
addEventHandler(handler)"] end USER_ACTION --> EMIT INTERNAL --> EMIT EMIT --> DEFAULT EMIT --> CUSTOM EMIT --> HOOK DEFAULT --> LISTENER CUSTOM --> HANDLER

事件类型

// packages/relation-graph-models/types.ts
enum RGEventNames {
    onReady = "onReady",
    onNodeClick = "onNodeClick",
    onNodeDragStart = "onNodeDragStart",
    onNodeDragging = "onNodeDragging",
    onNodeDragEnd = "onNodeDragEnd",
    onLineClick = "onLineClick",
    onCanvasClick = "onCanvasClick",
    onNodeExpand = "onNodeExpand",
    onNodeCollapse = "onNodeCollapse",
    onZoomEnd = "onZoomEnd",
    // ... 更多
}

事件发射流程:

  1. 用户操作触发事件处理方法(例如 onNodeClick()
  2. 方法调用 emitEvent(RGEventNames.onNodeClick, node, e)
  3. 系统检查 defaultEventHandler() 中已注册的监听器
  4. 调用 eventHandlers 数组中的自定义事件处理器
  5. 调用 _emitHook 以进行框架集成(Vue emit)
  6. 如果提供了自定义结果则返回该结果,从而允许取消事件

关键设计模式

1. 通过继承实现渐进增强

每个 WithX 类增加一个关注点,从而形成清晰的职责分离。此模式:

  • 使代码库可测试(每一层可独立测试)
  • 支持部分功能采用
  • 明确依赖链

2. 核心-适配器模式

框架无关核心 + 平台特定适配器:

  • RelationGraphCore 不包含框架代码
  • 平台适配器(RGDataProvider4Vue2 等)处理响应式
  • UI 组件消费核心实例

3. 数据提供器作为单一事实来源

所有数据修改都通过 RGDataProvider

  • 集中式状态管理
  • 通过 commits 进行变更跟踪
  • 跨平台一致的 API

4. 用于 DOM 集成的观察者模式

RelationGraphWith95Dom 使用浏览器观察器:

  • ResizeObserver 用于元素尺寸变化
  • MutationObserver 用于 DOM 变更
  • 将 DOM 监控与业务逻辑解耦

5. 用于布局的工厂模式

createLayout() 实例化布局算法:

  • RGTreeLayoutRGForceLayoutRGCircleLayout
  • 可插拔布局系统
  • 配置驱动的选择

该架构使 relation-graph 能够在支持多个框架的同时维护单一代码库,从而同时实现代码复用和平台原生的响应式模式。渐进增强模式使功能扩展时的复杂度保持可控,而核心-适配器模式则确保图逻辑与 UI 集成之间的清晰分离。