Echarts力导向图graph多事件添加

Echarts功能出色,文档详细(强烈推荐),如今已经更新到了4.x版本。
本文要介绍的是echarts所支持的graph(关系图、力导向图)的功能拓展的小实践。我们会利用其所提供的API增添三个功能。

1.选中节点
2.增删节点
3.层级缩放


一、容器准备与数据加载

这部分没有太多要说的,无论是直接写在html中还是使用框架,都需要为可视化的呈现准备一个DOM容器,初始化后随即渲染即可生成图表。

var myChart = echarts.init(document.getElementById('main'))//初始化,如果你的容器id为main的<div></div>
var option={/*你的配置项,含有重要的数据部分*/}
myChart.setOption(option)// 終了

option含有许多功能配置信息,包括坐标轴,区域缩放,地理坐标系等等组件,在本例中基本采用默认配置,只需要关注配置项的series即可。

var option={series:[{type:'graph',name:'随意',layout:'force',data:[],link:[]}]}

echarts中大部分配置都是共通的,我们选定图表类型graph和布局force即可(layout有三种选择,分别为:circular,none,forcecircular是环形布局,所有点围成了一个圈,none布局需要为每个数据点指定坐标,force就是老版本中采用力布局算法的图)。相比其他图表,graph除了数据data(可用别名nodes)之外,还需linksedges)这个数据属性。
如果数据如下:

data:[{
    name:'n1'
},{
    name:'n2'
},{
    name:'n3'
}],
links: [{
    source: 'n1',
    target: 'n2'
}, {
    source: 'n2',
    target: 'n3'
}]

则图形生成为:

n1->n2->n2

所以data描述了一个个单独节点的信息,它当然不止name这样简陋,这里我们只关注了必须的项,除了文档中的诸多可选项value,category等之外还可以自定义属性,值得注意的是它不允许出现重名。link则描述了节点的关系,如果不关注节点的指向或者说主次(可以为连线填上箭头),sourcetarget只要分别填上连线的两端即可。

二、事件处理

Echarts通过on来添加事件处理函数,在取得实例化的(前述)myChart后,事件监听如下:

myChart.on('click', function (params) {
    console.log(params);
});

鼠标事件包括'click'(单击),'dblclick'(双击),'mousedown','mouseup','mouseover','mouseout','globalout','contextmenu(右键)'。

除去鼠标事件之外,还支持图表行为,详见这里
这个回调函数:1.可以具名 2.可以指定上下文
它的参数params包含这些属性:

{
// 当前点击的图形元素所属的组件名称,
// 其值如 'series'、'markLine'、'markPoint'、'timeLine' 等。
componentType: string,
// 系列类型。值可能为:'line'、'bar'、'pie' 等。当 componentType 为 'series' 时有意义。
seriesType: string,
// 系列在传入的 option.series 中的 index。当 componentType 为 'series' 时有意义。
seriesIndex: number,
// 系列名称。当 componentType 为 'series' 时有意义。
seriesName: string,
// 数据名,类目名
name: string,
// 数据在传入的 data 数组中的 index
dataIndex: number,
// 传入的原始数据项
data: Object,
// sankey、graph 等图表同时含有 nodeData 和 edgeData 两种 data,
// dataType 的值会是 'node' 或者 'edge',表示当前点击在 node 还是 edge 上。
// 其他大部分图表中只有一种 data,dataType 无意义。
dataType: string,
// 传入的数据值
value: number|Array
// 数据图形的颜色。当 componentType 为 'series' 时有意义。
color: string
}

比如params.name可以得到单击(或双击事件)节点名,或者使用params.dataType判断点击到了节点还是连线。所以每当鼠标事件发生时,我们便可以抽取出目标节点的信息,从而在整个数据结构中以此为判断条件进行变换。可以参考官方小例子

三、逻辑梳理与功能实现

