├── .gitignore
├── display_img
└── display_force1.gif
├── 力向导图(forceSimulation)
├── d3_v5_forceSimulation.html
└── main.js
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | #
2 |
--------------------------------------------------------------------------------
/display_img/display_force1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BATFOR/D3.js_Visualization/HEAD/display_img/display_force1.gif
--------------------------------------------------------------------------------
/力向导图(forceSimulation)/d3_v5_forceSimulation.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
25 |
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 此代码基于前端可视化框架[d3.js](https://github.com/xswei/d3js_doc)。
2 | d3个人感觉和JQuery很像,主要对DOM进行数据绑定且进行相关操作。在学习D3之前,除了对HTML、css、js有相关应用了解外,还需对[SVG](https://www.runoob.com/svg/svg-rect.html)进行相关了解。d3中大部分函数库都是对数据进行处理
3 | ,然后将这这些处理了数据应用到画图展示上。
4 |
5 | ### 力向导图 ###
6 | **使用d3 v5版**
7 | **参考:** 此代码主要参考[https://github.com/zhaoluo123/vue-d3-force](https://github.com/zhaoluo123/vue-d3-force),去除了其中的vue模块,将d3版本从v3提升到v5。
8 |
9 | 力向导图可视,主要采用d3中力学仿真([**forceSimulation**](https://github.com/xswei/d3-force/blob/master/README.md#forceSimulation))模块,这个模块主要功能就是对数据不断进行仿真(可以根据需求添加多个具体的仿真模型,通过force函数),它会将每次仿真结果直接
10 | 以属性的方式直接加入(更新)到用户传入的**节点对象和边对象数据**中,比如会添加节点的x,y坐标等,每次仿真都会触发tick事件。而开发者需要做的就是在tick事件中进行图形的绘制渲染。
11 | 另外,[选择器(selection)](https://github.com/xswei/d3-selection/blob/master/README.md#selection)模块是d3中最常用的模块,和jQuery选择器一样,可对页面元素进行获取、属性更改、数据绑定等操作。
12 |
13 | **功能:**
14 | 1. 节点之间多关系绘制,节点自我关系绘制
15 | 2. 节点拖动放缩
16 | 3. 节点隐藏、解除固定(初始全部固定、拖动节点会触发当前节点固定)、删除(只编写函数接口)功能
17 | 
18 |
--------------------------------------------------------------------------------
/力向导图(forceSimulation)/main.js:
--------------------------------------------------------------------------------
1 | /***设备联系***/
2 |
3 | getNodeSelfPath = d => {
4 | if (d.relation.lineNumber === 1) {
5 | return "M" + (d.target.x + 25) + " " + (d.target.y - 10) + " C " + (d.target.x + 125) + " " + (d.target.y - 60) +
6 | "," + (d.target.x + 125) + " " + (d.target.y + 60) + "," + (d.target.x + 30) + " " + (d.target.y + 10);
7 | }
8 | if (d.relation.lineNumber === 2) {
9 | return "M" + (d.target.x - 10) + " " + (d.target.y - 25) + " C " + (d.target.x - 60) + " " + (d.target.y - 125) +
10 | "," + (d.target.x + 60) + " " + (d.target.y - 125) + "," + (d.target.x + 10) + " " + (d.target.y - 30);
11 | }
12 | if (d.relation.lineNumber === 3) {
13 | return "M" + (d.target.x - 25) + " " + (d.target.y + 10) + " C " + (d.target.x - 125) + " " + (d.target.y + 60) +
14 | "," + (d.target.x - 125) + " " + (d.target.y - 60) + "," + (d.target.x - 30) + " " + (d.target.y - 10);
15 | }
16 | if (d.relation.lineNumber === 4) {
17 | return "M" + (d.target.x + 10) + " " + (d.target.y + 25) + " C " + (d.target.x + 60) + " " + (d.target.y + 125) +
18 | "," + (d.target.x - 60) + " " + (d.target.y + 125) + "," + (d.target.x - 10) + " " + (d.target.y + 30);
19 | }
20 | };
21 |
22 | getNodesLine = d => {
23 |
24 | d.sourceRadius = 26;
25 | d.targetRadius = 31;
26 | let tan = Math.abs((d.target.y - d.source.y) / (d.target.x - d.source.x)); //圆心连线tan值
27 | let x1 = d.target.x - d.source.x > 0 ? Math.sqrt(d.sourceRadius * d.sourceRadius / (tan * tan + 1)) + d.source.x :
28 | d.source.x - Math.sqrt(d.sourceRadius * d.sourceRadius / (tan * tan + 1)); //起点x坐标
29 | let y1 = d.target.y - d.source.y > 0 ? Math.sqrt(d.sourceRadius * d.sourceRadius * tan * tan / (tan * tan + 1)) + d.source.y :
30 | d.source.y - Math.sqrt(d.sourceRadius * d.sourceRadius * tan * tan / (tan * tan + 1)); //起点y坐标
31 | let x2 = d.target.x - d.source.x > 0 ? d.target.x - Math.sqrt(d.targetRadius * d.targetRadius / (1 + tan * tan)) :
32 | d.target.x + Math.sqrt(d.targetRadius * d.targetRadius / (1 + tan * tan)); //终点x坐标
33 | let y2 = d.target.y - d.source.y > 0 ? d.target.y - Math.sqrt(d.targetRadius * d.targetRadius * tan * tan / (1 + tan * tan)) :
34 | d.target.y + Math.sqrt(d.targetRadius * d.targetRadius * tan * tan / (1 + tan * tan)); //终点y坐标
35 | if (d.target.x - d.source.x === 0 || tan === 0) { //斜率无穷大的情况或为0时
36 | y1 = d.target.y - d.source.y > 0 ? d.source.y + d.sourceRadius : d.source.y - d.sourceRadius;
37 | y2 = d.target.y - d.source.y > 0 ? d.target.y - d.targetRadius : d.target.y + d.targetRadius;
38 | }
39 | if (d.linknum === 0) { //设置编号为0的连接线为直线,其他连接线会均分在两边
40 | d.x_start = x1;
41 | d.y_start = y1;
42 | d.x_end = x2;
43 | d.y_end = y2;
44 | return 'M' + x1 + ' ' + y1 + ' L ' + x2 + ' ' + y2;
45 | }
46 | let a = d.sourceRadius > d.targetRadius ? d.targetRadius * d.linknum / 3 : d.sourceRadius * d.linknum / 3;
47 | let xm = d.target.x - d.source.x > 0 ? d.source.x + Math.sqrt((d.sourceRadius * d.sourceRadius - a * a) / (1 + tan * tan)) :
48 | d.source.x - Math.sqrt((d.sourceRadius * d.sourceRadius - a * a) / (1 + tan * tan));
49 | let ym = d.target.y - d.source.y > 0 ? d.source.y + Math.sqrt((d.sourceRadius * d.sourceRadius - a * a) * tan * tan / (1 + tan * tan)) :
50 | d.source.y - Math.sqrt((d.sourceRadius * d.sourceRadius - a * a) * tan * tan / (1 + tan * tan));
51 | let xn = d.target.x - d.source.x > 0 ? d.target.x - Math.sqrt((d.targetRadius * d.targetRadius - a * a) / (1 + tan * tan)) :
52 | d.target.x + Math.sqrt((d.targetRadius * d.targetRadius - a * a) / (1 + tan * tan));
53 | let yn = d.target.y - d.source.y > 0 ? d.target.y - Math.sqrt((d.targetRadius * d.targetRadius - a * a) * tan * tan / (1 + tan * tan)) :
54 | d.target.y + Math.sqrt((d.targetRadius * d.targetRadius - a * a) * tan * tan / (1 + tan * tan));
55 | if (d.target.x - d.source.x === 0 || tan === 0) { //斜率无穷大或为0时
56 | ym = d.target.y - d.source.y > 0 ? d.source.y + Math.sqrt(d.sourceRadius * d.sourceRadius - a * a) : d.source.y - Math.sqrt(d.sourceRadius * d.sourceRadius - a * a);
57 | yn = d.target.y - d.source.y > 0 ? d.target.y - Math.sqrt(d.targetRadius * d.targetRadius - a * a) : d.target.y + Math.sqrt(d.targetRadius * d.targetRadius - a * a);
58 | }
59 |
60 | let k = (x1 - x2) / (y2 - y1); //连线垂线的斜率
61 | let dx = Math.sqrt(a * a / (1 + k * k)); //相对垂点x轴距离
62 | let dy = Math.sqrt(a * a * k * k / (1 + k * k)); //相对垂点y轴距离
63 | if ((y2 - y1) === 0) {
64 | dx = 0;
65 | dy = Math.sqrt(a * a);
66 | }
67 | let xs, ys, xt, yt;
68 | if (a > 0) {
69 | xs = k > 0 ? xm - dx : xm + dx;
70 | ys = ym - dy;
71 | xt = k > 0 ? xn - dx : xn + dx;
72 | yt = yn - dy;
73 | } else {
74 | xs = k > 0 ? xm + dx : xm - dx;
75 | ys = ym + dy;
76 | xt = k > 0 ? xn + dx : xn - dx;
77 | yt = yn + dy;
78 | }
79 |
80 | //记录连线起始和终止坐标,用于定位线上文字
81 | d.x_start = xs;
82 | d.y_start = ys;
83 | d.x_end = xt;
84 | d.y_end = yt;
85 |
86 | //return 'M' + xs + ' ' + ys + "L" + + xt + ' ' + yt;//绘制直线
87 | let NodesDistance = Math.sqrt(Math.pow(d.source.x - d.target.x, 2) + Math.pow(d.source.y - d.target.y, 2));
88 | let rad = 200;
89 | if (300 >= NodesDistance && NodesDistance > 150) {
90 | rad = 300
91 | } else if (450 >= NodesDistance && NodesDistance > 300) {
92 | rad = 400
93 | } else if (600 >= NodesDistance && NodesDistance > 450) {
94 | rad = 500
95 | } else if (750 >= NodesDistance && NodesDistance > 600) {
96 | rad = 600
97 | } else if (900 >= NodesDistance && NodesDistance > 750) {
98 | rad = 700
99 | } else if (1050 >= NodesDistance && NodesDistance > 900) {
100 | rad = 800
101 | } else if (1200 >= NodesDistance && NodesDistance > 1050) {
102 | rad = 900
103 | }
104 |
105 | if (d.source.x < d.target.x) { //绘制曲线
106 | if (d.linknum < 0) {
107 | return "M" + xs + "," + ys + "A" + rad + "," + rad + " 0 0,0 " + xt + "," + yt;
108 | } else {
109 | return "M" + xs + "," + ys + "A" + rad + "," + rad + " 0 0,1 " + xt + "," + yt;
110 | }
111 | } else {
112 | if (d.linknum < 0) {
113 | return "M" + xs + "," + ys + "A" + rad + "," + rad + " 0 0,1 " + xt + "," + yt;
114 | } else {
115 | return "M" + xs + "," + ys + "A" + rad + "," + rad + " 0 0,0 " + xt + "," + yt;
116 | }
117 | }
118 | };
119 |
120 | setLinkNumber = (group) => {
121 | if (group.length === 0) return;
122 | if (group.length === 1) {
123 | group[0].linknum = 0;
124 | return;
125 | }
126 | let maxLinkNumber = group.length % 2 === 0 ? group.length / 2 : (group.length - 1) / 2;
127 | if (group.length % 2 === 0) {
128 | let startLinkNum = -maxLinkNumber + 0.5;
129 | for (let i = 0; i < group.length; i++) {
130 | group[i].linknum = startLinkNum++;
131 | }
132 | } else {
133 | let startLinkNum = -maxLinkNumber;
134 | for (let i = 0; i < group.length; i++) {
135 | group[i].linknum = startLinkNum++;
136 | }
137 | }
138 | };
139 |
140 | setLinkGroup = links => {
141 | let linkGroup = {};
142 | //对连接线进行统计和分组,不区分连接线的方向,只要属于同两个实体,即认为是同一组
143 | let linkmap = {};
144 | for (let i = 0; i < links.length; i++) {
145 | let key = links[i].source < links[i].target ? links[i].source + ':' + links[i].target : links[i].target + ':' + links[i].source;
146 | if (!linkmap.hasOwnProperty(key)) {
147 | linkmap[key] = 0;
148 | }
149 | linkmap[key] += 1;
150 | if (!linkGroup.hasOwnProperty(key)) {
151 | linkGroup[key] = [];
152 | }
153 | linkGroup[key].push(links[i]);
154 | }
155 | //为每一条连接线分配size属性,同时对每一组连接线进行编号
156 | for (let i = 0; i < links.length; i++) {
157 | let key = links[i].source < links[i].target ? links[i].source + ':' + links[i].target : links[i].target + ':' + links[i].source;
158 | links[i].size = linkmap[key];
159 | //同一组的关系进行编号
160 | let group = linkGroup[key];
161 | //给节点分配编号
162 | setLinkNumber(group);
163 | }
164 |
165 | };
166 |
167 | var my_data = {
168 | "links": [{
169 | "source": 0,
170 | "target": 1,
171 | "relation": {
172 | "relationshipId": 200,
173 | "relationship": "BELONG_APPLICATION",
174 | "created": 1574822650825,
175 | "lineNumber": null,
176 | "isSelf": false
177 | }
178 | }, {
179 | "source": 2,
180 | "target": 3,
181 | "relation": {
182 | "relationshipId": 135,
183 | "relationship": "EFFECT_LOCATION",
184 | "created": 1574821264333,
185 | "lineNumber": null,
186 | "isSelf": false
187 | }
188 | }, {
189 | "source": 6,
190 | "target": 7,
191 | "relation": {
192 | "relationshipId": 123,
193 | "relationship": "BELONG_MANUFACTURER",
194 | "created": 1574143813834,
195 | "lineNumber": null,
196 | "isSelf": false
197 | }
198 | }, {
199 | "source": 8,
200 | "target": 9,
201 | "relation": {
202 | "relationshipId": 132,
203 | "relationship": "PARENT",
204 | "created": 1571109959476,
205 | "lineNumber": null,
206 | "isSelf": false
207 | }
208 | }, {
209 | "source": 10,
210 | "target": 11,
211 | "relation": {
212 | "relationshipId": 145,
213 | "relationship": "AUTHORIZE_APPLICATION",
214 | "created": 1574409066966,
215 | "lineNumber": null,
216 | "isSelf": false
217 | }
218 | }, {
219 | "source": 12,
220 | "target": 13,
221 | "relation": {
222 | "relationshipId": 103,
223 | "relationship": "BELONG_APPLICATION",
224 | "created": 1574229503622,
225 | "lineNumber": null,
226 | "isSelf": false
227 | }
228 | }, {
229 | "source": 14,
230 | "target": 15,
231 | "relation": {
232 | "relationshipId": 95,
233 | "relationship": "AUTHORIZE_APPLICATION",
234 | "created": 1574218526058,
235 | "lineNumber": null,
236 | "isSelf": false
237 | }
238 | }, {
239 | "source": 0,
240 | "target": 16,
241 | "relation": {
242 | "relationshipId": 202,
243 | "relationship": "EFFECT_LOCATION",
244 | "created": 1574825180239,
245 | "lineNumber": null,
246 | "isSelf": false
247 | }
248 | }, {
249 | "source": 19,
250 | "target": 20,
251 | "relation": {
252 | "relationshipId": 180,
253 | "relationship": "CONTROL",
254 | "created": 1574652545781,
255 | "lineNumber": null,
256 | "isSelf": false
257 | }
258 | }, {
259 | "source": 2,
260 | "target": 2,
261 | "relation": {
262 | "relationshipId": 198,
263 | "relationship": "PARENT",
264 | "created": 1574821366951,
265 | "lineNumber": 1,
266 | "isSelf": true
267 | }
268 | }, {
269 | "source": 8,
270 | "target": 22,
271 | "relation": {
272 | "relationshipId": 141,
273 | "relationship": "PARENT",
274 | "created": 1571189421890,
275 | "lineNumber": null,
276 | "isSelf": false
277 | }
278 | }, {
279 | "source": 10,
280 | "target": 10,
281 | "relation": {
282 | "relationshipId": 163,
283 | "relationship": "PARENT",
284 | "created": 1574409116976,
285 | "lineNumber": 1,
286 | "isSelf": true
287 | }
288 | }, {
289 | "source": 9,
290 | "target": 8,
291 | "relation": {
292 | "relationshipId": 131,
293 | "relationship": "CONTROL",
294 | "created": 1571109777550,
295 | "lineNumber": null,
296 | "isSelf": false
297 | }
298 | }, {
299 | "source": 25,
300 | "target": 26,
301 | "relation": {
302 | "relationshipId": 182,
303 | "relationship": "EFFECT_LOCATION",
304 | "created": 1574734111195,
305 | "lineNumber": null,
306 | "isSelf": false
307 | }
308 | }, {
309 | "source": 6,
310 | "target": 6,
311 | "relation": {
312 | "relationshipId": 12,
313 | "relationship": "PARENT",
314 | "created": 1574142984212,
315 | "lineNumber": 1,
316 | "isSelf": true
317 | }
318 | }, {
319 | "source": 8,
320 | "target": 28,
321 | "relation": {
322 | "relationshipId": 60,
323 | "relationship": "PARENT",
324 | "created": 1571189421890,
325 | "lineNumber": null,
326 | "isSelf": false
327 | }
328 | }, {
329 | "source": 29,
330 | "target": 22,
331 | "relation": {
332 | "relationshipId": 118,
333 | "relationship": "PARENT",
334 | "created": 1571281100918,
335 | "lineNumber": null,
336 | "isSelf": false
337 | }
338 | }, {
339 | "source": 30,
340 | "target": 31,
341 | "relation": {
342 | "relationshipId": 82,
343 | "relationship": "BELONG_MANUFACTURER",
344 | "created": 1574842004656,
345 | "lineNumber": null,
346 | "isSelf": false
347 | }
348 | }, {
349 | "source": 0,
350 | "target": 32,
351 | "relation": {
352 | "relationshipId": 199,
353 | "relationship": "CONNECT_PLATFORM",
354 | "created": 1574822498689,
355 | "lineNumber": null,
356 | "isSelf": false
357 | }
358 | }, {
359 | "source": 33,
360 | "target": 34,
361 | "relation": {
362 | "relationshipId": 68,
363 | "relationship": "CONTROL",
364 | "created": 1570777779101,
365 | "lineNumber": null,
366 | "isSelf": false
367 | }
368 | }, {
369 | "source": 29,
370 | "target": 35,
371 | "relation": {
372 | "relationshipId": 3,
373 | "relationship": "PARENT",
374 | "created": 1571281100918,
375 | "lineNumber": null,
376 | "isSelf": false
377 | }
378 | }, {
379 | "source": 2,
380 | "target": 36,
381 | "relation": {
382 | "relationshipId": 194,
383 | "relationship": "CONNECT_PLATFORM",
384 | "created": 1574821180519,
385 | "lineNumber": null,
386 | "isSelf": false
387 | }
388 | }, {
389 | "source": 37,
390 | "target": 38,
391 | "relation": {
392 | "relationshipId": 190,
393 | "relationship": "BELONG_ADMIN",
394 | "created": 1574745879106,
395 | "lineNumber": null,
396 | "isSelf": false
397 | }
398 | }, {
399 | "source": 40,
400 | "target": 41,
401 | "relation": {
402 | "relationshipId": 1,
403 | "relationship": "BELONG_MANUFACTURER",
404 | "created": 1574130631578,
405 | "lineNumber": null,
406 | "isSelf": false
407 | }
408 | }, {
409 | "source": 8,
410 | "target": 35,
411 | "relation": {
412 | "relationshipId": 98,
413 | "relationship": "PARENT",
414 | "created": 1571189421890,
415 | "lineNumber": null,
416 | "isSelf": false
417 | }
418 | }, {
419 | "source": 10,
420 | "target": 42,
421 | "relation": {
422 | "relationshipId": 138,
423 | "relationship": "BELONG_APPLICATION",
424 | "created": 1574408689645,
425 | "lineNumber": null,
426 | "isSelf": false
427 | }
428 | }, {
429 | "source": 33,
430 | "target": 34,
431 | "relation": {
432 | "relationshipId": 66,
433 | "relationship": "PARENT",
434 | "created": 1570777635645,
435 | "lineNumber": null,
436 | "isSelf": false
437 | }
438 | }, {
439 | "source": 2,
440 | "target": 2,
441 | "relation": {
442 | "relationshipId": 192,
443 | "relationship": "CONTROL",
444 | "created": 1574821284400,
445 | "lineNumber": 2,
446 | "isSelf": true
447 | }
448 | }, {
449 | "source": 14,
450 | "target": 15,
451 | "relation": {
452 | "relationshipId": 94,
453 | "relationship": "BELONG_APPLICATION",
454 | "created": 1574218478704,
455 | "lineNumber": null,
456 | "isSelf": false
457 | }
458 | }, {
459 | "source": 44,
460 | "target": 9,
461 | "relation": {
462 | "relationshipId": 11,
463 | "relationship": "PARENT",
464 | "created": 1571189497514,
465 | "lineNumber": null,
466 | "isSelf": false
467 | }
468 | }, {
469 | "source": 10,
470 | "target": 45,
471 | "relation": {
472 | "relationshipId": 183,
473 | "relationship": "PARENT",
474 | "created": 1574734473815,
475 | "lineNumber": null,
476 | "isSelf": false
477 | }
478 | }, {
479 | "source": 46,
480 | "target": 47,
481 | "relation": {
482 | "relationshipId": 108,
483 | "relationship": "BELONG_MANUFACTURER",
484 | "created": 1574401675435,
485 | "lineNumber": null,
486 | "isSelf": false
487 | }
488 | }, {
489 | "source": 10,
490 | "target": 48,
491 | "relation": {
492 | "relationshipId": 185,
493 | "relationship": "EFFECT_LOCATION",
494 | "created": 1574735098436,
495 | "lineNumber": null,
496 | "isSelf": false
497 | }
498 | }, {
499 | "source": 30,
500 | "target": 49,
501 | "relation": {
502 | "relationshipId": 92,
503 | "relationship": "BELONG_ADMIN",
504 | "created": 1574842038292,
505 | "lineNumber": null,
506 | "isSelf": false
507 | }
508 | }, {
509 | "source": 30,
510 | "target": 50,
511 | "relation": {
512 | "relationshipId": 102,
513 | "relationship": "BELONG_ADMIN",
514 | "created": 1574842038292,
515 | "lineNumber": null,
516 | "isSelf": false
517 | }
518 | }, {
519 | "source": 2,
520 | "target": 1,
521 | "relation": {
522 | "relationshipId": 196,
523 | "relationship": "BELONG_APPLICATION",
524 | "created": 1574821237662,
525 | "lineNumber": null,
526 | "isSelf": false
527 | }
528 | }, {
529 | "source": 51,
530 | "target": 52,
531 | "relation": {
532 | "relationshipId": 39,
533 | "relationship": "PARENT",
534 | "created": 1571040502085,
535 | "lineNumber": null,
536 | "isSelf": false
537 | }
538 | }, {
539 | "source": 37,
540 | "target": 53,
541 | "relation": {
542 | "relationshipId": 191,
543 | "relationship": "BELONG_ADMIN",
544 | "created": 1574745879106,
545 | "lineNumber": null,
546 | "isSelf": false
547 | }
548 | }, {
549 | "source": 8,
550 | "target": 54,
551 | "relation": {
552 | "relationshipId": 77,
553 | "relationship": "PARENT",
554 | "created": 1571189421890,
555 | "lineNumber": null,
556 | "isSelf": false
557 | }
558 | }, {
559 | "source": 55,
560 | "target": 56,
561 | "relation": {
562 | "relationshipId": 130,
563 | "relationship": "EFFECT_LOCATION",
564 | "created": 1574322233908,
565 | "lineNumber": null,
566 | "isSelf": false
567 | }
568 | }, {
569 | "source": 30,
570 | "target": 13,
571 | "relation": {
572 | "relationshipId": 133,
573 | "relationship": "AUTHORIZE_APPLICATION",
574 | "created": 1574842153352,
575 | "lineNumber": null,
576 | "isSelf": false
577 | }
578 | }, {
579 | "source": 0,
580 | "target": 58,
581 | "relation": {
582 | "relationshipId": 201,
583 | "relationship": "BELONG_MANUFACTURER",
584 | "created": 1574825160187,
585 | "lineNumber": null,
586 | "isSelf": false
587 | }
588 | }, {
589 | "source": 34,
590 | "target": 33,
591 | "relation": {
592 | "relationshipId": 100,
593 | "relationship": "CONTROL",
594 | "created": 1570779022030,
595 | "lineNumber": null,
596 | "isSelf": false
597 | }
598 | }, {
599 | "source": 19,
600 | "target": 59,
601 | "relation": {
602 | "relationshipId": 99,
603 | "relationship": "BELONG_APPLICATION",
604 | "created": 1574652203566,
605 | "lineNumber": null,
606 | "isSelf": false
607 | }
608 | }, {
609 | "source": 8,
610 | "target": 44,
611 | "relation": {
612 | "relationshipId": 143,
613 | "relationship": "PARENT",
614 | "created": 1571189421890,
615 | "lineNumber": null,
616 | "isSelf": false
617 | }
618 | }, {
619 | "source": 44,
620 | "target": 8,
621 | "relation": {
622 | "relationshipId": 139,
623 | "relationship": "PARENT",
624 | "created": 1571122040940,
625 | "lineNumber": null,
626 | "isSelf": false
627 | }
628 | }, {
629 | "source": 44,
630 | "target": 22,
631 | "relation": {
632 | "relationshipId": 124,
633 | "relationship": "PARENT",
634 | "created": 1571189497514,
635 | "lineNumber": null,
636 | "isSelf": false
637 | }
638 | }, {
639 | "source": 45,
640 | "target": 61,
641 | "relation": {
642 | "relationshipId": 187,
643 | "relationship": "BELONG_MANUFACTURER",
644 | "created": 1574736042772,
645 | "lineNumber": null,
646 | "isSelf": false
647 | }
648 | }, {
649 | "source": 30,
650 | "target": 62,
651 | "relation": {
652 | "relationshipId": 181,
653 | "relationship": "AUTHORIZE_APPLICATION",
654 | "created": 1574842153352,
655 | "lineNumber": null,
656 | "isSelf": false
657 | }
658 | }, {
659 | "source": 44,
660 | "target": 28,
661 | "relation": {
662 | "relationshipId": 10,
663 | "relationship": "PARENT",
664 | "created": 1571189497514,
665 | "lineNumber": null,
666 | "isSelf": false
667 | }
668 | }, {
669 | "source": 44,
670 | "target": 54,
671 | "relation": {
672 | "relationshipId": 128,
673 | "relationship": "PARENT",
674 | "created": 1571189497514,
675 | "lineNumber": null,
676 | "isSelf": false
677 | }
678 | }, {
679 | "source": 10,
680 | "target": 63,
681 | "relation": {
682 | "relationshipId": 184,
683 | "relationship": "EFFECT_LOCATION",
684 | "created": 1574735076416,
685 | "lineNumber": null,
686 | "isSelf": false
687 | }
688 | }, {
689 | "source": 14,
690 | "target": 14,
691 | "relation": {
692 | "relationshipId": 93,
693 | "relationship": "PARENT",
694 | "created": 1574217786986,
695 | "lineNumber": 1,
696 | "isSelf": true
697 | }
698 | }, {
699 | "source": 64,
700 | "target": 65,
701 | "relation": {
702 | "relationshipId": 44,
703 | "relationship": "CONNECT_PLATFORM",
704 | "created": 1574758583985,
705 | "lineNumber": null,
706 | "isSelf": false
707 | }
708 | }, {
709 | "source": 29,
710 | "target": 8,
711 | "relation": {
712 | "relationshipId": 43,
713 | "relationship": "PARENT",
714 | "created": 1571281100918,
715 | "lineNumber": null,
716 | "isSelf": false
717 | }
718 | }, {
719 | "source": 10,
720 | "target": 67,
721 | "relation": {
722 | "relationshipId": 23,
723 | "relationship": "BELONG_MANUFACTURER",
724 | "created": 1574408725149,
725 | "lineNumber": null,
726 | "isSelf": false
727 | }
728 | }, {
729 | "source": 2,
730 | "target": 68,
731 | "relation": {
732 | "relationshipId": 195,
733 | "relationship": "BELONG_ADMIN",
734 | "created": 1574821199052,
735 | "lineNumber": null,
736 | "isSelf": false
737 | }
738 | }, {
739 | "source": 10,
740 | "target": 10,
741 | "relation": {
742 | "relationshipId": 9,
743 | "relationship": "CONTROL",
744 | "created": 1574408971838,
745 | "lineNumber": 2,
746 | "isSelf": true
747 | }
748 | }, {
749 | "source": 71,
750 | "target": 71,
751 | "relation": {
752 | "relationshipId": 46,
753 | "relationship": "CONTROL",
754 | "created": 1571721495529,
755 | "lineNumber": 1,
756 | "isSelf": true
757 | }
758 | }, {
759 | "source": 2,
760 | "target": 73,
761 | "relation": {
762 | "relationshipId": 197,
763 | "relationship": "BELONG_MANUFACTURER",
764 | "created": 1574821249233,
765 | "lineNumber": null,
766 | "isSelf": false
767 | }
768 | }, {
769 | "source": 74,
770 | "target": 10,
771 | "relation": {
772 | "relationshipId": 45,
773 | "relationship": "CONTROL",
774 | "created": 1574401909220,
775 | "lineNumber": null,
776 | "isSelf": false
777 | }
778 | }, {
779 | "source": 19,
780 | "target": 75,
781 | "relation": {
782 | "relationshipId": 117,
783 | "relationship": "CONTROL",
784 | "created": 1574652545781,
785 | "lineNumber": null,
786 | "isSelf": false
787 | }
788 | }, {
789 | "source": 6,
790 | "target": 76,
791 | "relation": {
792 | "relationshipId": 144,
793 | "relationship": "CONTROL",
794 | "created": 1574142879454,
795 | "lineNumber": null,
796 | "isSelf": false
797 | }
798 | }, {
799 | "source": 8,
800 | "target": 8,
801 | "relation": {
802 | "relationshipId": 142,
803 | "relationship": "PARENT",
804 | "created": 1571189421890,
805 | "lineNumber": 1,
806 | "isSelf": true
807 | }
808 | }, {
809 | "source": 10,
810 | "target": 63,
811 | "relation": {
812 | "relationshipId": 186,
813 | "relationship": "INSTALL_LOCATION",
814 | "created": 1574735183907,
815 | "lineNumber": null,
816 | "isSelf": false
817 | }
818 | }, {
819 | "source": 52,
820 | "target": 51,
821 | "relation": {
822 | "relationshipId": 122,
823 | "relationship": "CONTROL",
824 | "created": 1571040489911,
825 | "lineNumber": null,
826 | "isSelf": false
827 | }
828 | }, {
829 | "source": 2,
830 | "target": 77,
831 | "relation": {
832 | "relationshipId": 193,
833 | "relationship": "INSTALL_LOCATION",
834 | "created": 1574821301840,
835 | "lineNumber": null,
836 | "isSelf": false
837 | }
838 | }, {
839 | "source": 44,
840 | "target": 35,
841 | "relation": {
842 | "relationshipId": 79,
843 | "relationship": "PARENT",
844 | "created": 1571189497514,
845 | "lineNumber": null,
846 | "isSelf": false
847 | }
848 | }],
849 | "nodes": [{
850 | "id": 1,
851 | "deviceId": "002101025d09c809e4b0ca3a6a0966d2",
852 | "factoryCode": "061901",
853 | "modelCode": "00210102",
854 | "label": "Device",
855 | "linkId": 0
856 | }, {
857 | "id": 43,
858 | "applicationName": "测试盘古",
859 | "appId": "com.huawei.pangu",
860 | "label": "Application",
861 | "linkId": 1
862 | }, {
863 | "id": 18,
864 | "deviceId": "004801055dd4f157e4b04845806d6671",
865 | "factoryCode": "1120device002",
866 | "modelCode": "00480105",
867 | "label": "Device",
868 | "linkId": 2
869 | }, {
870 | "id": 140,
871 | "positionNumber": "887",
872 | "positionCode": "098",
873 | "label": "Position",
874 | "linkId": 3
875 | }, {
876 | "id": 86,
877 | "deviceId": "huo1a1005d5647ed270e07fad941eb33",
878 | "factoryCode": "huo11111111ww",
879 | "modelCode": "huoaa01a100",
880 | "label": "Device",
881 | "linkId": 4
882 | }, {
883 | "id": 125,
884 | "deviceId": "hye029015dc3b5df270e2cc0b2a2641c",
885 | "factoryCode": "dsafafaf666",
886 | "modelCode": "hye02901",
887 | "label": "Device",
888 | "linkId": 5
889 | }, {
890 | "id": 24,
891 | "deviceId": "000801025d0c7e438466e74289f900ef",
892 | "factoryCode": "buchongceshi2",
893 | "modelCode": "00080102",
894 | "label": "Device",
895 | "linkId": 6
896 | }, {
897 | "id": 163,
898 | "manufacturerCode": "HJJc",
899 | "manufacturerName": "测试厂商",
900 | "label": "Manufacturer",
901 | "linkId": 7
902 | }, {
903 | "id": 118,
904 | "deviceId": "004901015da53819e4b0bf772bd36775",
905 | "factoryCode": "13241341324143",
906 | "modelCode": null,
907 | "label": "Device",
908 | "linkId": 8
909 | }, {
910 | "id": 121,
911 | "deviceId": "004901015da53785e4b0bf772bd36774",
912 | "factoryCode": "58656745",
913 | "modelCode": "00490101",
914 | "label": "Device",
915 | "linkId": 9
916 | }, {
917 | "id": 2,
918 | "deviceId": "004101015dd7502ae4b0c5015d3aebe8",
919 | "factoryCode": "test1234",
920 | "modelCode": "00410101",
921 | "label": "Device",
922 | "linkId": 10
923 | }, {
924 | "id": 122,
925 | "applicationName": "测试2",
926 | "appId": "ceshi2",
927 | "label": "Application",
928 | "linkId": 11
929 | }, {
930 | "id": 105,
931 | "deviceId": "aa01a1005dce4dde0bfb1be4b75abe40",
932 | "factoryCode": "632598",
933 | "modelCode": "00080101",
934 | "label": "Device",
935 | "linkId": 12
936 | }, {
937 | "id": 131,
938 | "applicationName": "云企划2",
939 | "appId": "experienceUser",
940 | "label": "Application",
941 | "linkId": 13
942 | }, {
943 | "id": 111,
944 | "deviceId": "000901015d269b8bf140f7aa0df8b95a",
945 | "factoryCode": "0711002",
946 | "modelCode": "00090101",
947 | "label": "Device",
948 | "linkId": 14
949 | }, {
950 | "id": 113,
951 | "applicationName": "天行健111",
952 | "appId": "123344121",
953 | "label": "Application",
954 | "linkId": 15
955 | }, {
956 | "id": 165,
957 | "positionNumber": "009",
958 | "positionCode": "980",
959 | "label": "Position",
960 | "linkId": 16
961 | }, {
962 | "id": 137,
963 | "deviceId": "004101015dd64d90e4b0c5015d3aebe1",
964 | "factoryCode": "191018002",
965 | "modelCode": "00410101",
966 | "label": "Device",
967 | "linkId": 17
968 | }, {
969 | "id": 19,
970 | "deviceId": "pin1a1005d5647ed270e07fad941eb33",
971 | "factoryCode": "pin11111ww",
972 | "modelCode": "pin1a100",
973 | "label": "Device",
974 | "linkId": 18
975 | }, {
976 | "id": 20,
977 | "deviceId": "005601015dc50794e4b080f28a960a2c",
978 | "factoryCode": "0513",
979 | "modelCode": "00560101",
980 | "label": "Device",
981 | "linkId": 19
982 | }, {
983 | "id": 112,
984 | "deviceId": "000101035dc5310ce4b041b08987f1f8",
985 | "factoryCode": "05131",
986 | "modelCode": "00010103",
987 | "label": "Device",
988 | "linkId": 20
989 | }, {
990 | "id": 147,
991 | "deviceId": "sha1a1005d5647ed270e07fad941eb33",
992 | "factoryCode": "sha11111ww",
993 | "modelCode": "sha1a100",
994 | "label": "Device",
995 | "linkId": 21
996 | }, {
997 | "id": 158,
998 | "deviceId": "004901015da536e3e4b0bf772bd36773",
999 | "factoryCode": "dnc12332112",
1000 | "modelCode": "00490101",
1001 | "label": "Device",
1002 | "linkId": 22
1003 | }, {
1004 | "id": 123,
1005 | "deviceId": "0001011005dbd3acde4b00740880802d9",
1006 | "factoryCode": "23534546",
1007 | "modelCode": "000101100",
1008 | "label": "Device",
1009 | "linkId": 23
1010 | }, {
1011 | "id": 99,
1012 | "deviceId": "000101485dd207aee4b03622287ebb9d",
1013 | "factoryCode": "757869876876",
1014 | "modelCode": "00010148",
1015 | "label": "Device",
1016 | "linkId": 24
1017 | }, {
1018 | "id": 4,
1019 | "deviceId": "004101015dd64ea1e4b0c5015d3aebe2",
1020 | "factoryCode": "123",
1021 | "modelCode": "00410101",
1022 | "label": "Device",
1023 | "linkId": 25
1024 | }, {
1025 | "id": 142,
1026 | "positionNumber": "001",
1027 | "positionCode": "002",
1028 | "label": "Position",
1029 | "linkId": 26
1030 | }, {
1031 | "id": 44,
1032 | "deviceId": "004901025d84c8bfe4b00b0c3273832a",
1033 | "factoryCode": "1234132413241234",
1034 | "modelCode": "00490102",
1035 | "label": "Device",
1036 | "linkId": 27
1037 | }, {
1038 | "id": 160,
1039 | "deviceId": "004501035da43ba1e4b0940ae0681255",
1040 | "factoryCode": "889900666666555",
1041 | "modelCode": "00450103",
1042 | "label": "Device",
1043 | "linkId": 28
1044 | }, {
1045 | "id": 164,
1046 | "deviceId": "005401015da67cd0e4b05e140edc73b1",
1047 | "factoryCode": "201910161",
1048 | "modelCode": "00540101",
1049 | "label": "Device",
1050 | "linkId": 29
1051 | }, {
1052 | "id": 96,
1053 | "deviceId": "aa01a1005ddc9af2a973297a1cf341f3",
1054 | "factoryCode": "001",
1055 | "modelCode": "aa01a100",
1056 | "label": "Device",
1057 | "linkId": 30
1058 | }, {
1059 | "id": 151,
1060 | "manufacturerCode": "aa01",
1061 | "manufacturerName": "厂商aa01",
1062 | "label": "Manufacturer",
1063 | "linkId": 31
1064 | }, {
1065 | "id": 172,
1066 | "iotInfrastructureName": "test20190619",
1067 | "iotInfrastructureCode": "20190619",
1068 | "factoryType": "Thingworx",
1069 | "label": "IotInfrastructure",
1070 | "linkId": 32
1071 | }, {
1072 | "id": 154,
1073 | "deviceId": "aa01a1815d9feb526152de91705f9f6a",
1074 | "factoryCode": "zyzy00781",
1075 | "modelCode": "aa01a181",
1076 | "label": "Device",
1077 | "linkId": 33
1078 | }, {
1079 | "id": 153,
1080 | "deviceId": "aa01a1815d9fec4f6152de91705f9f6b",
1081 | "factoryCode": "zyzy0078234",
1082 | "modelCode": "aa01a181",
1083 | "label": "Device",
1084 | "linkId": 34
1085 | }, {
1086 | "id": 159,
1087 | "deviceId": "004901015da44155e4b02ff365d70baa",
1088 | "factoryCode": "432141211",
1089 | "modelCode": null,
1090 | "label": "Device",
1091 | "linkId": 35
1092 | }, {
1093 | "id": 103,
1094 | "iotInfrastructureName": "测试816iot-center",
1095 | "iotInfrastructureCode": "20190816",
1096 | "factoryType": "IoT-Center",
1097 | "label": "IotInfrastructure",
1098 | "linkId": 36
1099 | }, {
1100 | "id": 60,
1101 | "deviceId": "000101035ddc95a7e4b0fcf4c7a7dc3a",
1102 | "factoryCode": "764563445",
1103 | "modelCode": "00010103",
1104 | "label": "Device",
1105 | "linkId": 37
1106 | }, {
1107 | "id": 27,
1108 | "name": "吾问无为谓",
1109 | "employeeNumber": "142314",
1110 | "phone": "13218787857",
1111 | "label": "DeviceAdmin",
1112 | "linkId": 38
1113 | }, {
1114 | "id": 28,
1115 | "deviceId": "tui1a1005d5647ed270e07fad941eb33",
1116 | "factoryCode": "yui11111ww",
1117 | "modelCode": "tui1a100",
1118 | "label": "Device",
1119 | "linkId": 39
1120 | }, {
1121 | "id": 34,
1122 | "deviceId": "000801025d0c75f98466a48347b9be1e",
1123 | "factoryCode": "buchongceshi4",
1124 | "modelCode": "00080102",
1125 | "label": "Device",
1126 | "linkId": 40
1127 | }, {
1128 | "id": 45,
1129 | "manufacturerCode": "95664",
1130 | "manufacturerName": "12",
1131 | "label": "Manufacturer",
1132 | "linkId": 41
1133 | }, {
1134 | "id": 29,
1135 | "applicationName": "Test请勿删除此业务应用",
1136 | "appId": "190708",
1137 | "label": "Application",
1138 | "linkId": 42
1139 | }, {
1140 | "id": 33,
1141 | "deviceId": "aa01a1935d78cb6644527d9ccfdda354",
1142 | "factoryCode": "qwertyuio",
1143 | "modelCode": "5698",
1144 | "label": "Device",
1145 | "linkId": 43
1146 | }, {
1147 | "id": 157,
1148 | "deviceId": "004101015da43846e4b02ff365d70ba8",
1149 | "factoryCode": "wdnmddnc",
1150 | "modelCode": "00410101",
1151 | "label": "Device",
1152 | "linkId": 44
1153 | }, {
1154 | "id": 143,
1155 | "deviceId": "004901015dd648bae4b0c5015d3aebbf",
1156 | "factoryCode": "dnb",
1157 | "modelCode": "00490101",
1158 | "label": "Device",
1159 | "linkId": 45
1160 | }, {
1161 | "id": 133,
1162 | "deviceId": "000101035dce3585e4b024fa72195ac6",
1163 | "factoryCode": "20191115",
1164 | "modelCode": "00010103",
1165 | "label": "Device",
1166 | "linkId": 46
1167 | }, {
1168 | "id": 126,
1169 | "manufacturerCode": "0001",
1170 | "manufacturerName": "测试厂商",
1171 | "label": "Manufacturer",
1172 | "linkId": 47
1173 | }, {
1174 | "id": 145,
1175 | "positionNumber": "01",
1176 | "positionCode": "02",
1177 | "label": "Position",
1178 | "linkId": 48
1179 | }, {
1180 | "id": 116,
1181 | "name": "lili",
1182 | "employeeNumber": "1123",
1183 | "phone": "18236592287",
1184 | "label": "DeviceAdmin",
1185 | "linkId": 49
1186 | }, {
1187 | "id": 170,
1188 | "name": "2423",
1189 | "employeeNumber": "432432",
1190 | "phone": "13213243567",
1191 | "label": "DeviceAdmin",
1192 | "linkId": 50
1193 | }, {
1194 | "id": 6,
1195 | "deviceId": "004101015da3d9cee4b05637b9776da8",
1196 | "factoryCode": "111111111111122222222333333334444444",
1197 | "modelCode": "00410101",
1198 | "label": "Device",
1199 | "linkId": 51
1200 | }, {
1201 | "id": 35,
1202 | "deviceId": "000101035da3e713e4b07ee3503d6bb8",
1203 | "factoryCode": "235435",
1204 | "modelCode": "00010103",
1205 | "label": "Device",
1206 | "linkId": 52
1207 | }, {
1208 | "id": 39,
1209 | "name": "测试",
1210 | "employeeNumber": "20191120",
1211 | "phone": "13218787851",
1212 | "label": "DeviceAdmin",
1213 | "linkId": 53
1214 | }, {
1215 | "id": 161,
1216 | "deviceId": "000101035da43615e4b0940ae0681254",
1217 | "factoryCode": "9767456",
1218 | "modelCode": "00010103",
1219 | "label": "Device",
1220 | "linkId": 54
1221 | }, {
1222 | "id": 155,
1223 | "deviceId": "000101035dd6024de4b0b7a69b2099c6",
1224 | "factoryCode": "7567435345334",
1225 | "modelCode": "00010103",
1226 | "label": "Device",
1227 | "linkId": 55
1228 | }, {
1229 | "id": 15,
1230 | "positionNumber": "21212",
1231 | "positionCode": "1212",
1232 | "label": "Position",
1233 | "linkId": 56
1234 | }, {
1235 | "id": 114,
1236 | "deviceId": "doo1a1005d5647ed270e07fad941eb33",
1237 | "factoryCode": "doo11111ww",
1238 | "modelCode": "aa01a100",
1239 | "label": "Device",
1240 | "linkId": 57
1241 | }, {
1242 | "id": 107,
1243 | "manufacturerCode": "0021",
1244 | "manufacturerName": "0619设备厂商测试",
1245 | "label": "Manufacturer",
1246 | "linkId": 58
1247 | }, {
1248 | "id": 110,
1249 | "applicationName": "达西创意园",
1250 | "appId": "000888",
1251 | "label": "Application",
1252 | "linkId": 59
1253 | }, {
1254 | "id": 127,
1255 | "deviceId": "guo1a1005d5647ed270e07fad941eb33",
1256 | "factoryCode": "guo11111ww",
1257 | "modelCode": "guo1a100",
1258 | "label": "Device",
1259 | "linkId": 60
1260 | }, {
1261 | "id": 146,
1262 | "manufacturerCode": "0049",
1263 | "manufacturerName": "无锡爱玛有限公司",
1264 | "label": "Manufacturer",
1265 | "linkId": 61
1266 | }, {
1267 | "id": 171,
1268 | "applicationName": "0129",
1269 | "appId": "000111",
1270 | "label": "Application",
1271 | "linkId": 62
1272 | }, {
1273 | "id": 144,
1274 | "positionNumber": "",
1275 | "positionCode": "",
1276 | "label": "Position",
1277 | "linkId": 63
1278 | }, {
1279 | "id": 115,
1280 | "deviceId": "aa01a1005d5647ed270e07fad941eb33",
1281 | "factoryCode": "11111111ww",
1282 | "modelCode": "aa01a100",
1283 | "label": "Device",
1284 | "linkId": 64
1285 | }, {
1286 | "id": 149,
1287 | "iotInfrastructureName": "Oc测试平台",
1288 | "iotInfrastructureCode": "Oc_Test",
1289 | "factoryType": "OceanConnect",
1290 | "label": "IotInfrastructure",
1291 | "linkId": 65
1292 | }, {
1293 | "id": 85,
1294 | "deviceId": "aa01a1005d79f79b7e86cb64421d5f2e",
1295 | "factoryCode": "oc09121544",
1296 | "modelCode": "aa01a100",
1297 | "label": "Device",
1298 | "linkId": 66
1299 | }, {
1300 | "id": 10,
1301 | "manufacturerCode": "0041",
1302 | "manufacturerName": "江南烟草厂",
1303 | "label": "Manufacturer",
1304 | "linkId": 67
1305 | }, {
1306 | "id": 148,
1307 | "name": "测试",
1308 | "employeeNumber": "20191118",
1309 | "phone": "13218787857",
1310 | "label": "DeviceAdmin",
1311 | "linkId": 68
1312 | }, {
1313 | "id": 109,
1314 | "deviceId": "aa01a2165dce164af140638d567c5c0c",
1315 | "factoryCode": "1115factory001",
1316 | "modelCode": "aa01a216",
1317 | "label": "Device",
1318 | "linkId": 69
1319 | }, {
1320 | "id": 31,
1321 | "deviceId": "004501015d8493e1e4b07c14d91f6d0a",
1322 | "factoryCode": "123312abcd",
1323 | "modelCode": "00450101",
1324 | "label": "Device",
1325 | "linkId": 70
1326 | }, {
1327 | "id": 17,
1328 | "deviceId": "004901015da91703e4b0311aeee1075a",
1329 | "factoryCode": "4321412111",
1330 | "modelCode": "00490101",
1331 | "label": "Device",
1332 | "linkId": 71
1333 | }, {
1334 | "id": 102,
1335 | "deviceId": "000201025dd20c32e4b03622287ebb9e",
1336 | "factoryCode": "2019111801",
1337 | "modelCode": "00020102",
1338 | "label": "Device",
1339 | "linkId": 72
1340 | }, {
1341 | "id": 138,
1342 | "manufacturerCode": "0048",
1343 | "manufacturerName": "测试816",
1344 | "label": "Manufacturer",
1345 | "linkId": 73
1346 | }, {
1347 | "id": 0,
1348 | "deviceId": "000101035dd7772fe4b052fe501d9f6f",
1349 | "factoryCode": "test",
1350 | "modelCode": "00010103",
1351 | "label": "Device",
1352 | "linkId": 74
1353 | }, {
1354 | "id": 167,
1355 | "deviceId": "000101035dd3551de4b0502efc76fee0",
1356 | "factoryCode": "20191119002",
1357 | "modelCode": "00010103",
1358 | "label": "Device",
1359 | "linkId": 75
1360 | }, {
1361 | "id": 41,
1362 | "deviceId": "000801025d0c7f1a8466e74289f900f0",
1363 | "factoryCode": "buchongceshi5",
1364 | "modelCode": "00080102",
1365 | "label": "Device",
1366 | "linkId": 76
1367 | }, {
1368 | "id": 141,
1369 | "positionNumber": "987",
1370 | "positionCode": "091",
1371 | "label": "Position",
1372 | "linkId": 77
1373 | }]
1374 | };
1375 |
1376 |
1377 | ~~ function renderGraph() {
1378 | let links = my_data.links; //经过力学仿真后,links里面的source和target节点会引用对应的nodes对象
1379 | let nodes = my_data.nodes;
1380 |
1381 | //关系分组
1382 | setLinkGroup(links);
1383 |
1384 | //点击节点后弹出的灰色圆圈以及图标的定义,分为三组【1.删除、2.联系、3.解除位置锁定】
1385 | let [removePath, remove_rect1, remove_rect2, remove_line1, remove_line2, remove_line3] = [null];
1386 | let [unlockPath, unlock_path1, unlock_rect1, unlock_line1] = [null];
1387 | let [hidePath, hide_path1, hide_path2, hide_path3, hide_path4, hide_circle1, hide_line1] = [null];
1388 | let rightArc = d3.arc().outerRadius(60).innerRadius(30).startAngle(0).endAngle(1.85);
1389 | let leftArc = d3.arc().outerRadius(60).innerRadius(30).startAngle(4.5).endAngle(6.23);
1390 | let bottomArc = d3.arc().outerRadius(60).innerRadius(30).startAngle(1.9).endAngle(4.45);
1391 |
1392 | var simulation = null;
1393 | var zoom = null;
1394 | var svg = null;
1395 | var edges_line = null;
1396 | var edges_text = null;
1397 | var circle_g = null;
1398 | var circle = null;
1399 | var text = null;
1400 |
1401 | d3.select("#graph").html('');
1402 |
1403 | simulation = d3.forceSimulation() //启动力学仿真 //force之后返回的依然是forceSimulation对象
1404 | .force("charge", d3.forceManyBody()) //添加力学仿真模型
1405 | .force("links", d3.forceLink())
1406 | .force("center", d3.forceCenter(800 / 2, 600 / 2))
1407 | .force("collision", d3.forceCollide(30))
1408 | .nodes(nodes); //设定节点数组 //将json格式转化为力学图可用的格式
1409 |
1410 | //下面力学模型的参数配置也可以在初始化时就设置好,如向心力center的初始化
1411 | simulation.force("links").links(links).distance(150); //设置弹簧力模型参数,连线数组和连线长度
1412 | simulation.force("charge").strength(-200); //顶点的电荷数。该参数决定是排斥还是吸引,数值越小越互相排斥
1413 |
1414 | console.log(links)
1415 | console.log(nodes)
1416 |
1417 | zoom = d3.zoom() //创建一个放缩对象
1418 | .scaleExtent([.4, 2])
1419 | .on("zoom", zoomed);
1420 |
1421 | //配置画板svg属性
1422 | svg = d3.select("#graph").append("svg")
1423 | .attr("pointer-event", "all")
1424 | .attr("preserveAspectRatio", "xMidYMid meet") //自适应容器大小
1425 | .attr("viewPort", "0 0 800 600")
1426 | .attr("viewBox", "0 0 800 600")
1427 | .call(zoom);
1428 |
1429 | //设置连接线
1430 | edges_line = svg.append("g").selectAll(".edgepath")
1431 | .data(links) //此时的links属性已经经过力学仿真进行了相关数据修改
1432 | .enter()
1433 | .append("path")
1434 | .attr("marker-end", function(d, i) { return getMarkerArrow(i); }) //根据箭头标记的id号标记箭头
1435 | .style("stroke", '#9aaabf')
1436 | .style("stroke-width", 1) //线条粗细
1437 | .style("fill-opacity", 0)
1438 | .style("cursor", "pointer")
1439 | .attr("id", function(d, i) { return 'edgepath' + i; })
1440 | .on("mouseover", function(d) { return getStrokeWidth(d); })
1441 | .on("mouseout", function() { edges_line.style("stroke-width", 1) })
1442 | .on('click', (d, i) => { deleteLine(d, i); });
1443 |
1444 | //设置连接线上的文字
1445 | edges_text = svg.append("g").selectAll(".edgetext")
1446 | .data(links)
1447 | .enter()
1448 | .append("text")
1449 | .style("pointer-events", "none")
1450 | .attr("class", "linetext")
1451 | .attr('text-anchor', "middle")
1452 | .attr("fill-opacity", 1)
1453 | .style("cursor", "pointer")
1454 | .attr('class', 'edgelabel')
1455 | .attr('id', function(d, i) { return 'edgepath' + i; })
1456 | .attr('dx', 50)
1457 | .attr('dy', 0)
1458 | .attr('fill', '#9aaabf');
1459 |
1460 | //设置线条上的文字
1461 | edges_text.append('textPath')
1462 | .attr('xlink:href', function(d, i) { return '#edgepath' + i })
1463 | .attr("pointer-events", "none").attr("font-size", 9)
1464 | .text(function(d) { return d.relation.relationship; });
1465 |
1466 | circle_g = svg.selectAll("circle")
1467 | .data(nodes) //使用仿真后的nodes数据
1468 | .enter()
1469 | .append("g")
1470 | .attr("class", function(node, i) { return "g_circle_" + i; }) //标记circle的父节点
1471 | .style("cursor", "pointer")
1472 | .call(drag()) //将当前选中的元素传到drag函数中,使顶点可以被拖动
1473 | .on("click", (node, i) => {
1474 | if (d3.event.defaultPrevented) return; //阻止click事件和拖拽事件冲突
1475 | circleClick(node, i, this);
1476 | })
1477 | .on('mouseover', (node) => {
1478 | if (d3.event.defaultPrevented) return;
1479 | showNodeInfo(node, this);
1480 | // showCircleBorderOuterArc(node, i);
1481 | });
1482 |
1483 | svg.on("dblclick.zoom", null); //取消svg和圆圈的双击放大事件(d3中默认开启7个事件,关闭防止与上面的双击事件冲突)
1484 | circle_g.on("dblclick.zoom", null);
1485 |
1486 | //圆圈
1487 | circle = circle_g.append("circle")
1488 | .style("stroke-width", "2px")
1489 | .attr("r", 25) //设置圆圈半径
1490 | .style("fill", function(node) { return getCircleColor(node); });
1491 |
1492 | text = circle_g.append("text")
1493 | .attr("dy", ".35em")
1494 | .attr("text-anchor", "middle") //在圆圈中加上数据
1495 | .style('fill', "#FFFFFF")
1496 | .attr('x', function(d) { appendCircleText(d, this); });
1497 |
1498 | //圆圈的提示文字
1499 | circle.append("svg:title").text(function(node) {
1500 | switch (node.label) {
1501 | case 'Device':
1502 | return node.factoryCode;
1503 | case 'Application':
1504 | return node.applicationName;
1505 | case 'Position':
1506 | return node.positionCode;
1507 | case 'Manufacturer':
1508 | return node.manufacturerName;
1509 | case 'IotInfrastructure':
1510 | return node.iotInfrastructureName;
1511 | case 'DeviceAdmin':
1512 | return node.name;
1513 | }
1514 | });
1515 | text.append("svg:title").text(function(node) {
1516 | switch (node.label) {
1517 | case 'Device':
1518 | return node.factoryCode;
1519 | case 'Application':
1520 | return node.applicationName;
1521 | case 'Position':
1522 | return node.positionCode;
1523 | case 'Manufacturer':
1524 | return node.manufacturerName;
1525 | case 'IotInfrastructure':
1526 | return node.iotInfrastructureName;
1527 | case 'DeviceAdmin':
1528 | return node.name;
1529 | }
1530 | });
1531 |
1532 | function zoomed() { //svg下的g标签移动大小
1533 | svg.selectAll("g").attr("transform", d3.event.transform);
1534 | }
1535 |
1536 |
1537 | function getMarkerArrow(i) {
1538 | svg.append("defs").append("marker") //箭头
1539 | .attr("id", "arrow" + i)
1540 | .attr("markerUnits", "strokeWidth") //设置为strokeWidth箭头会随着线的粗细发生变化
1541 | .attr("markerUnits", "userSpaceOnUse")
1542 | .attr("markerWidth", 10) //标识的大小
1543 | .attr("markerHeight", 10)
1544 | .attr("viewBox", "0 -4 12 15") //坐标系的区域
1545 | .attr("refX", 0) //箭头坐标
1546 | .attr("refY", 0)
1547 | .attr("orient", 'auto') //绘制方向,可设定为:auto(自动确认方向)和 角度值
1548 | .append("svg:path")
1549 | .attr("stroke-width", 1) //箭头宽度
1550 | .attr("d", "M0,-5L10,0L0,5") //箭头的路径
1551 | .attr('fill', 'rgba(0,0,0, 0.4)'); //箭头颜色
1552 | return "url(#arrow" + i + ")";
1553 | }
1554 |
1555 | function getStrokeWidth(d) {
1556 | edges_line.style("stroke-width", function(edge) {
1557 | return edge.relation.relationshipId === d.relation.relationshipId ? 3 : 1;
1558 | });
1559 | }
1560 |
1561 | function drag() { //拖拽函数
1562 | return d3.drag().on("start", function(d) {
1563 | if (!d3.event.active) {
1564 | simulation.alphaTarget(0.05).restart(); // 设置衰减系数,对节点位置移动过程的模拟,数值越高移动越快,数值范围[0,1]
1565 | }
1566 | d3.event.sourceEvent.stopPropagation(); //取消默认事件
1567 | d.fixed = true; //拖拽开始后设定被拖拽对象为固定
1568 | d.fx = d.x; //通过设置fx值来固定节点位置 https://github.com/xswei/d3-force/blob/master/README.md#simulation_nodes
1569 | d.fy = d.y;
1570 | })
1571 | .on("drag", function(d) {
1572 | d.fx = d3.event.x;
1573 | d.fy = d3.event.y;
1574 | })
1575 | .on("end", function(d) {
1576 | if (!d3.event.active) {
1577 | simulation.alphaTarget(0.05);
1578 | }
1579 | d.fx = d.x; //设置为null则取消固定
1580 | d.fy = d.y;
1581 | });
1582 | }
1583 |
1584 | function circleClick(node, i, _this) {
1585 | //获取当前节点是否包含圆环
1586 | let existedRing = svg.select('.g_circle_' + i).selectAll('.g_circle_path');
1587 | //清除上个节点的圆圈以及图标
1588 | svg.selectAll('.g_circle_path').remove();
1589 | svg.selectAll('.remove_a').remove();
1590 | svg.selectAll('.hide_a').remove();
1591 | svg.selectAll('.unlock_a').remove();
1592 | removePath = null;
1593 | unlockPath = null;
1594 | hidePath = null;
1595 | if (existedRing && existedRing["_groups"][0].length === 0) {
1596 | //showCircleBorderOuterArc(node, i);
1597 | //绘制灰色可点击圆圈,分为三部分分别绘制
1598 | showRemove(node, i, _this);
1599 | showUnlock(node, i, _this);
1600 | showHide(node, i, _this);
1601 | }
1602 | }
1603 |
1604 | function getCircleColor(node) {
1605 | let color = {
1606 | 'Device': "#FF9D00",
1607 | 'Position': "#C477E9",
1608 | 'Work': '#67CAF4',
1609 | 'Install': '#BCDD73',
1610 | 'Application': '#DD1E9E',
1611 | 'Manufacturer': '#DDBA9E',
1612 | 'IotInfrastructure': '#6ca5dd',
1613 | 'DeviceAdmin': '#50DD87',
1614 | }; //圆圈背景色
1615 | return color[node.label] || '#C477E9';
1616 | }
1617 |
1618 | function appendCircleText(d, _this) {
1619 | let circleText = '';
1620 | if (d.label === 'Device' && d.factoryCode) {
1621 | circleText = d.factoryCode;
1622 | } else if (d.label === 'Position') {
1623 | circleText = d.positionCode;
1624 | } else if (d.label === 'Application') {
1625 | circleText = d.applicationName;
1626 | } else if (d.label === 'Manufacturer') {
1627 | circleText = d.manufacturerName;
1628 | } else if (d.label === 'IotInfrastructure') {
1629 | circleText = d.iotInfrastructureName;
1630 | } else if (d.label === 'DeviceAdmin') {
1631 | circleText = d.name;
1632 | }
1633 | //如果小于四个字符,不换行
1634 | if (circleText && circleText.length > 4) {
1635 | circleText = circleText.substring(0, 4) + "...";
1636 | d3.select(_this).text(function() { return ''; });
1637 | }
1638 | d3.select(_this).append('tspan').attr('x', 0).attr('y', 0).attr("font-size", 12)
1639 | .text(function() { return circleText; });
1640 | }
1641 |
1642 | function deleteLine(d, i) {
1643 | alert('delete this ' + d + ',' + i);
1644 | }
1645 |
1646 | function tick() {
1647 | //每个一小段时间此函数会被调用,用以绘图。alpha值越小表示力学仿真布局越合理,为了减少不必要的渲染,同时加快画面展示流畅度
1648 | //设置满足一定阈值时,才渲染图形
1649 | if (simulation.alpha() > 0.1) return; // 足够稳定时,才渲染一次.此阈值的设定要大于等于drag函数里面的alphaTarget值。
1650 |
1651 | circle.attr("transform", transform1); //圆圈
1652 | text.attr("transform", transform2); //顶点文字
1653 | edges_line.attr('d', function(d) {
1654 | //绘制自己指向自己的路径
1655 | if (d.relation.isSelf) { return getNodeSelfPath(d) }
1656 | //绘制两个节点之间的路径
1657 | return getNodesLine(d); //曲线路径
1658 | });
1659 |
1660 | // if(circleBorderOuterArcObj !== null) {
1661 | // circleBorderOuterArcObj.attr("transform", function (d){ return "translate("+d.x+","+d.y+")" });
1662 | // }
1663 |
1664 | //绘制节点删除功能半圆环
1665 | if (removePath !== null) {
1666 | removePath.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")" });
1667 |
1668 | let r1 = null;
1669 | remove_rect1.attr('d', function(d) { r1 = d; })
1670 | .attr("x", r1.x + 33 + 6.75).attr("y", r1.y - 36 + 9.75).attr("width", 5).attr("height", 3).attr("rx", 1.5).attr("ry", 1.5);
1671 |
1672 | let r2 = null;
1673 | remove_rect2.attr('d', function(d) { r2 = d; })
1674 | .attr("x", r2.x + 30 + 6.75).attr("y", r2.y - 33 + 9.75).attr("width", 12).attr("height", 14).attr("rx", 1.5).attr("ry", 1.5);
1675 |
1676 | let l1 = null;
1677 | remove_line1.attr('d', function(d) { l1 = d; })
1678 | .attr("x1", l1.x + 28 + 6.75).attr("y1", l1.y - 33 + 9.75).attr("x2", l1.x + 45 + 6.75).attr("y2", l1.y - 33 + 9.75);
1679 |
1680 | let l2 = null;
1681 | remove_line2.attr('d', function(d) { l2 = d; })
1682 | .attr("x1", l2.x + 34 + 6.75).attr("y1", l2.y - 30 + 9.75).attr("x2", l2.x + 34 + 6.75).attr("y2", l2.y - 23 + 9.75);
1683 |
1684 | let l3 = null;
1685 | remove_line3.attr('d', function(d) { l3 = d; })
1686 | .attr("x1", l3.x + 38 + 6.75).attr("y1", l3.y - 30 + 9.75).attr("x2", l3.x + 38 + 6.75).attr("y2", l3.y - 23 + 9.75);
1687 | }
1688 |
1689 | //绘制解除节点位置锁定半圆环
1690 | if (unlockPath !== null) {
1691 | unlockPath.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")" });
1692 | unlock_path1.attr("transform", function(d) { return "translate(" + (d.x - 45) + "," + (d.y - 23) + ")" });
1693 |
1694 | let r1 = null;
1695 | unlock_rect1.attr('d', function(d) { r1 = d; })
1696 | .attr("x", r1.x - 52 + 6.75).attr("y", r1.y - 30 + 9.75).attr("width", 15).attr("height", 12).attr("rx", 1.5).attr("ry", 1.5);
1697 |
1698 | let l1 = null;
1699 | unlock_line1.attr('d', function(d) { l1 = d; })
1700 | .attr("x1", l1.x - 52 + 15).attr("y1", l1.y - 30 + 15).attr("x2", l1.x - 52 + 15).attr("y2", l1.y - 30 + 18);
1701 | }
1702 |
1703 | //绘制隐藏节点和关系半圆环
1704 | if (hidePath !== null) {
1705 | hidePath.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")" });
1706 |
1707 | hide_path1
1708 | .attr("d", function(d) {
1709 | return "M" + (d.x - 13) + "," + (d.y + 42) + "A15,15,0,0,1" + (d.x + 13) + "," + (d.y + 42)
1710 | });
1711 | hide_path2
1712 | .attr("d", function(d) {
1713 | return "M" + (d.x - 12 + 10.4) + "," + (d.y + 34 + 10.937) + "A" + 3.749 + "," + 3.749 + ",0,1,1," + (d.x - 12 + 15.338) + "," + (d.y + 33 + 9)
1714 | });
1715 | hide_path3
1716 | .attr("d", function(d) {
1717 | return "M" + (d.x - 12) + "," + (d.y + 42) + "A20,20,0,0,0" + (d.x - 4) + "," + (d.y + 47)
1718 | });
1719 | hide_path4
1720 | .attr("d", function(d) {
1721 | return "M" + (d.x + 11) + "," + (d.y + 44) + "A20,20,0,0,0" + (d.x + 13) + "," + (d.y + 42)
1722 | });
1723 |
1724 | let c1 = null;
1725 | hide_circle1.attr('d', function(d) { c1 = d; })
1726 | .attr("cx", c1.x - 12 + 17.15).attr("cy", c1.y + 33 + 17.25).attr("r", 6);
1727 |
1728 | let l1 = null;
1729 | hide_line1.attr('d', function(d) { l1 = d; })
1730 | .attr("x1", l1.x - 12 + 14.15).attr("y1", l1.y + 33 + 17.25).attr("x2", l1.x - 12 + 20.15).attr("y2", l1.y + 33 + 17.25);
1731 |
1732 | }
1733 |
1734 | }
1735 | simulation.on("tick", tick); //指时间间隔,隔一段时间刷新一次画面
1736 |
1737 | //设置圆圈和文字的坐标
1738 | function transform1(d) {
1739 | //设置节点固定 初始全部固定,拖动节点后会固定当前节点
1740 | if (d.fixed != undefined && d.fixed == false) {
1741 | d.fx = null;
1742 | d.fy = null;
1743 | } else {
1744 | d.fx = d.x;
1745 | d.fy = d.y;
1746 | }
1747 | return "translate(" + d.x + "," + d.y + ")";
1748 | }
1749 |
1750 | function transform2(d) {
1751 | return "translate(" + (d.x) + "," + d.y + ")";
1752 | }
1753 |
1754 |
1755 | function showRemove(node, i, _this) {
1756 | removePath = d3.select('.g_circle_' + i).append("path").attr('class', 'g_circle_path')
1757 | .attr("transform", "translate(" + node.x + "," + node.y + ")").attr("d", rightArc)
1758 | .attr("fill", "rgb(210, 213, 218)")
1759 | .style("cursor", "pointer")
1760 | .on("click", () => { removeNodeAndPath(node, _this); })
1761 | .on("mouseover", function() { removePath.attr("fill", "rgb(185, 185, 185)") })
1762 | .on("mouseout", function() { removePath.attr("fill", "rgb(210, 213, 218)") });
1763 |
1764 | d3.select('.g_circle_' + i).append("g").attr("class", "remove_a")
1765 | .attr("transform", "translate(" + (node.x + 33) + "," + (node.y - 24) + ") scale(0.7)")
1766 | .append("defs").append("style")
1767 | .text(".remove_a{fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.5px;}");
1768 |
1769 | removePath.append("title").attr("class", "remove_a").text("Remove");
1770 | remove_rect1 = d3.select('.g_circle_' + i).append("rect").attr("class", "remove_a").attr("x", node.x + 33 + 6.75).attr("y", node.y - 36 + 9.75)
1771 | .attr("width", 5).attr("height", 3).attr("rx", 1.5).attr("ry", 1.5);
1772 | remove_rect2 = d3.select('.g_circle_' + i).append("rect").attr("class", "remove_a").attr("x", node.x + 30 + 6.75).attr("y", node.y - 33 + 9.75)
1773 | .attr("width", 12).attr("height", 14).attr("rx", 1.5).attr("ry", 1.5);
1774 | remove_line1 = d3.select('.g_circle_' + i).append("line").attr("class", "remove_a").attr("x1", node.x + 28 + 6.75).attr("y1", node.y - 33 + 9.75).attr("x2", node.x + 45 + 6.75).attr("y2", node.y - 33 + 9.75);
1775 | remove_line2 = d3.select('.g_circle_' + i).append("line").attr("class", "remove_a").attr("x1", node.x + 34 + 6.75).attr("y1", node.y - 30 + 9.75).attr("x2", node.x + 34 + 6.75).attr("y2", node.y - 23 + 9.75);
1776 | remove_line3 = d3.select('.g_circle_' + i).append("line").attr("class", "remove_a").attr("x1", node.x + 38 + 6.75).attr("y1", node.y - 30 + 9.75).attr("x2", node.x + 38 + 6.75).attr("y2", node.y - 23 + 9.75);
1777 |
1778 | d3.selectAll(".remove_a").on("click", () => { removeNodeAndPath(node, _this); })
1779 | }
1780 |
1781 | function showHide(node, i) {
1782 | hidePath = d3.select('.g_circle_' + i).append("path").attr('class', 'g_circle_path')
1783 | .attr("transform", "translate(" + node.x + "," + node.y + ")").attr("d", bottomArc)
1784 | .attr("fill", "rgb(210, 213, 218)")
1785 | .style("cursor", "pointer")
1786 | .on("click", function() { hideNodeAndLinks(node) })
1787 | .on("mouseover", function() { hidePath.attr("fill", "rgb(185, 185, 185)") })
1788 | .on("mouseout", function() { hidePath.attr("fill", "rgb(210, 213, 218)") });
1789 |
1790 | d3.select('.g_circle_' + i).append("g").attr("class", "hide_a")
1791 | .attr("transform", "translate(" + (node.x - 8) + "," + (node.y + 38) + ") scale(0.7)")
1792 | .append("defs").append("style")
1793 | .text(".hide_a{fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.5px;}");
1794 |
1795 | hidePath.append("title").attr("class", "hide_a").text("Hide");
1796 |
1797 | hide_path1 = d3.select('.g_circle_' + i).append("path").attr("class", "hide_a")
1798 | .attr("d", function(d) {
1799 | return "M" + (d.x - 13) + "," + (d.y + 42) + "A15,15,0,0,1" + (d.x + 13) + "," + (d.y + 42)
1800 | });
1801 | hide_path2 = d3.select('.g_circle_' + i).append("path").attr("class", "hide_a")
1802 | .attr("d", function(d) {
1803 | return "M" + (d.x - 12 + 10.4) + "," + (d.y + 34 + 10.937) + "A" + 3.749 + "," + 3.749 + ",0,1,1," + (d.x - 12 + 15.338) + "," + (d.y + 33 + 9)
1804 | });
1805 | hide_path3 = d3.select('.g_circle_' + i).append("path").attr("class", "hide_a")
1806 | .attr("d", function(d) {
1807 | return "M" + (d.x - 12) + "," + (d.y + 42) + "A20,20,0,0,0" + (d.x - 4) + "," + (d.y + 47)
1808 | });
1809 | hide_path4 = d3.select('.g_circle_' + i).append("path").attr("class", "hide_a")
1810 | .attr("d", function(d) {
1811 | return "M" + (d.x + 11) + "," + (d.y + 44) + "A20,20,0,0,0" + (d.x + 13) + "," + (d.y + 42)
1812 | });
1813 | hide_circle1 = d3.select('.g_circle_' + i).append("circle").attr("class", "hide_a").attr("cx", node.x - 12 + 17.15).attr("cy", node.y + 33 + 17.25).attr("r", 6);
1814 | hide_line1 = d3.select('.g_circle_' + i).append("line").attr("class", "hide_a").attr("x1", node.x - 12 + 14.15).attr("y1", node.y + 33 + 17.25).attr("x2", node.x - 12 + 20.15).attr("y2", node.y + 33 + 17.25);
1815 | d3.selectAll(".hide_a").on("click", (d) => { hideNodeAndLinks(d); })
1816 | }
1817 |
1818 | function showUnlock(node, i) {
1819 | unlockPath = d3.select('.g_circle_' + i).append("path").attr('class', 'g_circle_path')
1820 | .attr("transform", "translate(" + node.x + "," + node.y + ")").attr("d", leftArc)
1821 | .attr("fill", "rgb(210, 213, 218)").style("cursor", "pointer")
1822 | .on("click", function(d) { unlockNodeFixed(d, this); })
1823 | .on("mouseover", function() { unlockPath.attr("fill", "rgb(185, 185, 185)") })
1824 | .on("mouseout", function() { unlockPath.attr("fill", "rgb(210, 213, 218)") });
1825 |
1826 | d3.select('.g_circle_' + i).append("g").attr("class", "unlock_a")
1827 | .attr("transform", "translate(" + (node.x - 52) + "," + (node.y - 30) + ") scale(0.7)")
1828 | .append("defs").append("style")
1829 | .text(".unlock_a{fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.5px;}");
1830 |
1831 | unlockPath.append("title").attr("class", "unlock_a").text("Unlock");
1832 | unlock_path1 = d3.select('.g_circle_' + i).append("path").attr("class", "unlock_a")
1833 | .attr("transform", "translate(" + (node.x - 45) + "," + (node.y - 23) + ")")
1834 | .attr("d", d3.arc().outerRadius(5.3).innerRadius(5).startAngle(-1.8).endAngle(1.8))
1835 | .attr("fill", "#FFFFFF");
1836 | unlock_rect1 = d3.select('.g_circle_' + i).append("rect").attr("class", "unlock_a").attr("x", node.x - 52 + 6.75).attr("y", node.y - 30 + 9.75)
1837 | .attr("width", 15).attr("height", 12).attr("rx", 1.5).attr("ry", 1.5);
1838 | unlock_line1 = d3.select('.g_circle_' + i).append("line").attr("class", "unlock_a").attr("x1", node.x - 52 + 15).attr("y1", node.y - 30 + 15).attr("x2", node.x - 52 + 15).attr("y2", node.y - 30 + 18);
1839 |
1840 | d3.selectAll(".unlock_a").on("click", (d) => { unlockNodeFixed(d, this); })
1841 |
1842 | }
1843 |
1844 | function hideNodeAndLinks(node) {
1845 | d3.event.stopPropagation();
1846 | circle_g.attr('node', function(n) {
1847 | if (n.id === node.id) {
1848 | d3.select(this).remove();
1849 | }
1850 | });
1851 | edges_line.attr('d', function(d) {
1852 | if (d.source.id === node.id || d.target.id === node.id) {
1853 | d3.select(this).remove();
1854 | }
1855 | });
1856 | }
1857 |
1858 | function removeNodeAndPath(node, _this) {
1859 | d3.event.stopPropagation();
1860 | alert('delete this ' + node + ',' + _this);
1861 | }
1862 |
1863 | function showNodeInfo(node, _this) {
1864 | window.console.log(node);
1865 | window.console.log(_this);
1866 |
1867 | }
1868 |
1869 | function unlockNodeFixed(d, _this) {
1870 | d3.event.stopPropagation();
1871 | d.fixed = false; //解除节点位置锁定
1872 | //清除上个节点的圆圈以及图标
1873 | svg.selectAll('.g_circle_path').remove();
1874 | svg.selectAll('.remove_a').remove();
1875 | svg.selectAll('.hide_a').remove();
1876 | svg.selectAll('.unlock_a').remove();
1877 | removePath = null;
1878 | unlockPath = null;
1879 | hidePath = null;
1880 | }
1881 |
1882 | }();
--------------------------------------------------------------------------------