forceHelper.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. var vec2 = require("zrender/lib/core/vector");
  2. var scaleAndAdd = vec2.scaleAndAdd; // function adjacentNode(n, e) {
  3. // return e.n1 === n ? e.n2 : e.n1;
  4. // }
  5. function forceLayout(nodes, edges, opts) {
  6. var rect = opts.rect;
  7. var width = rect.width;
  8. var height = rect.height;
  9. var center = [rect.x + width / 2, rect.y + height / 2]; // var scale = opts.scale || 1;
  10. var gravity = opts.gravity == null ? 0.1 : opts.gravity; // for (var i = 0; i < edges.length; i++) {
  11. // var e = edges[i];
  12. // var n1 = e.n1;
  13. // var n2 = e.n2;
  14. // n1.edges = n1.edges || [];
  15. // n2.edges = n2.edges || [];
  16. // n1.edges.push(e);
  17. // n2.edges.push(e);
  18. // }
  19. // Init position
  20. for (var i = 0; i < nodes.length; i++) {
  21. var n = nodes[i];
  22. if (!n.p) {
  23. // Use the position from first adjecent node with defined position
  24. // Or use a random position
  25. // From d3
  26. // if (n.edges) {
  27. // var j = -1;
  28. // while (++j < n.edges.length) {
  29. // var e = n.edges[j];
  30. // var other = adjacentNode(n, e);
  31. // if (other.p) {
  32. // n.p = vec2.clone(other.p);
  33. // break;
  34. // }
  35. // }
  36. // }
  37. // if (!n.p) {
  38. n.p = vec2.create(width * (Math.random() - 0.5) + center[0], height * (Math.random() - 0.5) + center[1]); // }
  39. }
  40. n.pp = vec2.clone(n.p);
  41. n.edges = null;
  42. } // Formula in 'Graph Drawing by Force-directed Placement'
  43. // var k = scale * Math.sqrt(width * height / nodes.length);
  44. // var k2 = k * k;
  45. var friction = 0.6;
  46. return {
  47. warmUp: function () {
  48. friction = 0.5;
  49. },
  50. setFixed: function (idx) {
  51. nodes[idx].fixed = true;
  52. },
  53. setUnfixed: function (idx) {
  54. nodes[idx].fixed = false;
  55. },
  56. step: function (cb) {
  57. var v12 = [];
  58. var nLen = nodes.length;
  59. for (var i = 0; i < edges.length; i++) {
  60. var e = edges[i];
  61. var n1 = e.n1;
  62. var n2 = e.n2;
  63. vec2.sub(v12, n2.p, n1.p);
  64. var d = vec2.len(v12) - e.d;
  65. var w = n2.w / (n1.w + n2.w);
  66. if (isNaN(w)) {
  67. w = 0;
  68. }
  69. vec2.normalize(v12, v12);
  70. !n1.fixed && scaleAndAdd(n1.p, n1.p, v12, w * d * friction);
  71. !n2.fixed && scaleAndAdd(n2.p, n2.p, v12, -(1 - w) * d * friction);
  72. } // Gravity
  73. for (var i = 0; i < nLen; i++) {
  74. var n = nodes[i];
  75. if (!n.fixed) {
  76. vec2.sub(v12, center, n.p); // var d = vec2.len(v12);
  77. // vec2.scale(v12, v12, 1 / d);
  78. // var gravityFactor = gravity;
  79. scaleAndAdd(n.p, n.p, v12, gravity * friction);
  80. }
  81. } // Repulsive
  82. // PENDING
  83. for (var i = 0; i < nLen; i++) {
  84. var n1 = nodes[i];
  85. for (var j = i + 1; j < nLen; j++) {
  86. var n2 = nodes[j];
  87. vec2.sub(v12, n2.p, n1.p);
  88. var d = vec2.len(v12);
  89. if (d === 0) {
  90. // Random repulse
  91. vec2.set(v12, Math.random() - 0.5, Math.random() - 0.5);
  92. d = 1;
  93. }
  94. var repFact = (n1.rep + n2.rep) / d / d;
  95. !n1.fixed && scaleAndAdd(n1.pp, n1.pp, v12, repFact);
  96. !n2.fixed && scaleAndAdd(n2.pp, n2.pp, v12, -repFact);
  97. }
  98. }
  99. var v = [];
  100. for (var i = 0; i < nLen; i++) {
  101. var n = nodes[i];
  102. if (!n.fixed) {
  103. vec2.sub(v, n.p, n.pp);
  104. scaleAndAdd(n.p, n.p, v, friction);
  105. vec2.copy(n.pp, n.p);
  106. }
  107. }
  108. friction = friction * 0.992;
  109. cb && cb(nodes, edges, friction < 0.01);
  110. }
  111. };
  112. }
  113. exports.forceLayout = forceLayout;