(下文谈论的子父节点是以linkssource、target为依据的,主要体现数据索引的结构,并且树结构才能直接应用这些功能

点击高亮

这个比较简单,点击节点后通过params得到目标点的name后(其实data中的数据还含有index属性,可以通过这个来处理),找到该点在data数组中的位置后改变相应的配色或者亮度即可。对于改变配色的方案,只需要在规定好被选中的颜色基础上传递该节点的name(或者能够索引的信息)和category即可,因为再选中其余点时,我们通过维持前一个的索引和category来恢复颜色(默认会根据category的不同分配调色板上的颜色)。

//伪代码
if(preName===params.data.name)//do Nothing
else{
    在option中找到preName所在项A
    A.category=preCategory
    在option中找到param.data.name所在项B
    B.category=uniCategory//如果uniCategory所代表的数字没有规定的话一般会显示红色
   [ preName,preCategory]=[params.data.name,params.data.category]//传递当前节点信息以供后续使用
}
//稍显曲折的原因在于通过事件获取的params参数无法修改,我们知晓了节点的基本信息,但修改它还需要去option中
//这一部分可以顺便设置传递一些变量的功能,把选中节点的信息暴露给后续的增删操作

实际上,我倾向于改变节点的模糊度(属性opacity 0到1从不显示到正常亮度)来实现选种效果,graph中series中名为focusNodeAdjacency的作用是鼠标移到节点上的时候突出显示节点以及节点的边和邻接节点,只要我们把它改成单击突出显示节点即可。我希望你可以在源码上修改,顺便学习下自定义构建方法,或者重新发布一个DIY的npm包。

需要修改的地方在echarts/lib/chart/graph/GraphView.js,这里贴上参考链接没有提及的对邻接点不作为的部分,各个Echarts版本可能有少许差异。
GraphView.js

实际代码参照源码的方案,通过设置全局的opacity(series.itemStyle.opacity、series.lineStyle.opacity)和单点的opacity(data.itemStyle.opacity)做到了类似功能,点击节点高亮,再点击恢复。

增删节点
//add
newNode=输入信息
newSource.source=selectName
newSource.target=newNode.name
data.push(newNode)
links.push(newSource)
//delete
data.splice(selectNode.index,1)
找出待删除节点的子节点有关的Clinks
Clinks.source=selectLinks.source
links.splice(selectLinks.index,1)
//以上push,splice操作同时作用于数据库

这个需要添加两个按钮(或者直接用事件区分,根据你具体情况也可以加上增加节点的信息填框)。选择(父)节点A之后,我们得到了需要增添或者删除节点A的name。增加节点时,通过data.push可以直接把新(子)节点加上去,然后在links数组中增加一项source为A,target为新节点名字的项;删除节点则有一些选择,比如将A的子节点连同A全部删除,或者只删除A,然后将A的子节点过渡到A的父节点上:前者通过A.name在数组links中找出所有source为A的target,然后在data数组中找到所有name符合这些target和A.name的项删除掉,如果不考虑重名的因素,links中的项可以不删除。后者找到所有source为A.name对应的target后,将source改为A对应的source即可(links中target为A.name对应的source)。

这部分可能会和其余功能有所冲突,需要注意是不是同时更新了数据库和视图的数据。具体细节有兴趣可以自行查看源代码。

addNode.gif
层级缩放
spread.gif

这个指的是双击(或者其他)节点展开或者收起该节点的子节点,可以参照Echarts中的另一图表类型tree的功能模样。在实现过程上和增删的查找一样,我们只需要维持两个数据集合,一个是后台传过来的option,另一个是当前容器内的option。拿着目标节点的信息在后台option中查找相应的子节点和连线信息,然后通过push、splice操作改变容器中的option

//伪代码
//通过数据库数据和视图数据的对比实现
//如果splice数据时没有顺便删除links数组那么数据库与视图的这部分是一样的

1.找出数据库中links中所有满足(edges.source===name)的项
2.if(edges.target in 当前视图){删除该项,第三步} //得出是否子节点的结论备用
3.name=node.target 返回第一步
递归结束
4.if(A has no child) {第五步} else end
5.找出数据库在links数组edges.source===name的项
6.找出数据库在data数组data.name===edges.target的项
7.if(data.name in 视图){do nothing} else{push.(data)}//如果第二步没有设计好,预防收起子节点之后增加节点的情形 (・ェ・。)

参考:文内链接
代码地址:https://github.com/southproject/echarts-demo

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,012评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,589评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,819评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,652评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,954评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,381评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,687评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,404评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,082评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,355评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,880评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,249评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,864评论 3 232
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,007评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,760评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,394评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,281评论 2 259

推荐阅读更多精彩内容

  • 我看见我在寻求不被爱的痛苦感受,我全心地接纳这种感受,并且放下对它的需要。
    诗屿yuu阅读 133评论 0 0
  • 回归教育改革本身,公众教育从来就很难让人满意。 前文提到卢梭对于18世界的法国教育的不满。 19世纪的尼采对于德国...
    单禅阅读 277评论 0 0
  • 早晨,躺在床上,突然想到自己定的计划,要坚持6点起床,一看表6:52了,赶快起床。思前想后,这样不行啊。一定得有个...
    吸烟的胖子阅读 304评论 0 0