0 需求

做的项目需要画一个关系图,主要需求如下:

  • 需要展示6种对象之间的关系:数据机构 数据 合约 模型 计算机构 应用
  • 支持突出显示6种对象中的某一种的所有对象
  • 支持Top x子图功能。top x子图的定义:在6种对象中的每一种对象,取关系数最多的x个,将这至多6*x个对象绘制在一张图中
  • 任务仅为原型展示,无后端,可以面向数据编程

众所周知 ECharts 是一个功能强大的 JS 图表库,这次也使用 echarts 进行图表绘制。

最终效果大致如下图;感兴趣的话可以在 Codepen 预览动画效果,也可以亲自尝试各种参数的修改。

1 使用 ECharts

使用echarts想必大家都比较熟悉了,官网上也有很详细的教程,这里就简单介绍一下。

charts 库支持的图表类型有二三十种,基本涵盖了能想象到和完全没想过的各种图表绘制。同时echarts也支持各种常用的引入方式:从源码构建、npm安装、CDN引入等。

引入 JS 库后在网页中使用也很容易:

<!-- 为 ECharts 准备一个具备大小的 DOM -->
<div id="model-kg-graph" style="height: 800px"></div>
var graph_chart = echarts.init(document.getElementById("model-kg-graph"));
let option = {
// 相应的配置项
}
graph_chart.setOption(option);

不管绘制什么图表,需要的代码都是如上几行,区别只在 option 配置项的不同。主要的配置项有这些:

let option = {
// 图例,因为一张图中可能存在多个图表(例如柱状图+折线图),因此参数是数组
// 数组中每一项对应一个系列,每项是一个包含类别名称数组的对象;
// categories: ["数据机构", "数据", "合约", "模型", "计算机构", "应用"],
legend: [
{
data: graph_data.categories,
},
],
// 图表的配置;如果数组有多项几个图表将绘制在一起
// 每种不同的图表都有大量专属的配置内容,以下是比较常见通用的几种
series: {[
type: "graph", // 指定绘制的是什么图
roam: true, // 使用鼠标滚轮缩放、点击移动
animation: false, // 是否开启动画;默认是开启
emphasis: {}, // 可以设置被选中的元素突出显示的特殊样式
]},
};

除此以外还有标题、坐标系(柱状图/折线图中很常用)等等常见配置,这次没用到就忽略了。使用时可以查阅echarts事无巨细的配置项文档

2 关系图 Graph

本节中提到的所有配置项均是在 option.series 内,下文不再特殊说明

图的基本构成

说回关系图。关系图其实就是平时常说的图,基本构成是节点和边。在配置项中对应的就是:

// 也可以叫 nodes
data: [
{ name: "数据机构1", symbolSize: 3.0 },
], // 也可以叫 edges
links: [
{ source: "数据1", target:"数据机构3" },
],
  • data 中的每个对象对应一个节点,name 为唯一表示,不能重复,否则会报错 Cannot set property 'dataIndex' of undefined ,直接渲染失败;symbolSize 表示节点的大小,不设置会有默认值,根据连接数设置不同大小也是常见的做法。
  • links 中的每个对象对应一条边,对应 data 的 name 属性;如果找不到 name == source || name == target 的节点,那这条边就不会渲染。

分类

需求中提到有6类对象需要分别表示,也就是节点对应不同的颜色。相应的配置项:

// categories: ["数据机构", "数据", "合约", "模型", "计算机构", "应用"],

categories: graph_data.categories.map((c) => ({ name: c })),
data: [
{ name: "数据机构1", category: 0, symbolSize: 3.0 },
],
  • categories 虽然就是类别的数组,但数组的每项是一个对象,对象只有一个叫 name 的属性。

    • 如果不熟悉map语句,简单来说这个值就是 [ {name: "aaa"}, {name: "bbb"}, ... ]
    • 这里的名称需要和 legend (图例)里面的那个类别数组对应,否则会缺少对应的图例
  • 每个节点的数据里增加类别的索引,对应类别数组的下标。注意这里必须是一个 number,不能用字符串,否则整张图无法渲染(亲自踩过的抗)

图的布局

有了节点和边就可以构造出一张图了。echarts 提供了三种布局方式:

layout: "none" | "circular" | "force"
  • none:布局完全由每个节点中指定的 (x, y) 坐标决定;显然对于数据很多并且不确定的图来说并不现实

  • circular:环形布局;很有特点的布局方式,见下图

  • force:力引导布局;这种其实就是最常见的图的样子,可以根据参数自动渲染。文中使用的就是这种方式。

使用 force 布局之后还有一些细节设置可以选择:

force: {
initLayout: "circular",
repulsion: 1000,
layoutAnimation: false,
},
  • initLayout:初始布局,之后会根据设置的力引导属性继续变化直到稳定。说实话指不指定好像样子区别也不大
  • repulsion:斥力大小,简而言之数值越大节点之间距离越远,反之节点距离越近
  • layoutAnimation:渲染动画,就是从初始位置直到稳定的动画过程。官方文档中的说法是”节点数据较多(>100)的时候不建议关闭,布局过程会造成浏览器假死。“但那个动画真的十分魔性,建议去文章开头的链接里亲自体验一下。比起看这个视觉污染动画我宁愿他假死。

强调和样式

图有一些可以自定义的样式配置,基本节点、边、标签等等的颜色形状位置都可以自定义。这里介绍几个我用到的:

focusNodeAdjacency: true,
legendHoverLink: true,
lineStyle: {
color: "source",
opacity: 0.2,
curveness: 0.3,
},
  • focusNodeAdjacency:聚焦邻接节点,就是下图所示这种喜闻乐见的样式,很不戳。文档中说这个选项的默认值是true,但我用v4.9.0版本的库手动添加这一句之后才有效果,可能是v5中改了。

  • legendHoverLink:文档的说法是鼠标悬停在图例上节点高亮,但实际上至少v5.0.2还并不是这个效果;可能是库的bug,可以期待一下之后会不会改进。
  • lineStyle:顾名思义,线的样式:
    • curveness :线的曲率,不设置将为直线
    • opacity/color:透明度/颜色,可以用 source/target 指定为源/目标节点的颜色

其他配置项设置的是静态状态下图的样式,对于高亮状态的元素(例如鼠标悬停在节点/边上),还可以单独设置强调样式 emphasis。同样,基本所有元素的各种样式都能设置,以下是几个例子:

emphasis: {
itemStyle: {
shadowColor: "rgba(0, 0, 0, 0.4)",
shadowBlur: 15,
},
lineStyle: {
width: 3,
},
label: {
textBorderColor: "rgba(255, 255, 255, 0.8)",
textBorderWidth: 2,
},
},

3 突出显示指定节点

有一项需求是:突出显示某个类别的节点。(按理说鼠标悬停图例应该是这个效果,但他并不能用)

不过echarts提供了API,可以对图执行动作(action)。调用方式如下:

graph_chart.dispatchAction({
type: action,
seriesIndex: 0,
name: names,
});
  • type:指定动作,这里要用到的是 "highlight"/"downplay",高亮/取消高亮
  • seriesIndex/seriesName:用下标/名字指定操作的系列,数组指定多个
  • dataIndex/name:用data[]中的下标/名字指定要操作的数据,数组指定多个

据此可以写出函数:

nodesAction(action, category) {
if (category !== "") {
// 取到指定图option中的data[]
let nodes = this.graph_chart.getOption().series[0].data; // 根据category下标,获取到对应类别所有name的数组
let names = nodes
.filter((node) => node.category == category)
.map((node) => node.name); // 对指定的name[]执行指定操作
this.graph_chart.dispatchAction({
type: action,
seriesIndex: 0,
name: names,
});
}
}

项目使用的Vue框架,下拉选择框绑定了graphFocus属性,对这个数据添加一个侦听器:

watch: {
graphFocus(n, o) {
// n:新的值;o: 旧的值
this.nodesAction("highlight", n);
this.nodesAction("downplay", o);
},
},

就能实现切换选项的同时高亮对应的节点:

如果你使用的echarts版本在5.0.0以上,还可以通过以下配置实现类似于focusNodeAdjacency的效果:

emphasis: {
focus: "adjacency",
}

4 替换数据

最后一个需求是显示不同的子图。根据之前说的“如果两端节点不同时存在则边不会渲染”,我们只需要将data[]替换成子图的节点,就可以实现对应的子图。

按理说top节点应该有后端直接返回,所以如何获取节点的过程这里省略了。有了top节点之后,使用setOptionAPI更新新的配置项:

switchSubgraph(value) {
let data = graph_data.nodes;
switch (value) {
case 1:
data = this.top1Sub;
break;
case 3:
data = this.top3Sub;
break;
case 5:
data = this.top5Sub;
break;
}
this.graph_chart.setOption({
series: { data: data, zoom: 1 }, // zoom=1 重置缩放
});
},

setOption 的默认更新方式是合并更新,意思是只更改传入的新option与原来不同的地方,其他部分保持不变;所以我们只需要将更换的data传进去,不需要复制整个原先的option。

如果不希望使用合并更新,可以手动传入第二个参数notMerge=true,就会将整个option替换为传入的新选项

如果打开了动画,还可以自动根据更新前后的差异展示适当的动画。

  • 但是动画这东西是个坑。用v4.9.0的时候,替换data后边的显示是乱的,需要手动缩放一下;换成v5.0.0之后,替换完data显示没问题,一缩放又坏了。设置了animation: false之后啥毛病都没了。
  • 可能这功能还不够完善,对于常用的柱状图折线图表现比较好,关系图这种不那么常用又复杂的东西就有各种神秘bug。期望日后的版本中可以改善。

替换节点后,得到了期望的Top子图,并且之前的高亮功能也可以正常使用。

结语

以上就是我这次使用ECharts关系图的过程中遇到的问题以及最终的解决方式,希望也可以帮到你。如果有相关的问题、或是文章中存在疏漏,欢迎在评论区留言讨论!

