ECharts關系圖,節點可拖拽,添加節點和邊的點擊事件


來源於  https://blog.csdn.net/Mu_Yue_Yue/article/details/90375758

 

最近在做一個neo4j前端可視化的任務,對比了ECharts.js,Cytoscape.js和D3.js幾個前端可視化工具,最終選擇了ECharts.js,百度的一款開源工具,簡單好用,比較容易上手。后台采用Python的Django框架,主要用於接收前端的請求,從neo4j數據庫獲取數據,並將數據傳給前端服務器展示。這里只展示ECharts的用法以及自己的一些總結,為以后打下一個基礎。首先展示下效果圖:

 

EChart.js下載:https://www.echartsjs.com/download.html
        點擊進入下載頁面后,選擇一個版本,點擊進入相應的github地址,在點擊source code(zip),下載完成后將其解壓,在dist文件夾下又一個echarts.js文件,這個文件就是我們需要的,將其復制到項目中相應的js目錄中即可。

 

        

由於這里采用的布局是force,不是通過坐標進行節點的生成,所以不能參考網上其他的采用坐標的節點拖拽。對此百度了許多,最后找到了一種合適的方法。我們需要對源碼進行一些修改,只需要注釋掉一行代碼即可進行拖拽,這個方法主要參考另一位作者:https://blog.csdn.net/qq_38880340/article/details/85683322。打開源碼,大概在1317行,將下圖所示注釋掉之后,選擇保存即可。       

