link.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. import constant from "./constant.js";
  2. import jiggle from "./jiggle.js";
  3. function index(d) {
  4. return d.index;
  5. }
  6. function find(nodeById, nodeId) {
  7. var node = nodeById.get(nodeId);
  8. if (!node) throw new Error("node not found: " + nodeId);
  9. return node;
  10. }
  11. export default function(links) {
  12. var id = index,
  13. strength = defaultStrength,
  14. strengths,
  15. distance = constant(30),
  16. distances,
  17. nodes,
  18. count,
  19. bias,
  20. random,
  21. iterations = 1;
  22. if (links == null) links = [];
  23. function defaultStrength(link) {
  24. return 1 / Math.min(count[link.source.index], count[link.target.index]);
  25. }
  26. function force(alpha) {
  27. for (var k = 0, n = links.length; k < iterations; ++k) {
  28. for (var i = 0, link, source, target, x, y, l, b; i < n; ++i) {
  29. link = links[i], source = link.source, target = link.target;
  30. x = target.x + target.vx - source.x - source.vx || jiggle(random);
  31. y = target.y + target.vy - source.y - source.vy || jiggle(random);
  32. l = Math.sqrt(x * x + y * y);
  33. l = (l - distances[i]) / l * alpha * strengths[i];
  34. x *= l, y *= l;
  35. target.vx -= x * (b = bias[i]);
  36. target.vy -= y * b;
  37. source.vx += x * (b = 1 - b);
  38. source.vy += y * b;
  39. }
  40. }
  41. }
  42. function initialize() {
  43. if (!nodes) return;
  44. var i,
  45. n = nodes.length,
  46. m = links.length,
  47. nodeById = new Map(nodes.map((d, i) => [id(d, i, nodes), d])),
  48. link;
  49. for (i = 0, count = new Array(n); i < m; ++i) {
  50. link = links[i], link.index = i;
  51. if (typeof link.source !== "object") link.source = find(nodeById, link.source);
  52. if (typeof link.target !== "object") link.target = find(nodeById, link.target);
  53. count[link.source.index] = (count[link.source.index] || 0) + 1;
  54. count[link.target.index] = (count[link.target.index] || 0) + 1;
  55. }
  56. for (i = 0, bias = new Array(m); i < m; ++i) {
  57. link = links[i], bias[i] = count[link.source.index] / (count[link.source.index] + count[link.target.index]);
  58. }
  59. strengths = new Array(m), initializeStrength();
  60. distances = new Array(m), initializeDistance();
  61. }
  62. function initializeStrength() {
  63. if (!nodes) return;
  64. for (var i = 0, n = links.length; i < n; ++i) {
  65. strengths[i] = +strength(links[i], i, links);
  66. }
  67. }
  68. function initializeDistance() {
  69. if (!nodes) return;
  70. for (var i = 0, n = links.length; i < n; ++i) {
  71. distances[i] = +distance(links[i], i, links);
  72. }
  73. }
  74. force.initialize = function(_nodes, _random) {
  75. nodes = _nodes;
  76. random = _random;
  77. initialize();
  78. };
  79. force.links = function(_) {
  80. return arguments.length ? (links = _, initialize(), force) : links;
  81. };
  82. force.id = function(_) {
  83. return arguments.length ? (id = _, force) : id;
  84. };
  85. force.iterations = function(_) {
  86. return arguments.length ? (iterations = +_, force) : iterations;
  87. };
  88. force.strength = function(_) {
  89. return arguments.length ? (strength = typeof _ === "function" ? _ : constant(+_), initializeStrength(), force) : strength;
  90. };
  91. force.distance = function(_) {
  92. return arguments.length ? (distance = typeof _ === "function" ? _ : constant(+_), initializeDistance(), force) : distance;
  93. };
  94. return force;
  95. }