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. javascript 基础

    javascript概述: javascript历史: * 1992年Nombas开发出C-minus-minus(C--)的嵌入式脚本语言(最初绑定在CEnvi软件中).后将其改名ScriptEas ...

  2. Construct Bounding Sphere

    点集的包围球 http://en.wikipedia.org/wiki/Bounding_sphere http://blogs.agi.com/insight3d/index.php/2008/02 ...

  3. CListCtrl中删除多个不连续的行

    ==================================声明================================== 本文原创,转载在正文中显要的注明作者和出处,并保证文章的完 ...

  4. Node.js中的ORM

    ORM2是一款基于Node.js实现的ORM框架,名字相当的霸气,算是同类框架中非常出色的一款,具体介绍请猛击:https://github.com/dresende/node-orm2 刚接触Nod ...

  5. 用户向导页面实现左右滑动的ViewPager

    然后在一个博客,以前的博客ImageSwitcher实现用户向导,现在,随着ViewPager实现同样的功能.直接看代码: 布局文件activity_main.xml <RelativeLayo ...

  6. C语言_指针和数组的几种访问形式

    敲几行代码来看看几种访问的形式~ #include <stdio.h>;int main() { ] = {, , , , , }; //初始化5个元素的一维数组 int *p = arr ...

  7. C#基础(二)拆箱与装箱,循环与选择结构,枚举

    一.装箱和拆箱 装箱是将值类型转换为引用类型 eg: Int a=5; Object  o=a; 拆箱是将引用类型转换为值类型 eg: Int a=5; Object  o=a; Int b=(int ...

  8. 设计模式系列之装饰模式(Decorator Pattern)

    装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装.这种模式创建了一个装饰类,用来包装原 ...

  9. c++对象的存储空间

    1. 非静态成员 2. 静态成员变量 静态成员变量不占对象的内存空间 3. 成员函数 成员函数不占内存空间 4. 析构函数 5. 类中有虚析构函数 6. 继承空类和多重继承空类存储空间的计算 7. t ...

  10. 【EMV L2】GPO响应以及AIP、AFL

    [GPO命令] 终端通过GPO(Get Processing Options)命令 通知卡片交易开始.命令数据为PDOL指定的终端数据. [GPO响应] 卡片在GPO命令的响应中返回AIP和AFL:A ...