vis.js is a dynamic, browser-based visualization library
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

81 lines
2.2 KiB

  1. /**
  2. * @class HierarchicalRepulsionSolver
  3. */
  4. class HierarchicalRepulsionSolver {
  5. /**
  6. * @param {Object} body
  7. * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
  8. * @param {Object} options
  9. * @constructor HierarchicalRepulsionSolver
  10. */
  11. constructor(body, physicsBody, options) {
  12. this.body = body;
  13. this.physicsBody = physicsBody;
  14. this.setOptions(options);
  15. }
  16. /**
  17. *
  18. * @param {Object} options
  19. */
  20. setOptions(options) {
  21. this.options = options;
  22. }
  23. /**
  24. * Calculate the forces the nodes apply on each other based on a repulsion field.
  25. * This field is linearly approximated.
  26. *
  27. * @private
  28. */
  29. solve() {
  30. var dx, dy, distance, fx, fy, repulsingForce, node1, node2, i, j;
  31. var nodes = this.body.nodes;
  32. var nodeIndices = this.physicsBody.physicsNodeIndices;
  33. var forces = this.physicsBody.forces;
  34. // repulsing forces between nodes
  35. var nodeDistance = this.options.nodeDistance;
  36. // we loop from i over all but the last entree in the array
  37. // j loops from i+1 to the last. This way we do not double count any of the indices, nor i === j
  38. for (i = 0; i < nodeIndices.length - 1; i++) {
  39. node1 = nodes[nodeIndices[i]];
  40. for (j = i + 1; j < nodeIndices.length; j++) {
  41. node2 = nodes[nodeIndices[j]];
  42. // nodes only affect nodes on their level
  43. if (node1.level === node2.level) {
  44. dx = node2.x - node1.x;
  45. dy = node2.y - node1.y;
  46. distance = Math.sqrt(dx * dx + dy * dy);
  47. var steepness = 0.05;
  48. if (distance < nodeDistance) {
  49. repulsingForce = -Math.pow(steepness * distance, 2) + Math.pow(steepness * nodeDistance, 2);
  50. }
  51. else {
  52. repulsingForce = 0;
  53. }
  54. // normalize force with
  55. if (distance === 0) {
  56. distance = 0.01;
  57. }
  58. else {
  59. repulsingForce = repulsingForce / distance;
  60. }
  61. fx = dx * repulsingForce;
  62. fy = dy * repulsingForce;
  63. forces[node1.id].x -= fx;
  64. forces[node1.id].y -= fy;
  65. forces[node2.id].x += fx;
  66. forces[node2.id].y += fy;
  67. }
  68. }
  69. }
  70. }
  71. }
  72. export default HierarchicalRepulsionSolver;