PS:第一次用CodePen,真的够呛,研究这玩意的时间快和写文差不多长了。眼看可以就如何使用CodePen再写一篇(跑

参考资料

ECharts官方文档

前端 | 使用 ECharts 绘制关系图的更多相关文章

  1. echarts绘制甘特图

      在setoption之后添加这段代码: window.addEventListener('resize', function () { myChart.resize();   }); 图表就能随着 ...

  2. ECharts绘制折线图

    首先看实现好的页面 实现 首先引入echarts工具 // vue文件中引入echarts工具 let echarts = require('echarts/lib/echarts') require ...

  3. 前端通过jqplot绘制折线图

    首先需要下载jqplot需要的js与css文件,我已近打包好了,需要的可以下载 接下来导入其中关键的js与css如下, <link href="css/jquery.jqplot.mi ...

  4. 利用python+graphviz绘制数据结构关系图和指定目录下头文件包含关系图

    作为一名linux系统下的C语言开发,日常工作中经常遇到两个问题: 一是分析代码过程中,各种数据结构互相关联,只通过代码很难理清系统中所有结构体的整体架构,影响代码消化的效率; 二是多层头文件嵌套包含 ...

  5. 【Canvas】(2)---绘制折线图

    绘制折线图 之前在工作的时候,用过百度的ECharts绘制折线图,上手很简单,这里通过canvas绘制一个简单的折线图.这里将一整个绘制过程分为几个步骤: 1.绘制网格 2.绘制坐标系 3.绘制点 4 ...

  6. Echarts数据可视化series-graph关系图,开发全解+完美注释

    全栈工程师开发手册 (作者:栾鹏) Echarts数据可视化开发代码注释全解 Echarts数据可视化开发参数配置全解 6大公共组件详解(点击进入): title详解. tooltip详解.toolb ...

  7. 使用echarts绘制条形图和扇形图

    使用echarts绘制条形图和扇形图 简单举例说明下echarts如何绘制条形图和扇形图 代码示例 <!doctype html> <html lang="en" ...

  8. Echarts关系图-力引导布局

    需要做一个树形图,可以查看各个人员的关系. 可伸缩的力引导图-失败 刚开始,打算做一个可展开和伸缩的,搜索时候发现CSDN有一篇美美哒程序媛写的Echarts Force力导向图实现节点可折叠. 这里 ...

  9. 转:ECharts图表组件之简单关系图:如何轻松实现另类站点地图且扩展节点属性实现点击节点页面跳转

    站点地图不外乎就是罗列一个网站的层次结构,提炼地讲就是一个关系结构图.那么我们如何巧用ECharts图表组件内的简单关系结构图来实现一个站点的地图结构呢?另外如何点击某个节点的时候实现页面跳转呢? 针 ...

随机推荐

  1. TypeScript & LeetCode

    TypeScript & LeetCode TypeScript In Action TypeScript 复杂类型 编写复杂的 TypeScript 类型 // 方法「只可能」有两种类型签名 ...

  2. NGK算力生态建设者狂欢!SPC之后又有VAST!

    想致富,先挖矿.这句话已经成为了币圈的一句名言.挖矿一词始终贯穿着区块链以及数字加密领域. 据小道消息透露,NGK官最近将会推出两款挖矿产品---SPC星空币以及其子币VAST维萨币. 下面笔者就来一 ...

  3. uniapp 自定义弹窗组件

    先上效果: 组件源码:slot-modal.vue <template> <view class="modal-container" v-if="sho ...

  4. python中yaml模块的使用

    1.yaml库的导入 经过尝试,发现在python2 和python3语言环境下,安装yaml库的命令行语句不一样. python2: pip install yaml python3:pip ins ...

  5. spring扩展点整理

    本文转载自spring扩展点整理 背景 Spring的强大和灵活性不用再强调了.而灵活性就是通过一系列的扩展点来实现的,这些扩展点给应用程序提供了参与Spring容器创建的过程,好多定制化的东西都需要 ...

  6. npm与package.json快速入门

    本文转载自npm与package.json快速入门 导语 npm 是前端开发广泛使用的包管理工具,之前使用 Weex 时看了阮一峰前辈的文章了解了一些,这次结合官方文章总结一下,加深下理解吧! 读完本 ...

  7. 如何用python自动编写《赤壁赋》word文档

    目录 前言 安装-python-docx 一.自动编写<赤壁赋> 准备数据 新建文档 添加标题 添加作者 添加朝代 添加图片 添加段落 保存word文档 二.自动提取<赤壁赋> ...

  8. SpringBoot2.x整合JavaMail以qq邮箱发送邮件

    本文参考spring官网email接口文档所写. spring-email官方网址:https://docs.spring.io/spring/docs/5.1.8.RELEASE/spring-fr ...

  9. Go的结构体

    目录 结构体 一.什么是结构体? 二.结构体的声明 三.创建结构体 1.创建有名结构体 2.结构体初始化 2.1 按位置传参 2.2 按关键字传 3.创建匿名结构体 四.结构体的类型 五.结构体的默认 ...

  10. 阻塞队列——四组API

    方式 抛出异常 有返回值,不抛出异常 阻塞等待 超时等待 添加 add() offer() put() offer(...) 移除 remove() poll() take() poll(...) 检 ...