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.

83 lines
2.3 KiB

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