我們在echarts.js同級目錄下新建一個html文件,在head中引入echarts.js,在body中設置一個div,一定要設置這個div的寬和高,不然不會顯示出關系圖,完整代碼如下所示。

        

  1 <!DOCTYPE html>
  2 <html lang="en">
  3 <head>
  4 <meta charset="UTF-8">
  5 <title>Echarts測試</title>
  6 <script src="echarts.js"></script>
  7 </head>
  8 <body>
  9 <div id="chart1" style="width: 1600px; height: 900px; margin: 0 auto; border: 2px solid #FF0000;"></div>
 10 </body>
 11 
 12 <script type="text/javascript">
 13 var entityRelation = [{"r": {"name": "推薦食譜"}, "m": {"name": "綠豆薏米飯"}}, {"r": {"name": "推薦食譜"}, "m": {"name": "姜絲蘿卜湯"}},
 14 {"r": {"name": "推薦食譜"}, "m": {"name": "蔥蒜粥"}}, {"r": {"name": "推薦食譜"}, "m": {"name": "薏米蓮子粥"}},
 15 {"r": {"name": "推薦食譜"}, "m": {"name": "赤小豆粥"}}, {"r": {"name": "推薦食譜"}, "m": {"name": "香椿芽粥"}},
 16 {"r": {"name": "推薦食譜"}, "m": {"name": "涼拌香椿"}}, {"r": {"name": "推薦食譜"}, "m": {"name": "醋熘土豆絲"}},
 17 {"r": {"name": "忌吃"}, "m": {"name": "豬油(板油)"}}, {"r": {"name": "忌吃"}, "m": {"name": "咸魚"}}, {"r": {"name": "忌吃"}, "m": {"name": "白扁豆"}},
 18 {"r": {"name": "忌吃"}, "m": {"name": "油條"}}, {"r": {"name": "宜吃"}, "m": {"name": "芝麻"}}, {"r": {"name": "宜吃"}, "m": {"name": "雞蛋"}},
 19 {"r": {"name": "宜吃"}, "m": {"name": "南瓜子仁"}}, {"r": {"name": "宜吃"}, "m": {"name": "鵪鶉蛋"}}, {"r": {"name": "所屬科室"}, "m": {"name": "呼吸內科"}},
 20 {"r": {"name": "常用葯品"}, "m": {"name": "感冒靈顆粒"}}, {"r": {"name": "常用葯品"}, "m": {"name": "利巴韋林顆粒"}}, {"r": {"name": "好評葯品"}, "m": {"name": "傷風停膠囊"}},
 21 {"r": {"name": "好評葯品"}, "m": {"name": "感冒靈顆粒"}}, {"r": {"name": "好評葯品"}, "m": {"name": "喉痛靈片"}}, {"r": {"name": "好評葯品"}, "m": {"name": "阿莫西林顆粒"}},
 22 {"r": {"name": "好評葯品"}, "m": {"name": "洛索洛芬鈉膠囊"}}, {"r": {"name": "好評葯品"}, "m": {"name": "酚咖片"}},
 23 {"r": {"name": "好評葯品"}, "m": {"name": "洛索洛芬鈉片"}}, {"r": {"name": "好評葯品"}, "m": {"name": "風油精"}}, {"r": {"name": "好評葯品"}, "m": {"name": "匹多莫德分散片"}},
 24 {"r": {"name": "好評葯品"}, "m": {"name": "依托紅霉素片"}}, {"r": {"name": "好評葯品"}, "m": {"name": "穿心蓮片"}}, {"r": {"name": "好評葯品"}, "m": {"name": "頭孢丙烯分散片"}},
 25 {"r": {"name": "好評葯品"}, "m": {"name": "麻黃止嗽丸"}}, {"r": {"name": "好評葯品"}, "m": {"name": "肺寧片"}}, {"r": {"name": "好評葯品"}, "m": {"name": "抗病毒口服液"}},
 26 {"r": {"name": "好評葯品"}, "m": {"name": "消炎片"}}, {"r": {"name": "好評葯品"}, "m": {"name": "頭孢拉定膠囊"}}, {"r": {"name": "好評葯品"}, "m": {"name": "蒲公英顆粒"}},
 27 {"r": {"name": "好評葯品"}, "m": {"name": "銀芩膠囊"}}, {"r": {"name": "好評葯品"}, "m": {"name": "愈美膠囊"}}, {"r": {"name": "診斷檢查"}, "m": {"name": "白細胞計數(WBC)"}},
 28 {"r": {"name": "診斷檢查"}, "m": {"name": "血常規"}}, {"r": {"name": "診斷檢查"}, "m": {"name": "肺和胸膜聽診"}}, {"r": {"name": "診斷檢查"}, "m": {"name": "尿常規"}},
 29 {"r": {"name": "診斷檢查"}, "m": {"name": "內科檢查"}}, {"r": {"name": "症狀"}, "m": {"name": "鼻塞"}}, {"r": {"name": "症狀"}, "m": {"name": "頭痛"}},
 30 {"r": {"name": "症狀"}, "m": {"name": "渾身忽冷忽熱"}}, {"r": {"name": "症狀"}, "m": {"name": "情緒性感冒"}}, {"r": {"name": "症狀"}, "m": {"name": "咽喉干燥及灼熱感"}},
 31 {"r": {"name": "症狀"}, "m": {"name": "發燒"}}, {"r": {"name": "症狀"}, "m": {"name": "發熱伴寒戰"}}, {"r": {"name": "症狀"}, "m": {"name": "咽痛"}},
 32 {"r": {"name": "症狀"}, "m": {"name": "流鼻涕"}}];
 33 // entityRelation中的r代表的關系,m代表的是第二個實體,這個數據是從neo4j數據庫查詢后進行json格式化后的,原數據過多,就刪減了一部分。
 34 var key_word = '感冒';
 35 
 36 var data = []; // echarts中的節點數組
 37 var links = []; // echarts中邊的數組
 38 
 39 // 獲取實體1, 也就是中心節點
 40 var node = {} ;
 41 node['name'] = key_word;
 42 node['draggable'] = true; // 設置中心節點是否可以拖拽
 43 var id = 0;
 44 node['id'] = id.toString();
 45 data.push(node);
 46 
 47 // 獲取實體2, 存儲在data中, 如果實體2已經存在於data中, 則不push
 48 var maxDisPlayNode = 16; // 對展示節點的數量進行限制
 49 // console.log("實體長度----->", entityRelation.length); // 顯示關系個數
 50 for(var i = 0; i < Math.min(maxDisPlayNode, entityRelation.length); i++) {
 51 node = {};
 52 node['name'] = entityRelation[i]['m']['name'];
 53 node['draggable'] = true;
 54 
 55 if(entityRelation[i]['r']['name'] == '所屬科室') {
 56 node['category'] = 1; // 節點分類, 數字代表option.series.categories中的索引
 57 } else if (entityRelation[i]['r']['name'] == '常用葯品') {
 58 node['category'] = 2;
 59 } else if (entityRelation[i]['r']['name'] == '宜吃') {
 60 node['category'] = 3;
 61 } else if (entityRelation[i]['r']['name'] == '診斷檢查') {
 62 node['category'] = 4;
 63 } else if (entityRelation[i]['r']['name'] == '忌吃') {
 64 node['category'] = 5;
 65 } else if (entityRelation[i]['r']['name'] == '好評葯品') {
 66 node['category'] = 6;
 67 } else if (entityRelation[i]['r']['name'] == '推薦食譜') {
 68 node['category'] = 7;
 69 } else if (entityRelation[i]['r']['name'] == '症狀') {
 70 node['category'] = 8;
 71 } else if (entityRelation[i]['r']['name'] == '並發症') {
 72 node['category'] = 9;
 73 } else if (entityRelation[i]['r']['name'] == '生產葯品') {
 74 node['category'] = 10;
 75 }
 76 
 77 id = i + 1;
 78 node['id'] = id.toString();
 79 
 80 var flag = 1;
 81 relationTarget = id.toString();
 82 for (var j = 0; j < data.length; j++) {
 83 if (data[j]['name'] === node['name']) {
 84 flag = 0;
 85 relationTarget = data[j]['id'];
 86 break;
 87 }
 88 }
 89 
 90 relation = {};
 91 relation['source'] = 0; // 關系起點, 數字代表的是節點的id, 即node[id]
 92 relation['target'] = relationTarget; // 關系指向的終點, 也是id, 即通過節點的id描述兩個節點以及關系
 93 relation['category'] = 0;
 94 
 95 if (flag === 1) {
 96 data.push(node);
 97 relation['value'] = entityRelation[i]['r']['name'];
 98 relation['symbolSize'] = 10;
 99 links.push(relation);
100 } else {
101 maxDisPlayNode += 1;
102 for (var k = 0; k < links.length; k++) {
103 if (links[k]['target'] === relationTarget) {
104 links[k]['value'] = links[k]['value'] + " | " + entityRelation[i]['r']['name'];
105 break;
106 }
107 }
108 }
109 }
110 // console.log("data====>>>", data);
111 // console.log("links====>>>", links);
112 
113 // 初始化echarts實例
114 var myChart = echarts.init(document.getElementById("chart1"));
115 
116 option = {
117 title: {
118 text: ''
119 },
120 tooltip: {},
121 animationDurationUpdate: 1500,
122 animationEasingUpdate: 'quinticInOut',
123 label: {
124 normal: {
125 show: true,
126 textStyle: {
127 fontSize: 12
128 },
129 }
130 },
131 legend: {
132 x: "center",
133 show: false
134 },
135 series: [
136 
137 {
138 type: 'graph',
139 layout: 'force',
140 symbolSize: 45,
141 focusNodeAdjacency: false, // 是否在鼠標移到節點上的時候突出顯示節點以及節點的邊和鄰接節點, 默認是true
142 roam: true,
143 edgeSymbol: ['none', 'arrow'],
144 categories: [{
145 name: '查詢實體',
146 itemStyle: {
147 normal: {
148 color: "#FF0000",
149 }
150 }
151 }, {
152 name: '所屬科室',
153 itemStyle: {
154 normal: {
155 color: "#4592FF",
156 }
157 }
158 }, {
159 name: '常用葯品',
160 itemStyle: {
161 normal: {
162 color: "#FFFF00",
163 }
164 }
165 }, {
166 name: '宜吃',
167 itemStyle: {
168 normal: {
169 color: "#66CD00",
170 }
171 }
172 }, {
173 name: '診斷檢查',
174 itemStyle: {
175 normal: {
176 color: "#B8860B",
177 }
178 }
179 }, {
180 name: '忌吃',
181 itemStyle: {
182 normal: {
183 color: "#B23AEE",
184 }
185 }
186 }, {
187 name: '好評葯品',
188 itemStyle: {
189 normal: {
190 color: "#FFB90F",
191 }
192 }
193 }, {
194 name: '推薦食譜',
195 itemStyle: {
196 normal: {
197 color: "#7FFF00",
198 }
199 }
200 },{
201 name: '症狀',
202 itemStyle: {
203 normal: {
204 color: "#F08080",
205 }
206 }
207 }, {
208 name: '並發症',
209 itemStyle: {
210 normal: {
211 color: "#87CEFA",
212 }
213 }
214 }, {
215 name: '生產葯品',
216 itemStyle: {
217 normal: {
218 color: "#FFFF00",
219 }
220 }
221 }],
222 label: {
223 normal: {
224 show: true,
225 textStyle: {
226 fontSize: 12,
227 fontStyle : 'normal',
228 fontWeight : 'bolder',
229 fontFamily : 'sans-serif',
230 },
231 }
232 },
233 force: {
234 repulsion: 1000,
235 edgeLength: [150, 100],
236 layoutAnimation : false
237 // 因為力引導布局會在多次迭代后才會穩定, 這個參數決定是否顯示布局的迭代動畫(節點數量過多, 圖在迭代的過程中會旋轉),
238 // 在瀏覽器端節點數據較多(>100)的時候不建議關閉, 布局過程會造成瀏覽器假死。
239 },
240 edgeSymbolSize: [4, 50],
241 edgeLabel: {
242 normal: {
243 show: true,
244 textStyle: {
245 fontSize: 10
246 },
247 formatter: "{c}" // 標簽內容格式器。模板變量有 {a}、{b}、{c},分別表示系列名,數據名,數據值。
248 }
249 },
250 data: data, // 節點
251 links: links, // 邊或者關系
252 lineStyle: {
253 normal: {
254 opacity: 0.5,
255 width: 1.0,
256 curveness: 0,
257 color: "#262626"
258 }
259 }
260 }
261 ]
262 };
263 myChart.setOption(option); // 這步很重要, 必須設置才可以有效
264 myChart.on('click', function (param){
265 console.log('param---->', param); // 打印出param, 可以看到里邊有很多參數可以使用
266 //獲取節點點擊的數組序號
267 var arrayIndex = param.dataIndex;
268 console.log('arrayIndex---->', arrayIndex);
269 console.log('name---->', param.name);
270 if (param.dataType == 'node') {
271 alert("點擊了節點" + param.name)
272 } else {
273 alert("點擊了邊" + param.value)
274 }
275 });
276 </script>
277 
278 </html>

 


        其中的entityRelation即為我們從后台獲得的經過處理后的數據(這里只是為了展示最后的關系圖,所以直接將數據寫在了這里),r 代表的關系,m 代表的是第二個實體,原數據過多,就刪除了其中的一部分。key_word為第一個實體,也是中心節點,entityRelation中的 r 指的就是中心點key_word到第二個實體 m 的關系。

        data[]是echart中所有的節點的數組,包括所有的實體,links[]即為實體之間所有關系的數組。每個節點都有id,name,category等參數,category主要用於節點(實體)的分類,不同種類的實體用不同的顏色區分出來,相關注釋可以在代碼中查看。relation主要描述的是起始節點和指向的結束節點,是links[]數組的參數。

       echarts中的參數過多,可以參考官方文檔,或者下載的source code中的例子,或者參考下邊的文章,對echarts的參數進行了總結:http://www.cnblogs.com/koala2016/archive/2016/12/01/6123003.html。

點擊事件:
        對節點和邊添加點擊事件,主要通過click方法實現,代碼可以參考上邊給出的。可以通過將param打印出來查看里邊的具體參數,更方便下一步的處理。
————————————————
版權聲明:本文為CSDN博主「沐玥」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/Mu_Yue_Yue/article/details/90375758


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM