d3graph.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. import * as d3 from "https://cdn.jsdelivr.net/npm/d3@7/+esm";
  2. function getOrCreateNode(id, name, nodes, dict) {
  3. var node = dict[id];
  4. if (!node) {
  5. node = {}
  6. node.id = id;
  7. node.name = name;
  8. nodes.push(node);
  9. dict[id] = node;
  10. }
  11. return node;
  12. }
  13. function toGraphData(data) {
  14. var graph = {};
  15. var nodes = graph.nodes = [];
  16. var links = graph.links = [];
  17. var idToNode = [];
  18. var columns = data.head.vars;
  19. data.results.bindings.forEach(item => {
  20. var srcID = item[columns[0]].value;
  21. var trgtID = item[columns[1]].value;
  22. var src = getOrCreateNode(srcID, srcID, nodes, idToNode);
  23. var trgt = getOrCreateNode(trgtID, trgtID, nodes, idToNode);
  24. var link = {};
  25. link.source = src.id;
  26. link.target = trgt.id;
  27. links.push(link);
  28. });
  29. return graph;
  30. }
  31. function drawGraph(data, containerID, width = 500, height = 300) {
  32. var graph = toGraphData(data)
  33. var container = d3.select(containerID);
  34. var svg = container.append('svg').attr("width", width).attr("height", height);
  35. // arrow def
  36. svg.append('defs').append('marker')
  37. .attr('id', 'arrowhead')
  38. .attr('viewBox', '-0 -5 10 10')
  39. .attr('refX', 13)
  40. .attr('refY', 0)
  41. .attr('orient', 'auto')
  42. .attr('markerWidth', 13)
  43. .attr('markerHeight', 13)
  44. .attr('xoverflow', 'visible')
  45. .append('svg:path')
  46. .attr('d', 'M 0,-5 L 10 ,0 L 0,5')
  47. .attr('fill', '#999')
  48. .style('stroke', 'none');
  49. var nodes = graph.nodes;
  50. var links = graph.links;
  51. var simulation = d3.forceSimulation()
  52. .force("link", d3.forceLink().id(function (d) {
  53. return d.id;
  54. }).distance(80))
  55. .force("charge", d3.forceManyBody().strength(-100))
  56. .force("center", d3.forceCenter(width / 2, height / 2));
  57. var link = svg.selectAll(".link")
  58. .data(links)
  59. .enter()
  60. .append("line")
  61. .attr("class", "link")
  62. .attr('marker-end', 'url(#arrowhead)')
  63. var node = svg.selectAll(".node")
  64. .data(nodes)
  65. .enter()
  66. .append("g")
  67. .attr("class", "node")
  68. .call(d3.drag()
  69. .on("start", dragstarted)
  70. .on("drag", dragged)
  71. .on("end", dragended));
  72. node.append("circle")
  73. .attr("r", 5)
  74. .style("fill", "red")
  75. node.append("title")
  76. .text(function (d) {
  77. return d.name;
  78. });
  79. node.append("text")
  80. .attr("dy", -3)
  81. .text(function (d) {
  82. return d.id
  83. });
  84. simulation.nodes(nodes).on("tick", ticked);
  85. simulation.force("link").links(links);
  86. function ticked() {
  87. link
  88. .attr("x1", function (d) {
  89. return getX(d.source.x);
  90. })
  91. .attr("y1", function (d) {
  92. return getY(d.source.y);
  93. })
  94. .attr("x2", function (d) {
  95. return getX(d.target.x);
  96. })
  97. .attr("y2", function (d) {
  98. return getY(d.target.y);
  99. });
  100. node.attr("transform",
  101. function (d) {
  102. var dx = getX(d.x);
  103. var dy = getY(d.y);
  104. return "translate(" + dx + ", " + dy + ")";
  105. }
  106. );
  107. function getX(x) {
  108. var dx = x;
  109. if (dx < 20) dx = 20;
  110. if (dx > width - 20) dx = width - 20;
  111. return dx;
  112. }
  113. function getY(y) {
  114. var dy = y;
  115. if (dy < 20) dy = 20;
  116. if (dy > height - 20) dy = height - 20;
  117. return dy;
  118. }
  119. }
  120. function dragstarted(event) {
  121. if (!event.active) simulation.alphaTarget(0.3).restart()
  122. event.subject.fx = event.subject.x;
  123. event.subject.fy = event.subject.y;
  124. }
  125. function dragged(event) {
  126. event.subject.fx = event.x;
  127. event.subject.fy = event.y;
  128. }
  129. function dragended(event) {
  130. if (!event.active) simulation.alphaTarget(0);
  131. event.subject.fx = null;
  132. event.subject.fy = null;
  133. }
  134. }
  135. export { drawGraph, toGraphData };
  136. export default drawGraph;