LogicFlow 渲染与数据:render、getGraphData 与 adapterIn/adapterOut 数据适配器全解析
【免费下载链接】LogicFlowA flow chart editing framework focus on business customization. 专注于业务自定义的流程图编辑框架,支持实现脑图、ER图、UML、工作流等各种图编辑场景。项目地址: https://gitcode.com/GitHub_Trending/lo/LogicFlow
本指南聚焦 LogicFlow 实例层的渲染入口与图数据读写能力,围绕render、renderRawData、getGraphData、getGraphRawData、clearData五个核心方法,以及adapterIn/adapterOut两个数据适配器接口,讲解如何在接入业务系统时完成"业务数据 → LogicFlow 标准数据"的双向转换。读完本文,你将掌握 LogicFlow 图数据的渲染时机、读取方式、清空策略,以及如何用适配器无缝对接任意第三方流程数据格式。
数据读写全景:谁负责渲染,谁负责导出
在 LogicFlow.tsx 中,实例的渲染与数据读取能力由一组对称的方法构成,它们围绕两个概念展开:
- LogicFlow 原生数据(Raw Data):即
GraphData,由nodes与edges数组组成,是画布内部模型(Model)直接使用的数据结构。 - 业务数据(Biz Data):接入方系统自身定义的流程数据格式,例如 BPMN XML、自研审批流 JSON 等。
四组核心 API 的对应关系如下:
| 操作方向 | 经过适配器 | 不经过适配器 |
|---|---|---|
| 写入(渲染) | render(graphData) | renderRawData(graphData) |
| 读取(导出) | getGraphData(...params) | getGraphRawData() |
| 清空 | clearData()(内部强制触发一次空渲染) | — |
render:渲染入口与 adapterIn 转换
签名与行为
render(graphData: unknown): voidrender是渲染图数据的标准入口。当实例配置了adapterIn时,传入的数据会先经过adapterIn转换为 LogicFlow 原生数据,再渲染;未配置时则直接按 LogicFlow 标准格式渲染。
参数说明
| 名称 | 类型 | 必传 | 说明 |
|---|---|---|---|
graphData | unknown | 是 | 图数据,格式取决于是否配置了adapterIn。未配置时需符合 LogicFlow 标准格式;已配置时可以是任意业务数据结构。 |
基础示例:直接渲染标准格式
lf.render({ nodes: [{ id: 'node_1', type: 'rect', x: 120, y: 100 }], edges: [], });底层实现链路
从源码看,render的实现非常清晰(LogicFlow.tsx):
render(graphData: GraphConfigData) { let graphRawData = cloneDeep(graphData) if (this.adapterIn) { graphRawData = this.adapterIn(graphRawData) } this.renderRawData(graphRawData) }有两个细节值得注意:
- 数据先做深拷贝:
render首先对传入数据执行cloneDeep,避免外部对象被内部模型直接引用而相互污染。尤其当接入 Vue 这类对数据做响应式代理(Observe)的框架时,这一步至关重要——formatData工具(compatible.ts)通过JSON.parse(JSON.stringify(data))将带代理的对象转为纯对象,注释中特别说明该实现是"对数据实现兼容处理"。 - 委托给
renderRawData:render本身不直接操作画布,而是把转换后的数据交给renderRawData统一处理,保证"带适配器渲染"与"原生渲染"最终走同一条渲染管线。
renderRawData:跳过适配器的原生渲染
renderRawData(graphData: GraphData): voidrenderRawData直接渲染 LogicFlow 原生图数据,不经过adapterIn转换。当你手里的数据已经是标准GraphData结构时,应优先使用它,避免被适配器二次转换。
参数说明
| 名称 | 类型 | 必传 | 说明 |
|---|---|---|---|
graphData | GraphData | 是 | LogicFlow 原生图数据。 |
示例
lf.renderRawData({ nodes: [{ id: 'node_1', type: 'rect', x: 120, y: 100 }], edges: [], });渲染管线的关键环节
renderRawData是真正触及画布模型的方法(LogicFlow.tsx),其调用链为:
graphDataToModel:将图数据转换为内部 Model。在 GraphModel.ts 中,该方法会先清空已有的elementsModelMap、nodeModelMap、edgeModelMap,再根据graphData.nodes通过getModelAfterSnapToGrid生成节点模型、根据graphData.edges通过getModel(edge.type ?? currEdgeType)生成边模型;若边类型未注册会直接抛错找不到${edge.type}对应的边。。- 历史记录监听:当
options.history !== false时,调用history.watch(this.graphModel),使渲染后的操作进入撤销/重做栈。 - Preact 渲染
<Graph>组件:将图模型注入视图层完成绘制。 - 触发
GRAPH_RENDERED事件:渲染完成后 emitEventType.GRAPH_RENDERED,事件负载中包含data(当前图数据)与graphModel,供插件与业务方监听渲染完成时机。
getGraphData:读取图数据与 adapterOut 转换
签名与行为
getGraphData(...params: any[]): GraphConfigData | unknown获取当前图数据。当配置了adapterOut时,返回值会先经过适配器转换为业务数据;未配置时返回 LogicFlow 标准格式的GraphConfigData。
参数说明
| 名称 | 类型 | 必传 | 说明 |
|---|---|---|---|
...params | any[] | 否 | 透传给adapterOut的额外参数。 |
返回值
- 未配置
adapterOut:返回GraphConfigData; - 已配置
adapterOut:返回适配后的业务数据(unknown)。
示例
// 未配置 adapterOut 时,params 无实际作用 const data = lf.getGraphData(['property1', 'property2']);底层实现:params 的透传机制
源码实现(LogicFlow.tsx):
getGraphData(...params: any): GraphData | unknown { const data = this.getGraphRawData() if (this.adapterOut) { return this.adapterOut(data, ...params) } return data }getGraphData始终先通过getGraphRawData()拿到当前原生数据,再决定是否交给adapterOut处理;...params会被原样展开透传给adapterOut,这正是官方示例中通过getGraphData(['property1', 'property2'])向适配器传递"需要保留的字段列表"等业务参数的实现基础。
GraphConfigData 与 GraphData 的区别
GraphConfigData(MainTypes.zh.md):渲染入口使用的数据,nodes为NodeConfig[] | undefined,edges为EdgeConfig[] | undefined;GraphData(MainTypes.zh.md):导出时的数据类型,nodes为NodeData[],edges为EdgeData[],两者都包含完整的节点/边配置信息。
getGraphRawData:不受适配器影响的原生导出
getGraphRawData(): GraphData获取当前图的 LogicFlow 原生数据,不受adapterOut影响。无论实例是否配置了输出适配器,返回值始终是标准GraphData结构。
返回值
GraphData:由nodes与edges两个数组构成的标准图数据。
示例
const rawData = lf.getGraphRawData(); console.log(rawData.nodes, rawData.edges);实现与使用建议
源码仅一行(LogicFlow.tsx):
getGraphRawData(): GraphData { return this.graphModel.modelToGraphData() }modelToGraphData(GraphModel.ts)遍历画布上的边与节点,调用各自的getData()收集数据,并自动过滤掉virtual(虚拟)边。官方源码注释对此有明确建议:
注意:
getGraphData返回的数据受到 adapter 影响,所以其数据格式不一定是 LogicFlow 内部图数据格式。如果实现通用插件,请使用getGraphRawData。
这意味着通用插件、历史快照、复制粘贴等需要"标准格式"场景一律应使用getGraphRawData,而面向具体业务方(如保存到后端)才使用getGraphData。
clearData:清空画布
clearData(): void清空当前画布中的全部节点和边数据。
示例
lf.clearData();底层实现:为何要"强制刷新"
源码实现(LogicFlow.tsx):
clearData() { this.graphModel.clearData() // 强制刷新数据, 让 preact 清除对已删除节点的引用 this.render({}) }这里有两个关键步骤:
graphModel.clearData()(GraphModel.ts)清空模型层维护的节点与边;- 随后调用
render({})强制触发一次空渲染——注释明确指出,这是为了让Preact 清除对已删除节点的引用,防止 DOM 层残留对旧元素的引用。
因此在清理后,画布会恢复为空白状态,且渲染管线(含GRAPH_RENDERED事件)会再次走通,便于业务方统一监听。
adapterIn:输入数据适配器
adapterIn?: (data: unknown) => GraphData自定义输入数据适配函数,用于在render前把业务数据转换为 LogicFlow 原生数据。只要在实例上赋值了该函数,之后每次调用render传入的数据都会被它先转换一次。
返回值
GraphData:转换后的标准图数据。
示例
lf.adapterIn = (bizData) => { // 将业务结构转换成 nodes / edges return { nodes: [], edges: [], }; };声明位置与设计意图
adapterIn与adapterOut是定义在 LogicFlow 实例类上的可选实例属性(LogicFlow.tsx),类注释中写明了其设计初衷:
自定义数据转换方法。当接入系统格式和 LogicFlow 数据格式不一致时,可自定义此方法来进行数据格式转换。
也就是说,adapterIn面向的是"系统数据 → LogicFlow 标准数据"这一转换方向。常见的实战场景包括:
- 将后端存储的 JSON 审批流结构映射为
nodes/edges; - 将 BPMN XML 解析后的对象树转换为 LogicFlow 节点与连线。
注意:adapterIn是实例属性而非构造参数,需要在创建实例后、调用render前赋值;若要构建可复用的数据格式接入能力,可结合 bpmn-adapter 这类官方扩展了解更完整的适配实现。
adapterOut:输出数据适配器
adapterOut?: (data: GraphConfigData, ...params: any[]) => unknown自定义输出数据适配函数,用于在getGraphData时把 LogicFlow 原生数据转换为业务数据。
参数说明
| 名称 | 类型 | 必传 | 说明 |
|---|---|---|---|
data | GraphConfigData | 是 | 当前图数据。 |
...params | any[] | 否 | 来自getGraphData(...params)的透传参数。 |
示例
lf.adapterOut = (data, reserveFields = []) => { return { processNodes: data.nodes, processEdges: data.edges, reserveFields, }; };典型用法:业务字段透传
...params的存在让输出适配器具备了极大的灵活性。典型场景是:业务方在保存流程图时需要附带额外字段,此时可以通过getGraphData将字段列表透传进adapterOut,适配器再把这些字段并入返回结果:
// 保存时获取带业务字段的流程数据 const bizData = lf.getGraphData(['owner', 'version']);结合源码实现可以看出,adapterOut的参数data实际来自getGraphRawData()的返回值,因此业务方拿到的永远是"当前画布的最新数据",无需关心内部 Model 的维护细节。
四个核心方法与适配器组合使用示例
将上述 API 组合起来,即可实现一个完整的"业务数据渲染 → 编辑 → 业务数据导出"闭环:
import LogicFlow from '@logicflow/core'; // 1. 定义输入适配器:后端 JSON → LogicFlow 标准数据 lf.adapterIn = (bizData) => { return { nodes: bizData.processNodes.map((n) => ({ id: n.id, type: n.nodeType, x: n.x, y: n.y, text: n.label, properties: n.props, })), edges: bizData.processEdges.map((e) => ({ sourceNodeId: e.from, targetNodeId: e.to, type: e.edgeType || 'polyline', })), }; }; // 2. 定义输出适配器:LogicFlow 标准数据 → 后端 JSON lf.adapterOut = (data, reserveFields = []) => ({ processNodes: data.nodes, processEdges: data.edges, reserveFields, }); // 3. 渲染业务数据(自动经过 adapterIn) lf.render(backendBizData); // 4. 读取原生数据(跳过适配器,适合通用逻辑) const raw = lf.getGraphRawData(); // 5. 读取业务数据(自动经过 adapterOut,可透传字段) const saveData = lf.getGraphData(['owner']); // 6. 清空画布 lf.clearData();小结
- 渲染入口:
render支持 adapterIn 转换后渲染,renderRawData直通原生数据;两者最终都汇聚到同一条graphDataToModel → Preact 渲染 → GRAPH_RENDERED管线。 - 数据读取:
getGraphData可透传参数给adapterOut,适合业务导出;getGraphRawData返回标准GraphData,适合插件与通用逻辑。 - 适配器:
adapterIn/adapterOut是定义在实例上的可选函数属性,方向相反、职责对称,是 LogicFlow 与任意业务数据格式对接的关键扩展点。 - 清空:
clearData在清理模型后还会强制执行一次空渲染,以确保视图层引用被正确回收。
相关参考文档:MainTypes.zh.md 类型说明、核心实现 LogicFlow.tsx、GraphModel.ts。
【免费下载链接】LogicFlowA flow chart editing framework focus on business customization. 专注于业务自定义的流程图编辑框架,支持实现脑图、ER图、UML、工作流等各种图编辑场景。项目地址: https://gitcode.com/GitHub_Trending/lo/LogicFlow
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考