Echarts关系图-力引导布局
Posted cowpea
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Echarts关系图-力引导布局相关的知识,希望对你有一定的参考价值。
需要做一个树形图,可以查看各个人员的关系。
可伸缩的力引导图-失败
刚开始,打算做一个可展开和伸缩的,搜索时候发现CSDN有一篇美美哒程序媛写的Echarts Force力导向图实现节点可折叠。
这里放上前辈的代码
/** 这段代码来自 http://blog.csdn.net/r4NqiAn/article/details/48320487 Echarts-Force 力导向布局图树状结构实现节点可折叠效果 作者:Reese 日期:2015-09-09 版本:V0.1 功能:点击一次节点,展开一级子节点;再次点击节点,折叠所有子孙节点; 弹出最终子节点的标签 备注:在使用该方法的时候,在nodes的属性里要自定义flag属性,并设置ignore */ var ecConfig = require(\'echarts/config\'); function openOrFold(param){ var linksNodes=[];//中间变量 var data=param.data;//表示当前选择的某一节点 var option = myChart.getOption();//获取已生成图形的Option var nodesOption=option.series[0].nodes;//获得所有节点的数组 var linksOption=option.series[0].links;//获得所有连接的数组 var categoryLength=option.series[0].categories.length;//获得类别数组的大小 /** 该段代码判断当前节点的category是否为最终子节点, 如果是,则弹出该节点的label */ if(data.category==(categoryLength-1)){ alert(data.label); } /**判断是否选择到了连接线上*/ if(data != null && data != undefined){ /** 判断所选节点的flag 如果为真,则表示要展开数据, 如果为假,则表示要折叠数据 */ if (data.flag) { /** 遍历连接关系数组 最终获得所选择节点的一层子节点 */ for(var m in linksOption){ //引用的连接关系的目标,既父节点是当前节点 if(linksOption[m].target==data.id){ linksNodes.push(linksOption[m].source);//获得子节点数组 } }//for(var m in linksOption){...} /** 遍历子节点数组 设置对应的option属性 */ if(linksNodes != null && linksNodes != undefined){ for(var p in linksNodes){ nodesOption[linksNodes[p]].ignore = false;//设置展示该节点 nodesOption[linksNodes[p]].flag = true; } } //设置该节点的flag为false,下次点击折叠子孙节点 nodesOption[data.id].flag = false; //重绘 myChart.setOption(option); }else{ /** 遍历连接关系数组 最终获得所选择节点的所有子孙子节点 */ for(var m in linksOption){ //引用的连接关系的目标,既父节点是当前节点 if(linksOption[m].target==data.id){ linksNodes.push(linksOption[m].source);//找到当前节点的第一层子节点 } if(linksNodes != null && linksNodes != undefined){ for(var n in linksNodes){ //第一层子节点作为父节点,找到所有子孙节点 if(linksOption[m].target==linksNodes[n]){ linksNodes.push(linksOption[m].source); } } } }//for(var m in linksOption){...} /** 遍历最终生成的连接关系数组 */ if(linksNodes != null && linksNodes != undefined){ for(var p in linksNodes){ nodesOption[linksNodes[p]].ignore = true;//设置折叠该节点 nodesOption[linksNodes[p]].flag = true; } } //设置该节点的flag为true,下次点击展开子节点 nodesOption[data.id].flag = true; //重绘 myChart.setOption(option); }//if (data.flag) {...} }//if(data != null && data != undefined){...} }//function openOrFold(param){...} myChart.on(ecConfig.EVENT.CLICK, openOrFold);
看了一下,思路很清晰。然后开始做,发现她的这代码有个问题就是折叠如果多层会有折叠不上的情况,也可能是我自己代码的原因。
需注意
1.在Echarts3中没有ignore属性,我发现data[].category如果对应值不存在的话,就会不显示节点,所以,再点击的时候设置子节点 x.category=x.category*-1;就可隐藏,显示时候同样反转就行。有需要特殊隐藏稍加一点判断就行。
nodesOption[linksNodes[p]].category = nodesOption[linksNodes[p]].category*-1;
2.不用多加自定义属性去折叠了,隐藏了就折叠了,但是得获取到递归获取到所有子id。这里还有些残留的代码片段
//先判断是要展开还是闭合:如果有一个category为正,则闭合;否则扩展一层 。 expend=true; for ( var p in linksNodes) { if(nodesOption[linksNodes[p]].category>0 ){ //&& !is_exist(linksOption,nodesOption,nodesOption[linksNodes[p]].id) expend=false; nodesOption[linksNodes[p]].category=Math.abs(nodesOption[linksNodes[p]].category)*-1; } nodesOption[linksNodes[p]].category=Math.abs(nodesOption[linksNodes[p]].category)*-1; //顺便使所有的值一致,全置为负值。因为关闭全关闭,展开只展开一层(特例)下面做处理就好、 //console.log(p+\':\'+nodesOption[linksNodes[p]].category) } if(expend){ //展开 一层 linksNodeArrs=[]; linksNodes_in=get_id(linksOption,data.id,0); //console.log(linksNodes_in) for ( var p in linksNodes_in) { nodesOption[linksNodes_in[p]].category = nodesOption[linksNodes_in[p]].category*-1; } }else{ //闭合不需要做处理 } //递归取所有 id function get_id(arr,cId,f=1){ for ( var m in arr) { if (arr[m].source == cId) { linksNodeArrs.push(arr[m].target); //linksNodeArrs.push(m); //console.log(arr[m].target); if(f) get_id(arr,arr[m].target); } } return linksNodeArrs; }
图一为简单的扩展折叠,完美
图二为有问题的折叠,点击[设计师B]时,[项目1]和[厂商D]应该存在,因为还有别的路径,逻辑错误,这里要弄折叠肯定得通过有向图比较好解决。不过这里暂时用不到,以后有机会填此坑。
那么,不考虑折叠了,考虑单击出相关一级子节点,双击只显示此节点的第一级。
可扩展,以及单独显示的力引导图
为了以后需要查数据库动态获取数据,所以暂时把关系都存到数据库里。主要有两组数据,一组是每个节点(数据),一组是他们的关系即连接线 。有人可能会想,这想一种数据结构,对,这就是有向图 :
扯回来,代码只是演示相关功能并不完善,这里将不详细介绍各代码,只是简单的取数据库而已,Echarts基础请看官方文档和技术文章。
数据库简单设计三个,categories各分类,nodes数据节点,links边(可以看到保存了关系)
TP代码:
#查询最基本的显示 public function index(){ ####分类查询#### $category=M(\'categories\')->field(\'name\')->where(\'name is not null\')->order(\'id asc\')->select();//注:需要从0排起 //legend,页顶部的标签 -可空 $legend_data=\' \'; foreach($category as $v){ $legend_data.="\'{$v[\'name\']}\',"; } $legend_data=substr($legend_data,0,-1); $this->assign(\'legend_data\',$legend_data); //分类,与legend同数据 $json_cate=json_encode($category,JSON_NUMERIC_CHECK); $this->assign(\'json_cate\',$json_cate); ####连接查询#### 查询第一层 $links_data=M(\'links\')->field(\'source,target,value,id as id_\')->order(\'id asc\')->where(\'source=0\')->select();// $id_str=\'0,\'; foreach($links_data as $v){ $id_str.="{$v[\'target\']},"; } $id_str=substr($id_str,0,-1); $links_data2=M(\'links\')->field(\'source,target,value,id as id_\')->order(\'id asc\')->where(" `source` in (%s) ",$id_str)->select(); foreach($links_data2 as $k=>$v){ $links_data[]=$v; } $json_links=json_encode($links_data); $this->assign(\'json_links\',$json_links); ####数据查询#### $where=array(); $where[\'id\']=array(\'in\',$id_str); $nodes_data=M(\'nodes\')->field(\'id,name,category\')->order(\'id asc\')->where($where)->select(); $json_nodes=json_encode($nodes_data,JSON_NUMERIC_CHECK); //echo $json_nodes; $this->assign(\'json_nodes\',$json_nodes); $this->display(); } public function only_show(){ //only_show函数等下点击节点时候ajax用。 $selfid=I(\'post.id\'); ####连接查询#### $map=array(); $map[\'_query\'] = "source=$selfid&target=$selfid&_logic=or"; $links_data=M(\'links\')->field(\'source,target,value\')->order(\'id asc\')->where($map)->select(); $id_str=\' \'; foreach($links_data as $v){ $id_str.="{$v[\'target\']},"; $id_str.="{$v[\'source\']},"; } $id_str=substr($id_str,0,-1); $links_data=M(\'links\')->field(\'source,target,value,id as id_\')->order(\'id asc\')->where(" `source` in (%s) or `target` in (%s) ",$id_str,$id_str)->select(); $json_links=json_encode($links_data); $result[\'json_links\']=$json_links; ####数据查询#### $where[\'id\']=array(\'in\',$id_str); $nodes_data=M(\'nodes\')->field(\'id as id,name,category\')->order(\'id asc\')->where($where)->select(); $json_nodes=json_encode($nodes_data,JSON_NUMERIC_CHECK); $result[\'json_nodes\']=$json_nodes; $this->ajaxReturn($result); }
视图代码:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title>关系图试验</title> 5 <meta charset="utf-8"> 6 <script type="text/javascript" src="__PUBLIC__/js/echarts.js"></script> 7 <script type="text/javascript" src="__PUBLIC__/js/jquery.js"></script> 8 9 </head> 10 <body> 11 <div id="main" style="width: 1000px;height:600px;"></div> 12 <script type="text/javascript"> 13 var linksNodeArrs=[]; 14 var TimeFn=null; 15 $(function(){ 16 17 option = { 18 title: { 19 text: \'测试关系图\' 20 }, 21 tooltip: {}, 22 //animationDurationUpdate: 1500, 23 animationEasingUpdate: \'quinticInOut\', 24 label: { 25 normal: { 26 show: true, 27 textStyle: { 28 fontSize: 12 29 }, 30 } 31 }, 32 legend: { 33 x: "center", 34 show: true, 35 data: [{$legend_data}] 36 }, 37 series: [ 38 { 39 //name:\'系列名\', 40 type: \'graph\', 41 layout: \'force\', 42 symbolSize: 45, 43 focusNodeAdjacency: true, //突出相关 44 roam: true, //鼠标缩放、平移 45 force: { //斥力因子 46 repulsion: 500, 47 edgeLength:[100,200], 48 }, 49 draggable:true, 50 tooltip:{ 51 trigger:\'item\', 52 backgroundColor: \'rgba(245, 244, 237,0.7)\' ,//提示框浮动背景色 53 borderColor:\'black\', 54 borderWidth:1, 55 textStyle:{ 56 color:\'black\', 57 fontWeight:\'bold\', 58 59 } 60 }, 61 62 categories: {$json_cate}, 63 label: { 64 normal: { 65 show: true, 66 textStyle: { 67 fontSize: 12 68 }, 69 } 70 }, 71 72 edgeSymbolSize: [0, 10], 73 edgeSymbol:\'arrow\', 74 75 edgeLabel: { 76 normal: { 77 show: true, 78 textStyle: { 79 fontSize: 10 80 }, 81 formatter: "{b}" 82 } 83 }, 84 nodes: {$json_nodes}, 85 links: {$json_links}, 86 lineStyle: { 87 normal: { 88 opacity: 0.9, 89 width: 1, 90 curveness: 0, 91 shadowColor: \'rgba(0, 0, 0, 0.8)\', 92 shadowBlur: 5, 93 shadowOffsetX:3, 94 shadowOffsetY:3, 95 }, 96 emphasis:{ 97 width:3 //hover时改变线宽 98 } 99 }, 100 101 102 } 103 ] 104 }; 105 106 //console.log(option) 107 var myChart = echarts.init(document.getElementById(\'main\')); 108 myChart.setOption(option); 109 110 //↑上面为加载完后初次显示 111 112 myChart.on(\'click\', cevent); 113 myChart.on(\'dblclick\', dbcevent); 114 115 function cevent(param) { 116 clearTimeout(TimeFn); 117 //执行延时 118 TimeFn = setTimeout(function(){ 119 var option = myChart.getOption(); 120 var data = param.data; 121 if (data != null && data != undefined) { 122 cid=data.id; 123 $.post("{:U(\'only_show\')}",{id:cid},function(rs){ 124 var json_nodes = eval(\'(\' + rs.json_nodes + \')\'); 125 var json_links = eval(\'(\' + rs.json_links + \'echarts关系图配置详解