十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

ECharts关系图graph实战:从数据设计到性能优化

ECharts关系图graph实战:从数据设计到性能优化 前两天有个做数据可视化大屏的朋友问我想把公司几十个业务系统之间的依赖关系画出来问我用什么方案快。我脱口而出ECharts的graph——关系图。他愣了一下说平时柱状图、饼图、折线图用得挺多关系图还真没碰过。这其实是很多人的状态ECharts用得再溜一到graph就卡壳。原因不难理解关系图的思维模式和常规图表有本质区别它不再是“一个维度对应一个数值”而是“多个节点之间互相连接”数据结构和配置方式都换了一套逻辑。这篇分享我想把echarts关系图graph从数据设计、核心配置、实操落地到踩坑排查完整过一遍。不管你是前端、数据分析师还是刚从柱状图、饼图开始接触ECharts的新手只要按着这个思路走一遍关系图基本就能直接上手。顺带把graph相关几个高频困惑比如graph和tree怎么选、graph初始不高亮怎么解决、tooltip换行怎么写、内容多了卡顿怎么优化也一起说清楚。1. 别把关系图当普通图表看先理解它的底层逻辑1.1 图数据和行列数据根本不是同一个物种常规的柱状图、折线图、饼图数据本质上都是一张或多张二维表x轴一个字段y轴一个数值字段或者维度度量。关系图完全不是这套玩法。关系图的数据是真正的“图结构”由两个核心部分组成nodes节点图中的点每个点有自己的id、名称、大小、分类、坐标等属性links边/连线点与点之间的连接关系每条边有source起点、target终点还可以带权重value和样式。如果你写过图数据库或者接触过Neo4j会发现ECharts graph的数据模型和图数据库非常像它本质上就是一个简化版的图数据模型。这也是为什么很多人在对接图数据库时会直接把查询结果转成graph需要的nodes和links结构再丢给ECharts渲染。我见过不少新手第一次用graph下意识想用数组下标去关联节点结果节点一增删就错位。正确的做法是每个节点必须有一个全局唯一的idlinks里的source和target都通过id来引用这样无论节点怎么增删连线关系都不会乱。这也是graph数据组织和表格数据组织最大的区别——它讲究的是“引用”而不是“顺序”。1.2 图形业务场景那么多怎么判断该用graphECharts里能表达关系的图表其实不止graph树图tree也能表达层级关系。我做项目时一般这样判断有明确的上下级、父子层级且层级深度比较固定优先用tree比如公司组织架构、代码目录结构关系是网状的、多对多的甚至存在闭环或跨层连接那就必须用graph比如系统依赖关系、社交关系网络、知识图谱、资金流向、人物关系分析。graph还有一种很常见的用法是把多个子图组合在一起用categories分类区分不同角色再配合图例legend做筛选。比如做应收应付资金关系图时客户、供应商、内部公司分属不同分类节点用不同颜色展示既清晰又有业务深度。另外提醒一句如果你看到的是“把大象放进冰箱”的线性流程或者循环判断逻辑那更适合用类似mermaid graph这类文本图谱工具或者ECharts的桑基图不要硬套graph。关系图的优势是表达复杂网状结构不是所有带箭头的东西都适合塞进graph里。2. graph核心配置拆解每个参数背后都是物理规律2.1 nodes、links、categories三件套先把数据模型立住先看一段最小可用的graph配置我尽量写细一点这是一个“数据分析师与技能点”的知识图谱示例用categories区分人物和技能。option { series: [{ type: graph, layout: force, // 力引导布局节点之间会相互排斥并自动寻找稳定位置 roam: true, // 允许鼠标缩放和平移大图必备 draggable: true, // 节点可拖拽拖拽后布局会微调 data: [ { id: d1, name: 林一, category: 0, symbolSize: 60, value: 10 }, { id: d2, name: 陈晨, category: 0, symbolSize: 50, value: 8 }, { id: s1, name: Python, category: 1, symbolSize: 40 }, { id: s2, name: ECharts, category: 1, symbolSize: 40 }, { id: s3, name: SQL, category: 1, symbolSize: 40 } ], links: [ { source: d1, target: s1, value: 5 }, { source: d1, target: s2, value: 5 }, { source: d2, target: s2, value: 3 }, { source: d2, target: s3, value: 4 } ], categories: [ { name: 分析师 }, { name: 技能 } ], label: { show: true, position: right, fontSize: 12 } }] };几个容易踩的细节category字段用的是下标索引0、1而不是类别名字符串。如果写成category: 分析师ECharts并不认识节点颜色会全部变成默认色。这是graph里出现频率最高的低级错误之一。links里的value不是必填的但如果你希望线条粗细表达关系强弱这个值一定要给。node的id建议用稳定唯一的值比如数据库主键或系统编码不要用name当id因为name可能重复也可能会导致节点边合并出错。配色上如果你不手动设置每个节点的itemStyle颜色ECharts会根据categories自动分配颜色这一点很省事但也意味着categories的顺序会直接影响视觉方案设计时先规划好分类顺序。2.2 力引导布局调参掌握这几个手感就够了graph最常用的布局是layout: force节点之间像带电粒子一样互相排斥同时连线的弹簧把有关系的节点拉近最终稳定下来的位置往往能呈现出很好的聚类效果。这也是很多知识图谱好看的原因它不是画出来的是“算”出来的。关键参数都在force对象里force: { repulsion: 300, // 节点之间的斥力值越大节点散得越开 gravity: 0.1, // 重力值越大整个图越向中心收拢 edgeLength: [100, 250], // 边的理想长度范围值越大连线越长 friction: 0.6, // 摩擦系数值越大运动衰减越快 layoutAnimation: false // 布局收敛后是否还保留动画大图建议直接关掉 }实际调参经验节点数量在三五十个以内repulsion给150到300比较舒服太小会挤成一坨太大节点满天飞。节点数到几百上千repulsion反而要适当调大同时gravity降低不然整张图会缩成一个球什么关系都看不出来。edgeLength设置成数组时ECharts会在这个区间内根据边权重调整长度权重大的边更短视觉上很有层次感。如果你不明所以地把edgeLength设成固定值100往往体会不到force布局的妙处。如果遇到图一直震荡停不下来优先检查friction是不是设得太低以及是否给部分节点设置了固定的x、y坐标两者叠加会导致布局永远不收敛。2.3 交互联动配置roam、draggable和emphasis才是“高级感”来源关系图真正拉开差距的不是节点画得多好看而是交互体验。graph本身是信息技术感很强的图型如果鼠标移上去没有任何反馈数据再多也白搭。我强烈建议三件套一起开roam: true, // 支持缩放平移节点多的时候才看得清局部关系 draggable: true, // 支持拖拽节点用户可以手动整理布局 emphasis: { focus: adjacency // 高亮当前节点和它相邻的节点其他全部变淡 }emphasis的focus字段是graph的核心交互利器。它有三个可选值none没有焦点效果self只高亮当前节点adjacency高亮当前节点和它直接相连的所有节点其余弱化。实际项目里我几乎无脑用adjacency因为关系图的核心场景就是“沿着一条边看它连到什么”如果不锁定相邻节点用户一移鼠标满屏都在闪毫无重点。关于热搜里那个“echart graph关系图 初始不高亮”的问题多半不是ECharts的问题。最常见的原因是数据里links的source/target跟节点的id对不上导致“相邻节点”根本不存在高亮自然不生效。还有一种情况是你在series外层配置了emphasis但graph的某些子配置会覆盖它或者你在数据项里单独设置了itemStyle.emphasis把高亮样式冲掉了。排查时先打开控制台看warning再逐项删减配置很快能定位。3. 实际动手做一张“文章主题关系图谱”3.1 数据怎么准备才算干净理论知识说得再多不如直接跑一个完整例子。我以“文章主题关系图谱”为例把一批技术文章作为节点文章之间如果有相同的标签比如都提到ECharts就连一条边边的权重就是共同标签数量。这种场景在内容运营、检索推荐里很常见也能体现graph处理多对多关系的能力。先准备数据。生产环境里你可能需要从后端动态获取但在本地演示时我直接在前端构造数组const articles [ { id: a1, name: ECharts快速上手, labels: [ECharts, 可视化] }, { id: a2, name: Graph关系图实战, labels: [ECharts, 关系图] }, { id: a3, name: 数据大屏设计要点, labels: [可视化, 大屏] }, { id: a4, name: 前端性能优化笔记, labels: [性能, 前端] }, { id: a5, name: Python数据清洗, labels: [Python, 分析] }, { id: a6, name: SQL面试整理, labels: [SQL, 分析] } ];接着把文章数组转成nodes再根据共同标签生成links。我不会在博文里贴一段几十行的循环代码但核心思路是嵌套遍历所有文章对如果两篇文章有共同标签就生成一条边同时把共同标签数量作为value。这样数据是从业务关系里“计算”出来的而不是手写的后面换数据源也方便。为了好看一点我给文章加上symbolSize让文章节点大小和它关联的文章数量挂钩关联越多节点越大。3.2 最小可用代码让图先跑起来现在把处理好的数据塞进ECharts配置里。我用的是最常见的CDN和容器方式如果你用的是Vue、React里封装好的echarts库核心配置几乎不用改只是初始化时机不同const chartDom document.getElementById(graph-container); const myChart echarts.init(chartDom); myChart.setOption({ tooltip: {}, series: [{ type: graph, layout: force, data: nodes, links: links, categories: [{ name: 文章 }], roam: true, draggable: true, force: { repulsion: 250, gravity: 0.1, edgeLength: [80, 160], friction: 0.6, layoutAnimation: false }, label: { show: true, position: right, fontSize: 12 }, lineStyle: { color: source, // 线条颜色跟随起点节点 width: 2, curveness: 0.15 // 稍微带一点弯曲视觉更柔和 }, emphasis: { focus: adjacency } }] });这一段跑起来你已经能得到一个可以拖拽、缩放、悬停高亮的关系图了。我用“文章主题关系图谱”这个例子测试过初始布局会自动把相同标签的文章聚到一块比如a1和a2因为都提到ECharts会离得很近a1和a3因为都提可视化也会靠近整张图会自然地形成几个聚类区域看起来就像一篇分析文章的关系网。3.3 美化五连大小、颜色、连线和tooltip图能跑起来只是第一步。真实项目里领导或者客户不会看“能跑”他们只看“好不好看”“信息清不清楚”。所以接下来我从五个维度做美化。第一是节点大小。除了用symbolSize定死我更喜欢用回调函数比如用value计算大小symbolSize: function (val, params) { return 30 (params.data.value || 0) * 3; }第二是配色。如果你希望节点颜色不完全依赖categories而想按业务维度着色可以在data里的每个节点上配置itemStyle.color。我习惯给核心节点用高饱和色边缘节点用低饱和色视觉焦点一目了然。第三是连线美化。graph的lineStyle支持非常多属性推荐以下几个组合color: source线条颜色跟随起点节点看起来像信息从源头流出curveness: 0.1到0.3给线条一点弧度不会像一把乱稻草opacity控制在0.4到0.8之间太多边的时候不会糊成一团。第四是标签。节点多的时候label全部显示一定会重叠。这时候可以开label的formatter做裁剪或者干脆只在emphasis高亮时显示标签非高亮状态下只显示节点圆点。我做知识图谱大屏时经常这样配label: { show: true, formatter: function (params) { return params.data.name.length 6 ? params.data.name.slice(0, 6) ... : params.data.name; } }第五是tooltip。graph的tooltip建议写成函数格式化返回HTML片段这样能显示更丰富的信息。这也是热搜里“echarts tooltip自动换行”的解决方法之一就是在formatter返回的字符串里直接加需要更精细的排版也可以包一层div指定宽度。tooltip: { formatter: function (params) { if (params.dataType node) { let linkCount links.filter(l l.source params.data.id || l.target params.data.id).length; return div stylefont-weight:bold params.data.name /div div关联数 linkCount 个/div; } else { return params.data.source → params.data.target br/权重 params.data.value; } } }这里的linkCount计算只是示例如果你的数据量很大可以在准备数据阶段就直接把每个节点的度算好放进去不要每次hover都遍历全量数组。4. 性能优化与高频问题排查实录4.1 节点一多就卡先做这三步关系图相比柱状图、饼图渲染成本呈指数级上涨。我做过一张包含三千多个节点、一万多条边的依赖关系图默认配置直接白屏了几秒。后来总结了三条铁律第一关闭冗余动画。force布局本身就消耗性能如果数据点很多把force.layoutAnimation设为false同时把series.animation设为false。用户的耐心是有限度的与其让图慢悠悠地动半天不如一次渲染到位。第二控制边和节点的显示数量。如果边超过几千条可以降权过滤只保留权重比较高的边节点可以按度数排序只展示top N节点其他节点折叠到分类需要时再展开。这不是偷懒而是信息设计问题——人眼根本处理不了上万条边同时存在。第三合理使用scaleLimit限制缩放范围防止用户把图放到无限大出现所有节点边缘糊成一片的情况scaleLimit: { min: 0.3, max: 4 }还有一点想额外提一下如果你做的数据大屏里只有关系图这一个模块不要急着上大而全的三维方案。2D的graph用Canvas渲染已经能扛住绝大多数业务量真到扛不住的时候首先要做的是数据聚合而不是换渲染引擎。4.2 高频问题速查表附排查思路我把平时被问到的graph相关问题整理成一个速查表遇到问题直接对着查问题现象可能原因解决办法节点全部挤成一团force.repulsion太小或gravity太大调大repulsion到200以上调小gravity边没有显示只有节点links里source/target和节点id不匹配核对id引用控制台会有警告信息hover节点没有高亮emphasis.focus没设置或links数据关联不上设置focus: adjacency并检查links的source/target节点拖不动draggable没开或节点有固定坐标设置draggable: true检查data里的x/y/fixed字段节点标签互相遮挡节点太密集或label全部强制显示非高亮时只显示部分标签或开启label的formatter裁剪tooltip文字不换行formatter返回的字符串里没有换行标识使用或者给tooltip加extraCssText设置宽度大图白屏卡顿节点边数量过多动画过多关动画、降权过滤边、减少初始节点数量节点颜色全是同一种category索引写错data里没有正确分类确认category是数组下标分类数据放到categories数组图一直震荡停不下来friction过低或存在多个固定节点调高friction检查是否误设了x、y坐标图表初始化后位置不对force布局收敛前的动画被截断调用myChart.resize()或等待布局稳定后再截图另外还想专门说一下和graph容易混淆的兄弟工具。搜“git graph插件怎么用”的同学那个是VS Code里用来查看Git提交历史的Git Graph插件跟ECharts的graph没什么关系。搜“mermaid graph”的同学那是一个用文本描述流程图的工具适合画简单的流程图、时序图不适合做复杂的交互网络分析。如果你需要的是高度可交互、可拖拽、可随数据实时变化的网状关系可视化ECharts graph依然是目前开源方案里综合性价比最高的选择。还有一类辅助工具比如getdata graph digitizer是用来从论文、手册的图片里逆向提取坐标数据的很多做科研绘图的朋友喜欢用它配合ECharts复现实验曲线。它不是graph关系图工具但跟ECharts配合使用确实很舒服提取出来的数据可以直接生成折线图、散点图属于一个值得收藏的周边利器。5. 最后分享一段踩坑心得关系图graph这个系列我前前后后做了十几个项目最大的感受是它不是一个“配置完就完事”的图表而是一个需要持续调优的数据产品。第一次打开graph时你看到的是什么样并不重要重要的是用户能不能通过缩放、拖拽、高亮自己去发现数据里的规律。所以我的建议是做graph之前先想清楚你的用户是谁——他们是要看业务全景还是要定位单条关系链全景图就着重调布局和分类视觉定位关系链就把tooltip和emphasis.focus做好这两者的配置思路差别很大。再分享一个实用小技巧如果你要在项目里大量使用graph建议把force相关参数抽成一个配置文件节点数量、边的数量变化时只需要改几个阈值而不是每次从零调参。我自己的习惯是提前准备三套预设小图50节点、中图50到300节点、大图300节点跑项目时根据数据量直接套省下大量时间。如果你也被要求做一张“看起来很专业”的图不妨从echarts graph关系图开始。它不像地图、色斑图那样需要复杂的地理数据也不像词云图那样需要特殊处理只要把nodes和links理清楚再按上面的步骤调一遍参数很快就能做出一张既能看又能玩的关系网络图。
返回列表