当前位置:   article > 正文

d3.js关系图_js 关系图

js 关系图

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <style>
  5. .nodetext {
  6. font-size: 12px;
  7. font-family: SimSun;
  8. fill: #000000;
  9. }
  10. .tooltip {
  11. height: auto;
  12. font-family: simsun;
  13. font-size: 14px;
  14. text-align: center;
  15. }
  16. select#lineFontType.form-control,
  17. select#nodesFontType.form-control {
  18. width: 184px;
  19. }
  20. .layout-split-east {
  21. border-left: 5px solid #E6EEF8;
  22. }
  23. </style>
  24. <base href="<%=basePath%>">
  25. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  26. <meta name="viewport" content="width=device-width, initial-scale=1">
  27. <script src="https://code.jquery.com/jquery-3.0.0.min.js"></script>
  28. <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
  29. </head>
  30. <body>
  31. <!-- 力导向图div -->
  32. <div id="divid"></div>
  33. <script>
  34. $(document).ready(function () {
  35. showChart();
  36. })
  37. function showChart() {
  38. var data = {
  39. "links": [
  40. { "source": "陆洋", "target": "建银国际产业基金管理有限公司", "relation": "副董事长大人", "sourceId": "", "targetId": "", "sourceImg": "http://mail.tom.com/error/i2.gif", "targetImg": "", "sourceColor": "", "targetColor": "", "sourceRadius": "30", "targetRadius": "45", "lineColor": "#458B00" },
  41. { "source": "汪红辉", "target": "乾行文化投资公司", "relation": "总经理", "sourceId": "", "targetId": "", "sourceImg": "", "targetImg": "", "sourceColor": "", "targetColor": "#00FF00", "sourceRadius": "30", "targetRadius": "40", "lineColor": "#EEEE00" },
  42. { "source": "汪红辉", "target": "天津裕丰股权投资管理有限公司", "relation": "董事", "sourceId": "", "targetId": "", "sourceImg": "", "targetImg": "", "sourceColor": "", "targetColor": "", "sourceRadius": "30", "targetRadius": "42", "lineColor": "#0000CD" },
  43. { "source": "汪红辉", "target": "乾行文化投资公司", "relation": "法人", "sourceId": "", "targetId": "", "sourceImg": "", "targetImg": "", "sourceColor": "", "targetColor": "", "sourceRadius": "30", "targetRadius": "40", "lineColor": "#9AC0CD" },
  44. { "source": "汪红辉", "target": "乾行文化投资公司", "relation": "董事长", "sourceId": "", "targetId": "", "sourceImg": "", "targetImg": "", "sourceColor": "", "targetColor": "", "sourceRadius": "30", "targetRadius": "40", "lineColor": "#CD4F39" },
  45. { "source": "汪红辉", "target": "建银国际产业基金管理有限公司", "relation": "董事", "sourceId": "", "targetId": "", "sourceImg": "", "targetImg": "", "sourceColor": "", "targetColor": "", "sourceRadius": "30", "targetRadius": "45", "lineColor": "#0000CD" },
  46. { "source": "胡章宏", "target": "建银国际产业基金管理有限公司", "relation": "董事长", "sourceId": "", "targetId": "", "sourceImg": "", "targetImg": "", "sourceColor": "", "targetColor": "", "sourceRadius": "30", "targetRadius": "45", "lineColor": "#CD4F39" },
  47. { "source": "建银国际产业基金管理有限公司", "target": "胡章宏", "relation": "法人", "sourceId": "", "targetId": "", "sourceImg": "", "targetImg": "", "sourceColor": "", "targetColor": "", "sourceRadius": "45", "targetRadius": "30", "lineColor": "#9AC0CD" }
  48. ]
  49. };
  50. var options = {};
  51. options.backgroundColor = "#D1EEEE";
  52. options.nodesFontType = "SimSun";
  53. options.nodesFontSize = 20;
  54. options.lineFontType = "SimHei";
  55. options.lineFontSize = 12;
  56. options.lineColor = "#000000";
  57. options.showExamples = true;
  58. options.examplesX = 20;
  59. options.examplesY = 450;
  60. options.examplesFontColor = "#000000";
  61. drawChart("divid", options, data);
  62. }
  63. function drawChart(divid, options, datas, dataFilter) {
  64. var backgroundColor = options.backgroundColor; //背景颜色
  65. var nodesFontType = options.nodesFontType; //节点字体
  66. var nodesFontSize = options.nodesFontSize; //节点字号
  67. var lineFontType = options.lineFontType; //关系字体
  68. var lineFontSize = options.lineFontSize; //关系字号
  69. var lineColor = options.lineColor; //连线颜色
  70. var examplesFontColor = options.examplesFontColor; //关系示例字体颜色
  71. var width = 800; //画布宽
  72. var height = 500; //画布高
  73. var svgChart = d3.select("svg");
  74. svgChart.remove();
  75. var tip = $(".tooltip");
  76. if (tip.length > 0) {
  77. tip.remove();
  78. }
  79. var sourceDatas = {};
  80. sourceDatas.links = [];
  81. for (var i = 0; i < datas.links.length; i++) {
  82. var jsonObj = {};
  83. jsonObj.source = datas.links[i].source;
  84. jsonObj.target = datas.links[i].target;
  85. jsonObj.relation = datas.links[i].relation;
  86. jsonObj.sourceId = datas.links[i].sourceId;
  87. jsonObj.targetId = datas.links[i].targetId;
  88. jsonObj.sourceImg = datas.links[i].sourceImg;
  89. jsonObj.targetImg = datas.links[i].targetImg;
  90. jsonObj.sourceColor = datas.links[i].sourceColor;
  91. jsonObj.targetColor = datas.links[i].targetColor;
  92. jsonObj.sourceRadius = datas.links[i].sourceRadius;
  93. jsonObj.targetRadius = datas.links[i].targetRadius;
  94. jsonObj.lineColor = datas.links[i].lineColor;
  95. sourceDatas.links.push(jsonObj);
  96. }
  97. var resourceLinks = sourceDatas.links;
  98. if (dataFilter != undefined && dataFilter.length > 0) {
  99. var indexArray = [];
  100. for (var i = 0; i < dataFilter.length; i++) {
  101. for (var j = 0; j < resourceLinks.length; j++) {
  102. if (resourceLinks[j].relation == dataFilter[i].relation && dataFilter[i].isShow == "false") {
  103. indexArray.push(j);
  104. }
  105. }
  106. }
  107. if (indexArray.length > 0) {
  108. var tempArray = [];
  109. for (var j = 0; j < resourceLinks.length; j++) {
  110. for (var i = 0; i < indexArray.length; i++) {
  111. if (indexArray[i] != j) {
  112. if (i == indexArray.length - 1) {
  113. tempArray.push(resourceLinks[j]);
  114. break;
  115. }
  116. continue;
  117. } else {
  118. break;
  119. }
  120. }
  121. }
  122. resourceLinks = tempArray;
  123. }
  124. }
  125. var links = resourceLinks;
  126. //关系分组
  127. var linkGroup = {};
  128. //对连接线进行统计和分组,不区分连接线的方向,只要属于同两个实体,即认为是同一组
  129. var linkmap = {};
  130. for (var i = 0; i < links.length; i++) {
  131. var key = links[i].source < links[i].target ? links[i].source + ':' + links[i].target : links[i].target + ':' + links[i].source;
  132. if (!linkmap.hasOwnProperty(key)) {
  133. linkmap[key] = 0;
  134. }
  135. linkmap[key] += 1;
  136. if (!linkGroup.hasOwnProperty(key)) {
  137. linkGroup[key] = [];
  138. }
  139. linkGroup[key].push(links[i]);
  140. }
  141. //为每一条连接线分配size属性,同时对每一组连接线进行编号
  142. for (var i = 0; i < links.length; i++) {
  143. var key = links[i].source < links[i].target ? links[i].source + ':' + links[i].target : links[i].target + ':' + links[i].source;
  144. links[i].size = linkmap[key];
  145. //同一组的关系进行编号
  146. var group = linkGroup[key];
  147. //给节点分配编号
  148. setLinkNumber(group);
  149. }
  150. //节点
  151. var nodes = {};
  152. //关系对应颜色
  153. var relationColor = {};
  154. for (var i = 0; i < links.length; i++) {
  155. links[i].source = nodes[links[i].source] || (nodes[links[i].source] = { name: links[i].source, color: links[i].sourceColor, image: links[i].sourceImg, radius: links[i].sourceRadius });
  156. links[i].target = nodes[links[i].target] || (nodes[links[i].target] = { name: links[i].target, color: links[i].targetColor, image: links[i].targetImg, radius: links[i].targetRadius });
  157. }
  158. var sourceData = datas.links;
  159. for (var i = 0; i < sourceData.length; i++) {
  160. relationColor[sourceData[i].relation] = { "relation": sourceData[i].relation, "lineColor": sourceData[i].lineColor };
  161. }
  162. nodes = d3.values(nodes);
  163. relationColor = d3.values(relationColor);
  164. var examples_x = parseFloat(options.examplesX); //关系示例坐标x
  165. var examples_y = parseFloat(options.examplesY); //关系示例坐标y
  166. var examplesLength = 80;
  167. var examplesSize = Math.floor((width - examples_x) / examplesLength);
  168. var examplesRow = relationColor.length % examplesSize == 0 ? relationColor.length / examplesSize : Math.ceil(relationColor.length / examplesSize);
  169. //计算关系示列位置
  170. for (var i = 1; i <= relationColor.length; i++) {
  171. var num = i % examplesSize == 0 ? examplesSize : i % examplesSize;
  172. relationColor[i - 1].x = examples_x + (num - 1) * examplesLength;
  173. relationColor[i - 1].y = examples_y + 20 * Math.ceil(i / examplesSize);
  174. }
  175. if (dataFilter == undefined) {
  176. dataFilter = [];
  177. for (var i = 0; i < relationColor.length; i++) {
  178. dataFilter.push({ "relation": relationColor[i].relation, "isShow": "true" });
  179. }
  180. }
  181. //绑定相连节点
  182. for (var i = 0; i < nodes.length; i++) {
  183. for (var j = 0; j < links.length; j++) {
  184. if (nodes[i].name == links[j].source.name) {
  185. nodes[i][links[j].target.name] = { name: links[j].target.name };
  186. }
  187. if (nodes[i].name == links[j].target.name) {
  188. nodes[i][links[j].source.name] = { name: links[j].source.name };
  189. }
  190. }
  191. }
  192. var svg = d3.select("#" + divid).append("svg")
  193. .attr("width", width)
  194. .attr("height", height)
  195. .attr("style", "background-color:" + backgroundColor);
  196. if (options.showExamples == "true") {
  197. var examples = svg.selectAll(".examples")
  198. .data(relationColor)
  199. .enter()
  200. .append("svg:g")
  201. .attr("fill-opacity", function (d) {
  202. for (var i = 0; i < dataFilter.length; i++) {
  203. if (d.relation == dataFilter[i].relation && dataFilter[i].isShow == "false") {
  204. return 0.2;
  205. }
  206. }
  207. return 1;
  208. })
  209. .on("click", function (d) {
  210. for (var i = 0; i < dataFilter.length; i++) {
  211. if (dataFilter[i].relation == d.relation) {
  212. if (dataFilter[i].isShow == "true") {
  213. dataFilter[i].isShow = "false";
  214. } else {
  215. dataFilter[i].isShow = "true";
  216. }
  217. }
  218. }
  219. drawChart(divid, options, datas, dataFilter);
  220. });
  221. examples.append("svg:path")
  222. .attr("d", function (d) {
  223. var x1 = d.x;
  224. var y1 = d.y;
  225. var x2 = x1 + 20;
  226. var y2 = y1;
  227. return 'M' + x1 + ' ' + y1 + ' L ' + x2 + ' ' + y2;
  228. })
  229. .style("stroke", function (d) {
  230. if (d.lineColor == "") {
  231. return lineColor;
  232. } else {
  233. return d.lineColor;
  234. }
  235. })
  236. .style("stroke-width", 2.5);
  237. examples.append("svg:text")
  238. .style("font-size", "14px")
  239. .style("fill", examplesFontColor)
  240. .attr("x", function (d) {
  241. if (d.relation.length > 3) {
  242. return d.x + 20 + 14 * 4 / 2;
  243. }
  244. return d.x + 20 + 14 * d.relation.length / 2;
  245. })
  246. .attr("y", function (d) {
  247. return d.y + 5;
  248. })
  249. .attr('text-anchor', "middle")
  250. .text(function (d) {
  251. if (d.relation.length > 3) {
  252. return d.relation.substring(0, 3) + "...";
  253. }
  254. return d.relation;
  255. })
  256. .on("mouseover", function (d) {
  257. tooltip.html("<span>" + d.relation + "</span>")
  258. .style("left", (d3.event.pageX) + "px")
  259. .style("top", (d3.event.pageY + 20) + "px")
  260. .style("display", "block")
  261. .style("position", "absolute")
  262. .style("opacity", 1.0);
  263. })
  264. .on("mouseout", function (d, i) {
  265. tooltip.style("opacity", 0.0);
  266. });
  267. }
  268. //D3力导向布局
  269. var force = d3.layout.force()
  270. .nodes(nodes)
  271. .links(links)
  272. .size([width, height])
  273. .linkDistance(200)
  274. .charge(-1500)
  275. .start();
  276. //
  277. var edges_path = svg.selectAll(".edgepath")
  278. .data(links)
  279. .enter()
  280. .append("path")
  281. .attr("marker-end", function (d, i) {
  282. var arrowMarker = svg.append("marker")
  283. .attr("id", "arrow" + i)
  284. .attr("markerUnits", "userSpaceOnUse")
  285. .attr("markerWidth", "16")
  286. .attr("markerHeight", "15")
  287. .attr("viewBox", "0 0 12 12")
  288. .attr("refX", 9)
  289. .attr("refY", 6)
  290. .attr("orient", "auto")
  291. .append("svg:path")
  292. .attr("d", "M2,2 L10,6 L2,10 L6,6 L2,2")
  293. .attr("fill", function () {
  294. return d.lineColor = "" ? lineColor : d.lineColor;
  295. });
  296. return "url(#arrow" + i + ")";
  297. })
  298. .style("stroke", function (d) {
  299. if (d.lineColor == "") {
  300. return lineColor;
  301. } else {
  302. return d.lineColor;
  303. }
  304. })
  305. .style("stroke-width", 1.5)
  306. .on("mouseover", function (d) {
  307. //影藏其它连线上文字
  308. edges_text.style("fill-opacity", function (edge) {
  309. if (edge === d) {
  310. return 1;
  311. }
  312. return 0;
  313. })
  314. edges_path.style("stroke-width", function (edge) {
  315. if (edge === d) {
  316. return 4;
  317. }
  318. return 1.5;
  319. })
  320. })
  321. .on("mouseout", function (d, i) {
  322. //显示连线上的文字
  323. edges_text.style("fill-opacity", 1);
  324. edges_path.style("stroke-width", 1.5);
  325. });
  326. //边上的文字(人物之间的关系)
  327. var edges_text = svg.selectAll(".linetext")
  328. .data(links)
  329. .enter()
  330. .append("svg:g")
  331. .attr("class", "linetext")
  332. .attr("fill-opacity", 1);
  333. edges_text.append("svg:text")
  334. .style("font-size", (lineFontSize + "px"))
  335. .style("font-family", lineFontType)
  336. .style("fill", "#000000")
  337. .attr("y", ".31em")
  338. .attr('text-anchor', "middle")
  339. .text(function (d) {
  340. return d.relation;
  341. });
  342. edges_text.insert('rect', 'text')
  343. .attr('width', function (d) {
  344. return d.relation.length * lineFontSize;
  345. })
  346. .attr('height', function (d) {
  347. return lineFontSize;
  348. })
  349. .attr("y", "-.6em")
  350. .attr('x', function (d) {
  351. return -d.relation.length * lineFontSize / 2;
  352. })
  353. .style('fill', '#fff');
  354. // 圆形图片节点(人物头像)
  355. var circle = svg.selectAll("circle")
  356. .data(nodes)
  357. .enter()
  358. .append("circle")
  359. .style("stroke", function (d) {
  360. if (d.color == "") {
  361. return "#EE8262";
  362. }
  363. return d.color;
  364. })
  365. .style("stroke-width", "2px")
  366. .attr("r", function (d) {
  367. return d.radius;
  368. })
  369. .attr("fill", function (d, i) {
  370. //节点图片不为空是添加背景色
  371. if (d.image == "") {
  372. if (d.color == "") {
  373. return "#EE8262";
  374. }
  375. return d.color;
  376. } else {
  377. //创建圆形图片
  378. var defs = svg.append("defs").attr("id", "imgdefs")
  379. var catpattern = defs.append("pattern")
  380. .attr("id", "catpattern" + i)
  381. .attr("height", 1)
  382. .attr("width", 1)
  383. catpattern.append("image")
  384. /* .attr("x", - (img_w / 2 - radius))
  385. .attr("y", - (img_h / 2 - radius)) */
  386. .attr("width", d.radius * 2)
  387. .attr("height", d.radius * 2)
  388. .attr("xlink:href", d.image)
  389. return "url(#catpattern" + i + ")";
  390. }
  391. })
  392. .on("mouseover", function (d, i) {
  393. //影藏其它连线上文字
  394. edges_text.style("fill-opacity", function (edge) {
  395. if (edge.source === d || edge.target === d) {
  396. return 1;
  397. }
  398. if (edge.source !== d && edge.target !== d) {
  399. return 0;
  400. }
  401. })
  402. //其它节点亮度调低
  403. circle.style("opacity", function (edge) {
  404. var v = d.name;
  405. if (edge.name == v || (edge[v] != undefined && edge[v].name == v)) {
  406. return 1;
  407. } else {
  408. return 0.2;
  409. }
  410. })
  411. //其他连先亮度调低
  412. edges_path.style("opacity", function (edge) {
  413. if (edge.source === d || edge.target === d) {
  414. return 1;
  415. }
  416. if (edge.source !== d && edge.target !== d) {
  417. return 0.2;
  418. }
  419. })
  420. //其他节点文字亮度调低
  421. nodes_text.style("opacity", function (edge) {
  422. var v = d.name;
  423. if (edge.name == v || (edge[v] != undefined && edge[v].name == v)) {
  424. return 1;
  425. } else {
  426. return 0.2;
  427. }
  428. })
  429. })
  430. .on("mouseout", function (d, i) {
  431. //显示连线上的文字
  432. edges_text.style("fill-opacity", 1);
  433. edges_path.style("opacity", 1);
  434. circle.style("opacity", 1);
  435. nodes_text.style("opacity", 1);
  436. tooltip.style("opacity", 0.0);
  437. })
  438. .call(force.drag);
  439. var tooltip = d3.select("body").append("div")
  440. .attr("class", "tooltip")
  441. .attr("opacity", 0.0);
  442. var nodes_text = svg.selectAll(".nodetext")
  443. .data(nodes)
  444. .enter()
  445. .append("text")
  446. .style("font-size", (nodesFontSize + "px"))
  447. .style("font-family", nodesFontType)
  448. .attr('x', function (d) {
  449. var name = d.name;
  450. //如果小于四个字符,不换行
  451. if (name.length < 4) {
  452. d3.select(this).append('tspan')
  453. .attr("dx", -nodesFontSize * (name.length / 2))
  454. .text(function () { return name; });
  455. } else if (name.length >= 4 && name.length <= 6) {
  456. var top = d.name.substring(0, 3);
  457. var bot = d.name.substring(3, name.length);
  458. d3.select(this).append('tspan')
  459. .attr("dx", -nodesFontSize * 1.5)
  460. .attr("dy", -nodesFontSize * 0.5)
  461. .text(function () { return top; });
  462. d3.select(this).append('tspan')
  463. .attr("dx", -(nodesFontSize * name.length / 2))
  464. .attr("dy", nodesFontSize)
  465. .text(function () { return bot; });
  466. } else if (name.length > 7) {
  467. var top = d.name.substring(0, 3);
  468. var mid = d.name.substring(3, 6);
  469. var bot = d.name.substring(6, name.length);
  470. d3.select(this).append('tspan')
  471. .attr("dx", -nodesFontSize * 1.5)
  472. .attr("dy", -nodesFontSize * 0.5)
  473. .text(function () { return top; });
  474. d3.select(this).append('tspan')
  475. .attr("dx", -nodesFontSize * 3)
  476. .attr("dy", nodesFontSize)
  477. .text(function () { return mid; });
  478. d3.select(this).append('tspan')
  479. .attr("dx", -nodesFontSize * 2)
  480. .attr("dy", nodesFontSize)
  481. .text(function () { return "..."; });
  482. }
  483. })
  484. .on("mouseover", function (d, i) {
  485. //影藏其它连线上文字
  486. edges_text.style("fill-opacity", function (edge) {
  487. if (edge.source === d || edge.target === d) {
  488. return 1;
  489. }
  490. if (edge.source !== d && edge.target !== d) {
  491. return 0;
  492. }
  493. })
  494. //其他节点亮度调低
  495. circle.style("opacity", function (edge) {
  496. var v = d.name;
  497. if (edge.name == v || (edge[v] != undefined && edge[v].name == v)) {
  498. return 1;
  499. } else {
  500. return 0.2;
  501. }
  502. })
  503. //其他连线亮度调低
  504. edges_path.style("opacity", function (edge) {
  505. if (edge.source === d || edge.target === d) {
  506. return 1;
  507. }
  508. if (edge.source !== d && edge.target !== d) {
  509. return 0.2;
  510. }
  511. })
  512. //其他节点文字亮度调低
  513. nodes_text.style("opacity", function (edge) {
  514. var v = d.name;
  515. if (edge.name == v || (edge[v] != undefined && edge[v].name == v)) {
  516. return 1;
  517. } else {
  518. return 0.2;
  519. }
  520. })
  521. tooltip.html("<span>" + d.name + "</span>")
  522. .style("left", (d3.event.pageX) + "px")
  523. .style("top", (d3.event.pageY + 20) + "px")
  524. .style("display", "block")
  525. .style("opacity", 1.0);
  526. })
  527. .on("mouseout", function (d, i) {
  528. //显示连线上的文字
  529. edges_text.style("fill-opacity", 1);
  530. edges_path.style("opacity", 1);
  531. circle.style("opacity", 1);
  532. nodes_text.style("opacity", 1);
  533. tooltip.style("opacity", 0.0);
  534. })
  535. .call(force.drag);
  536. var drag = force.drag()
  537. .on("dragstart", function (d, i) {
  538. d.fixed = true; //拖拽开始后设定被拖拽对象为固定
  539. })
  540. .on("dragend", function (d, i) {
  541. })
  542. .on("drag", function (d, i) {
  543. });
  544. //力学图运动开始时
  545. force.on("start", function () {
  546. });
  547. //力学图运动结束时
  548. force.on("end", function () {
  549. });
  550. force.on("tick", function () {
  551. //限制结点的边界
  552. nodes.forEach(function (d, i) {
  553. d.x = d.x - 45 < 0 ? 45 : d.x;
  554. d.x = d.x + 45 > width ? width - 45 : d.x;
  555. d.y = d.y - 45 < 0 ? 45 : d.y;
  556. d.y = d.y + 45 > height ? height - 45 : d.y;
  557. });
  558. edges_path.attr("d", function (d) {
  559. var tan = Math.abs((d.target.y - d.source.y) / (d.target.x - d.source.x)); //圆心连线tan值
  560. var x1 = d.target.x - d.source.x > 0 ? Math.sqrt(d.sourceRadius * d.sourceRadius / (tan * tan + 1)) + d.source.x :
  561. d.source.x - Math.sqrt(d.sourceRadius * d.sourceRadius / (tan * tan + 1)); //起点x坐标
  562. var y1 = d.target.y - d.source.y > 0 ? Math.sqrt(d.sourceRadius * d.sourceRadius * tan * tan / (tan * tan + 1)) + d.source.y :
  563. d.source.y - Math.sqrt(d.sourceRadius * d.sourceRadius * tan * tan / (tan * tan + 1)); //起点y坐标
  564. var x2 = d.target.x - d.source.x > 0 ? d.target.x - Math.sqrt(d.targetRadius * d.targetRadius / (1 + tan * tan)) :
  565. d.target.x + Math.sqrt(d.targetRadius * d.targetRadius / (1 + tan * tan));//终点x坐标
  566. var y2 = d.target.y - d.source.y > 0 ? d.target.y - Math.sqrt(d.targetRadius * d.targetRadius * tan * tan / (1 + tan * tan)) :
  567. d.target.y + Math.sqrt(d.targetRadius * d.targetRadius * tan * tan / (1 + tan * tan));//终点y坐标
  568. if (d.target.x - d.source.x == 0 || tan == 0) { //斜率无穷大的情况或为0
  569. y1 = d.target.y - d.source.y > 0 ? d.source.y + d.sourceRadius : d.source.y - d.sourceRadius;
  570. y2 = d.target.y - d.source.y > 0 ? d.target.y - d.targetRadius : d.target.y + d.targetRadius;
  571. }
  572. if (d.linknum == 0) {//设置编号为0的连接线为直线,其他连接线会均分在两边
  573. d.x_start = x1;
  574. d.y_start = y1;
  575. d.x_end = x2;
  576. d.y_end = y2;
  577. return 'M' + x1 + ' ' + y1 + ' L ' + x2 + ' ' + y2;
  578. }
  579. var a = d.sourceRadius > d.targetRadius ? d.targetRadius * d.linknum / 3 : d.sourceRadius * d.linknum / 3;
  580. var xm = d.target.x - d.source.x > 0 ? d.source.x + Math.sqrt((d.sourceRadius * d.sourceRadius - a * a) / (1 + tan * tan)) :
  581. d.source.x - Math.sqrt((d.sourceRadius * d.sourceRadius - a * a) / (1 + tan * tan));
  582. var ym = d.target.y - d.source.y > 0 ? d.source.y + Math.sqrt((d.sourceRadius * d.sourceRadius - a * a) * tan * tan / (1 + tan * tan)) :
  583. d.source.y - Math.sqrt((d.sourceRadius * d.sourceRadius - a * a) * tan * tan / (1 + tan * tan));
  584. var xn = d.target.x - d.source.x > 0 ? d.target.x - Math.sqrt((d.targetRadius * d.targetRadius - a * a) / (1 + tan * tan)) :
  585. d.target.x + Math.sqrt((d.targetRadius * d.targetRadius - a * a) / (1 + tan * tan));
  586. var yn = d.target.y - d.source.y > 0 ? d.target.y - Math.sqrt((d.targetRadius * d.targetRadius - a * a) * tan * tan / (1 + tan * tan)) :
  587. d.target.y + Math.sqrt((d.targetRadius * d.targetRadius - a * a) * tan * tan / (1 + tan * tan));
  588. if (d.target.x - d.source.x == 0 || tan == 0) {//斜率无穷大或为0
  589. 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);
  590. 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);
  591. }
  592. var k = (x1 - x2) / (y2 - y1);//连线垂线的斜率
  593. var dx = Math.sqrt(a * a / (1 + k * k)); //相对垂点x轴距离
  594. var dy = Math.sqrt(a * a * k * k / (1 + k * k)); //相对垂点y轴距离
  595. if ((y2 - y1) == 0) {
  596. dx = 0;
  597. dy = Math.sqrt(a * a);
  598. }
  599. if (a > 0) {
  600. var xs = k > 0 ? xm - dx : xm + dx;
  601. var ys = ym - dy;
  602. var xt = k > 0 ? xn - dx : xn + dx;
  603. var yt = yn - dy;
  604. } else {
  605. var xs = k > 0 ? xm + dx : xm - dx;
  606. var ys = ym + dy;
  607. var xt = k > 0 ? xn + dx : xn - dx;
  608. var yt = yn + dy;
  609. }
  610. //记录连线起始和终止坐标,用于定位线上文字
  611. d.x_start = xs;
  612. d.y_start = ys;
  613. d.x_end = xt;
  614. d.y_end = yt;
  615. return 'M' + xs + ' ' + ys + ' L ' + xt + ' ' + yt;
  616. });
  617. //更新连接线上文字的位置
  618. edges_text.attr("transform", function (d) {
  619. return "translate(" + (d.x_start + d.x_end) / 2 + "," + (d.y_start + d.y_end) / 2 + ")" + " rotate(" + Math.atan((d.y_end - d.y_start) / (d.x_end - d.x_start)) * 180 / Math.PI + ")";
  620. });
  621. //更新结点图片和文字
  622. circle.attr("cx", function (d) { return d.x });
  623. circle.attr("cy", function (d) { return d.y });
  624. nodes_text.attr("x", function (d) { return d.x });
  625. nodes_text.attr("y", function (d) { return d.y });
  626. });
  627. }
  628. function setLinkNumber(group) {
  629. if (group.length == 0) return;
  630. if (group.length == 1) {
  631. group[0].linknum = 0;
  632. return;
  633. }
  634. var maxLinkNumber = group.length % 2 == 0 ? group.length / 2 : (group.length - 1) / 2;
  635. if (group.length % 2 == 0) {
  636. var startLinkNum = -maxLinkNumber + 0.5;
  637. for (var i = 0; i < group.length; i++) {
  638. group[i].linknum = startLinkNum++;
  639. }
  640. } else {
  641. var startLinkNum = -maxLinkNumber;
  642. for (var i = 0; i < group.length; i++) {
  643. group[i].linknum = startLinkNum++;
  644. }
  645. }
  646. }
  647. </script>
  648. </html>

git地址:https://github.com/binliuli/visual.git

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/562990
推荐阅读
相关标签
  

闽ICP备14008679号