ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

用echarts graph画流程图:从数据可视化到交互实战指南

用echarts graph画流程图:从数据可视化到交互实战指南 “用 echarts 画流程图”这话放在三年前我自己都不信因为 echarts 在我印象里就是柱状图、饼图、折线图、地图这些东西的代名词。直到有一次做后台管理系统需要把用户注册审核的流程和数据可视化大屏塞进同一个页面既不想为了流程图单独引一套拖拽设计器又希望所有图表可以共用一套主题、一套点击交互我才认真把 echarts 的 graph 系列翻出来研究了一遍。实际折腾下来发现echarts 不仅能画流程图而且在数据驱动、联动交互这件事上很多时候比专业的流程图工具更顺手。这篇文章不是抄文档是我把项目里的真实案例拆开之后的完整复盘包括什么时候该用 echarts 画流程图、graph 系列的核心思路、一个从零开始的“用户注册审核流程图”以及适配大屏时的各类坑。内容偏实战适合已经会用 echarts 但没用 graph 画过流程图的人也适合正准备在毕设或后台系统里画一张动态流程图的同学。1. 先从需求聊起为什么偏偏用 echarts 画流程图1.1 流程图里的图形符号都有固定含义别用错很多人一上来就写代码结果画出来的东西叫“美术连线图”不叫流程图。流程图有约定俗成的图形语义这个在软件工程、数学建模、课程设计里都会被检查。最基本的几类图形含义典型场景椭圆/圆角矩形开始或结束流程起点、终止节点矩形处理步骤执行某个操作、赋值、计算菱形判断分支if/else、条件校验、审核平行四边形输入/输出读取数据、打印结果圆形/连接符页面内跳转避免跨页连线太长双杠矩形预定义过程/子流程调用子模块用 echarts 画流程图时很多人会忽略这一步直接用圆形表示“处理”用矩形表示“判断”别人看懂要靠猜。实际上 echarts 的 graph 系列提供了丰富的 symbol 类型circle、rect、roundRect、diamond、triangle等等足够覆盖流程图的常规需要。在画之前先想清楚你每个节点在上面这个表格里属于哪一类。1.2 技术选型对比专业流程图工具 vs echarts graph我在做选型的时候主要在两个方向之间犹豫一是引入 LogicFlow、X6、bpmn.js 这类专业图编排库二是用 echarts graph 硬画。对比下来结论其实很清晰维度echarts graph专业流程图库上手成本低只需配置 nodes 和 links中等需要理解 Model、Edge、Node 的生命周期拖拽编辑原生不支持需要自己开发内置拖拽、连线、锚点数据驱动非常直接setOption 全量更新依赖库内部数据模型增量更新灵活联动图表同生态坐标轴、提示框、主题天然统一一般要自己再封装自定义程度高动画、缩放、点击事件都现成高但很多功能要写插件大屏适配resize 后整体重绘效果稳定视库而定拖拽型编辑器在大屏里适配反而麻烦所以我的结论是如果只是“展示”一张流程而不是让人“编辑”流程echarts 完全够用而且更省事。如果是给业务人员做流程设计器需要拖拖拽拽、连连接点、保存画布数据那还是老老实实用 LogicFlow 或 bpmn.js 这类专业库。1.3 echarts 流程图适合什么人、什么项目从我实际接触过的需求来看下面这几类项目特别适合用 echarts 画流程图数据可视化大屏里的流程展示。节点旁边要挂实时指标比如“待审核人数 12”、“今日通过率 86%”echarts 的 label 和 tooltip 直接能绑定数据天然适合。后台管理系统里的模块关系图、用户流程说明页。不需要编辑只需要把逻辑讲清楚。课程设计、毕业设计里的系统流程图。用代码画出来可以直接嵌进网页比截图 Visio 更专业也好维护。和 echarts 已有的其他图表组合在一个页面保持技术栈统一。反过来说如果需求里有“用户要能自己拖拽节点、画连线、保存流程配置”这些字样那一开始就别选 echarts它不是一个图编辑框架别硬上。2. graph 系列用节点和边把流程图搭起来2.1 节点、边、布局三个关键概念echarts 的 graph 类型本质是图Graph模型核心概念就三个节点node、边edge/line、布局layout。节点用数组传进去每个节点至少有个id和name然后你可以给它叠一堆样式字段比如坐标、符号形状、大小、颜色。边用另一个数组传每条边指定source和target分别表示从哪个节点到哪个节点。理解了这个模型再看流程图就别把它当成“画图”了而是当成“填数据”const nodes [{ id: start, name: 开始 }, { id: end, name: 结束 }]; const links [{ source: start, target: end }];这个结构类似地铁线路图站点是节点站与站之间的线路是边。流程图里常见的“回退”“分支”“循环”本质上都是边的方向和条件不同而已。2.2 布局方式怎么选手中没有需求就别滥用 forcegraph 系列支持layout: force力导向、layout: circular环形、layout: none自定义布局三种模式。很多新手一上来就用 force因为不管什么数据它都会自动把节点摊开视觉上还挺有“关系图”的感觉。但流程图恰恰不能这么干。流程图的阅读顺序是强制的从上到下、从左到右判断分支的位置必须固定回退线必须清晰。force 布局会把节点“吸”到奇怪的位置还会在数据更新时产生抖动根本没法用。所以画流程图的通用做法是layout: none然后手动给每个节点指定x和y并设置fixed: true。这样 echarts 就不会去干预你的坐标。这里有个容易踩的坑即使你配置了 x/y如果忘了写fixed: truegraph 在有些版本里还是会认为坐标只是“初始位置”更新数据后就可能被重新排布。我在项目中吃过这个亏调试了半天才发现是 fixed 的问题。2.3 把流程图图例翻译成 configsymbol、label、线型、箭头理解了 graph 是数据驱动的接下来就是把流程图的图形语义映射到 echarts 的配置上。这个过程不需要死记硬背核心就四个点节点形状用symbol控制symbol: circle // 开始、结束 symbol: rect // 处理步骤 symbol: roundRect // 处理步骤更柔和 symbol: diamond // 判断节点大小用symbolSize控制symbolSize可以是数字也可以是数组[宽, 高]。矩形、菱形建议都用数组形式只给一个数字的话长宽相等写“处理步骤”这种字多的 label 很容易被截断。注意 diamond 的宽高指的是菱形外接矩形的宽高具体显示出来多少建议边调边看不要凭感觉。箭头和线型用edgeSymbollineStyle控制edgeSymbol: [none, arrow] // 起点无箭头、终点有箭头 lineStyle: { type: solid, // 默认流程用实线 curveness: 0 // 0为直线回退线可以设成0.2或0.3 }如果你想突出“回退”或“异常流”可以把线型设成dashed颜色换成红色视觉上一下就能区分开。判断分支的条件文字用边的label控制{ source: check, target: submit, label: { show: true, formatter: 通过 } }这个是在边上显示文字比如“通过”“驳回”“不通过”。graph 系列里这部分的字段叫label不是edgeLabel我见过有人照着折线图文档写edgeLabel导致不显示的情况。3. 实操写一个“用户注册审核流程图”3.1 先画一张纸面草图再列节点数据写代码之前我强烈建议先在纸上把这套流程的逻辑画出来否则写 links 的时候经常会把 source 和 target 搞反。我这边用一个用户注册审核的例子流程如下开始 → 填写注册信息 → 格式校验判断→ 校验不通过回到填写注册信息校验通过进入提交注册 → 管理员审核判断→ 审核通过开通账号审核不通过驳回回到填写注册信息 → 结束这个流程有判断、有回退、有分支用来演示 echarts 画流程图基本够用了。先把节点列出来idname符号含义start开始circle开始fill填写注册信息roundRect处理步骤check格式校验diamond判断submit提交注册roundRect处理步骤audit管理员审核diamond判断pass开通账号roundRect处理步骤reject驳回roundRect处理步骤end结束circle结束这一步就把“流程图的图形语义”和“数据模型”对应上了。后面写代码只是翻译。3.2 节点坐标与样式控制节点坐标我按 600 宽、700 高的画布来排垂直方向从上到下把流程主线铺开分支在左右两侧展开。具体坐标设计如下start: (300, 40)fill: (300, 140)check: (300, 260)submit: (300, 380)audit: (300, 500)pass: (180, 620)reject: (420, 620)end: (300, 720)为什么这么排主流程全部居中判断分支左右对称回退线才有空间画弧线不会和主线重叠。如果你把分支节点也排在中间回退线就会穿来穿去最后一张图根本没法看。节点配置示例{ id: check, name: 格式校验, symbol: diamond, symbolSize: [140, 70], x: 300, y: 260, fixed: true, label: { show: true, position: inside } }这里label默认在节点内部判断节点的字比较多可以用position: inside配合fontSize控制。如果菱形里放不下也可以放到外面比如position: right看具体设计。3.3 连线的细节分支、回退、曲线、边标签节点排好后连线是重点。流程图里大部分连线是直线但回退线必须用曲线否则会和主流程线重叠。echarts 的 graph 里通过lineStyle.curveness控制曲线程度curveness越大线越弯。再看分支条件。格式校验节点出去的两条线一条回到前面的fill节点一条去submit节点。光看线不够直观必须在线条上标注条件文字{ source: check, target: submit, label: { show: true, formatter: 通过, color: #27ae60 } }, { source: check, target: fill, label: { show: true, formatter: 不通过, color: #e74c3c }, lineStyle: { curveness: 0.2, type: dashed } }这样读图的人一眼就能看出来绿线是“通过”红色虚线是“不通过”回退方向是虚线逻辑跑得通。3.4 完整代码一个可运行的 echarts 配置把上面的节点和连线整合成一个完整的 option核心是 series 的类型设为graphconst option { tooltip: { trigger: item }, series: [{ type: graph, layout: none, roam: true, nodes: [ { id: start, name: 开始, symbol: circle, x: 300, y: 40, fixed: true, label: { show: true, position: bottom } }, { id: fill, name: 填写注册信息, symbol: roundRect, symbolSize: [160, 50], x: 300, y: 140, fixed: true, label: { show: true, position: inside } }, { id: check, name: 格式校验, symbol: diamond, symbolSize: [150, 70], x: 300, y: 260, fixed: true, label: { show: true, position: inside } }, { id: submit, name: 提交注册, symbol: roundRect, symbolSize: [160, 50], x: 300, y: 380, fixed: true, label: { show: true, position: inside } }, { id: audit, name: 管理员审核, symbol: diamond, symbolSize: [160, 70], x: 300, y: 500, fixed: true, label: { show: true, position: inside } }, { id: pass, name: 开通账号, symbol: roundRect, symbolSize: [160, 50], x: 180, y: 620, fixed: true, label: { show: true, position: inside } }, { id: reject, name: 驳回, symbol: roundRect, symbolSize: [140, 50], x: 420, y: 620, fixed: true, label: { show: true, position: inside } }, { id: end, name: 结束, symbol: circle, x: 300, y: 720, fixed: true, label: { show: true, position: bottom } } ], links: [ { source: start, target: fill }, { source: fill, target: check, label: { show: true, formatter: 提交, position: right } }, { source: check, target: submit, label: { show: true, formatter: 通过, color: #27ae60, position: right } }, { source: check, target: fill, label: { show: true, formatter: 不通过, color: #e74c3c, position: left }, lineStyle: { curveness: 0.2, type: dashed, color: #e74c3c } }, { source: submit, target: audit }, { source: audit, target: pass, label: { show: true, formatter: 通过, color: #27ae60, position: right } }, { source: audit, target: reject, label: { show: true, formatter: 驳回, color: #e74c3c, position: left }, lineStyle: { curveness: 0.2, type: dashed, color: #e74c3c } }, { source: reject, target: fill, label: { show: true, formatter: 重新填写, position: bottom }, lineStyle: { curveness: 0.3, type: dashed, color: #e74c3c } }, { source: pass, target: end } ] }] };直接把这段配置丢给一个初始化好的 echarts 实例刷新就能看到流程图。注意roam: true开了缩放和平移这对于节点数量多的流程特别有用不然画布放不下时只能干瞪眼。3.5 加上 interaction点击、缩放、tooltip 换行只是画出来肯定不够流程图最好能点、能看详情。点击节点的事件可以这样挂myChart.on(click, function (params) { if (params.dataType node) { const nodeData params.data; // 在这里根据 nodeData.id 去查详情、跳转页面、打开抽屉 } });注意dataType的取值节点是node边是edge。如果不判断点击连线时也会触发回调很容易误操作。tooltip 默认对于长文本不会自动换行如果节点要展示的详情特别长可以在 formatter 里手动处理tooltip: { trigger: item, formatter: function(params) { if (params.dataType node) { const desc params.data.desc || ; return params.data.name \n wrapText(desc, 20); } return ; } } function wrapText(text, maxLen) { const arr []; for (let i 0; i text.length; i maxLen) { arr.push(text.substring(i, i maxLen)); } return arr.join(\n); }这个wrapText是我实际项目里一直在用的工具函数很多后台页面都要求 tooltip 不要撑破屏幕手动换行比依赖 CSS 靠谱得多。4. 从单图到大屏适配、TOOLTIP 与周边图表的坑4.1 px 转 rem 后echarts 为什么纹丝不动很多用 Vue 3 大屏项目的人会碰到一个问题项目里配置了 postcss-pxtorem把 CSS 里的 px 自动转成 rem页面上的普通 DOM 元素缩放得很好但 echarts 画出来的图表纹丝不动而且窗口一变化图表要么溢出要么太小。原因很简单pxtorem 只处理 CSS 文件里的 px而 echarts 的 option 里的数值是在 JS 里直接设置的数字像素它根本不走 CSS 编译流程。而 canvas 内部绘制的文字、坐标、节点大小全都是根据这些 JS 数值直接画到位图上的和页面 rem 无关。所以你给 echarts 设置什么尺寸它就画什么尺寸不会跟随 rem 缩放。如果你试图用transform: scale()去缩放整个 canvas 容器图表是“看起来”小了但 canvas 是一个位图被 CSS 缩放之后会模糊而且 tooltip 位置也会偏移这不是正路。4.2 大屏适配的正确写法scale 比例方案我在大屏里画 echarts 流程图时用的是比较笨但最稳的方案设计稿固定宽度所有节点坐标、symbolSize、字体大小都按比例缩放。设计稿宽度按 1920 来出运行时拿到当前容器的宽度计算缩放比例const baseWidth 1920; const scale window.innerWidth / baseWidth; const nodes nodeData.map(d ({ ...d, x: d.x * scale, y: d.y * scale, symbolSize: [d.w * scale, d.h * scale] })); const option { series: [{ type: graph, layout: none, nodes, // ... }] };字体大小同样要乘 scale。启动时执行一次窗口 resize 时再执行一次并调用chart.resize()重绘。这个方案核心思路是把 echarts 当成一个“按像素绘制的画布”而我们手动控制它的总大小。和 rem 没关系也不需要 pxtorem 去处理 canvas 内部的东西。实测在大屏和普通 PC 屏幕上都能保持相对位置一致不会出现节点错位、连线歪斜的问题。4.3 顺手解决同类 echarts 高频问题饼图小圆点、x 轴刻度在 echarts 社区里经常能看到这几个问题虽然不是流程图的核心但既然是 echarts 实战拿出来一起说饼图 labelLine 末尾小圆点偏移。这个问题的根源一般是labelLine.length2太长而 label 的align方向不对导致末尾圆点没有紧贴文字。处理方式是把label.align设成和 labelLine 同方向比如left或right同时调小length2。如果你需要绝对精确还可以改用富文本形式自定义 label在小圆点的位置放一个文字符号。折线图 x 轴刻度过多重叠。做法是设置xAxis.axisLabel.interval: 0强制全部显示或者配合rotate: 45、hideOverlap: true来优化。流程图里没有 x 轴但如果你把流程图和其他图表组合到大屏这个同样常见。这些都是小细节但 echarts 的坑往往就藏在细节里先把周边问题扫干净流程图才能真正地放进大屏。5. 常见问题与排查技巧实录5.1 节点不受控制、全挤在一起现象是明明设置了 x/y节点还是乱跑或者挤成一团。排查步骤按顺序来确认layout是不是none只要不是none坐标就可能被布局算法覆盖。确认每个节点都设置了fixed: true。没有 fixedgraph 更新时会重新计算位置。检查节点 id 是否重复。如果 id 重复links 里的 source/target 可能连到错误节点视觉上表现为位置错乱。这个是我最常在同事代码里看到的问题九成都是 layout 忘了改。5.2 连线标签文字和线条重叠边上的条件文字如果挤在线上读起来非常费劲。处理方法有几种给 edge 的 label 加背景色和 paddinglabel: { show: true, formatter: 通过, backgroundColor: #fff, padding: [2, 6], borderRadius: 4 }合理利用position例如文字放在线条的middle、start、end不同曲线类型配合不同位置。回退线一定要设置curveness曲线拉开后文字空间就出来了。加背景色是我试过最有效的方案没有之一。不加背景文字和线交叉时完全没办法看。5.3 点击节点拿不到数据 / 事件绑定不上点击事件绑不上先确认你的 echarts 实例有没有被其他图层挡住。graph 系列的节点如果有顶层浮层鼠标事件可能被拦截。另外节点数据里如果设置了silent: true点击也会失效。排查时可先在chart.on(click)回调里打印 params看看触发的params.dataType是什么再决定是判断问题还是数据问题。还有一点容易忽略你必须在初始化的 chart 实例上绑定事件而不是在 option 里写。有些新手会写option.click function(){}然后发现没有反应这就是把 echarts 当成 DOM 在用了。5.4 节点数量大、动画卡的问题流程图几十个节点还好上到上百个节点就会开始掉帧尤其 hover 时阴影、动画全部叠加时特别明显。优化思路关闭动画animation: false。减少阴影和emphasis状态里的复杂样式。symbol尽量用内置形状不要用大尺寸图片或path字符串path 越复杂渲染越慢。如果节点和边超过 500建议做数据聚合或分屏展示不要硬画。echarts 性能再强也是基于 canvas 的节点数量级到了不要执着于一个图硬画到底拆成多张图或者用分片渲染才是正解。6. 相关概念BPMN 网关、思维导图与其它流程工具6.1 BPMN 网关符号到底长什么样、怎么用如果你接触过业务审批系统可能会看到“排他网关”“并行网关”这些词它们是 BPMN业务流程建模标注规范里的概念。简单理解网关就是一个分流器/合并器控制流程在某个节点如何分支、如何汇聚。最常见的三种排他网关X多个分支只走一个相当于 if/else。并行网关多个分支全部走相当于拆成多个并行任务。包容网关O满足条件的分支都走比排他网关更灵活。如果只是展示用途echarts 里可以用diamond的变形加文字模拟菱形中间画个 X 或 。如果要做成可编辑的 BPMN 流程设计器还是建议用 bpmn.js 这类库echarts 不是干这个的。6.2 毕设/课设里的软件工程流程图怎么画才算“标准”很多计算机专业、信息管理专业的同学在毕设里要画“用户管理模块流程图”“系统登录流程图”“数学建模流程图”。这里有个容易被忽略的考点审核老师看重的往往不是图形多漂亮而是逻辑是否完整、符号是否规范。规范的流程图画法需注意每个判断框至少有两个出口且每个出口都要有明确的条件文字。每个路径最终要能走到“结束”不能出现无法到达的死节点。流程方向从上到下、从左到右回退线允许从右到左但不允许出现不必要的交叉。起止节点只能有一个“开始”可以有多个“结束”。如果只是画在论文里用 Visio、draw.io、ProcessOn 都行。但如果你想把流程图嵌到毕设系统网页里展示用 echarts graph 画一张动态的会加分不少它可以在线缩放、点击看详情答辩时演示效果很直观。6.3 什么时候用 xmind、draw.io、visio而不是 echarts工具没有绝对的好坏只有合适不合适。我自己的选择标准是这样场景推荐工具快速梳理思路、从思维导图转流程xmind画静态论文插图、作业图draw.io、Visio在线协作、多人同时标注ProcessOn把流程图嵌入系统、联动其他图表、数据驱动展示echarts graphxmind 做流程图的能力其实偏弱它最强的是思维导图。如果只是把“流程逻辑”理清楚用 xmind 的逻辑图足够但如果要精确控制每一个箭头、每一个分支的坐标那还是 draw.io 或者直接写 echarts 更可控。不要把时间花在纠结工具上先想清楚你这个图是“给人看的”还是“给系统用的”答案自然会出来。最后分享一个我自己的习惯。不管是用 echarts 还是其他工具画流程图之前我一定先拿草稿纸把节点 id 列出来再把每条边的 source 和 target 写清楚。graph 的数据结构本质上就是一张图的邻接表links里写错一个 source箭头就会跑到奇怪的地方排查起来反而最费时间。如果只让我留一条经验给后来人那就是先把数据模型设计干净剩下的交给配置。流程图画的是数据逻辑不是美术作品。
返回列表