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.

64 lines
2.2 KiB

  1. /**
  2. * Calculate the forces the nodes apply on each other based on a repulsion field.
  3. * This field is linearly approximated.
  4. *
  5. * @private
  6. */
  7. exports._calculateNodeForces = function () {
  8. var dx, dy, angle, distance, fx, fy, combinedClusterSize,
  9. repulsingForce, node1, node2, i, j;
  10. var nodes = this.calculationNodes;
  11. var nodeIndices = this.calculationNodeIndices;
  12. // approximation constants
  13. var a_base = -2 / 3;
  14. var b = 4 / 3;
  15. // repulsing forces between nodes
  16. var nodeDistance = this.constants.physics.repulsion.nodeDistance;
  17. var minimumDistance = nodeDistance;
  18. // we loop from i over all but the last entree in the array
  19. // j loops from i+1 to the last. This way we do not double count any of the indices, nor i == j
  20. for (i = 0; i < nodeIndices.length - 1; i++) {
  21. node1 = nodes[nodeIndices[i]];
  22. for (j = i + 1; j < nodeIndices.length; j++) {
  23. node2 = nodes[nodeIndices[j]];
  24. combinedClusterSize = node1.clusterSize + node2.clusterSize - 2;
  25. dx = node2.x - node1.x;
  26. dy = node2.y - node1.y;
  27. distance = Math.sqrt(dx * dx + dy * dy);
  28. // same condition as BarnesHutSolver, making sure nodes are never 100% overlapping.
  29. if (distance == 0) {
  30. distance = 0.1*Math.random();
  31. dx = distance;
  32. }
  33. minimumDistance = (combinedClusterSize == 0) ? nodeDistance : (nodeDistance * (1 + combinedClusterSize * this.constants.clustering.distanceAmplification));
  34. var a = a_base / minimumDistance;
  35. if (distance < 2 * minimumDistance) {
  36. if (distance < 0.5 * minimumDistance) {
  37. repulsingForce = 1.0;
  38. }
  39. else {
  40. repulsingForce = a * distance + b; // linear approx of 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness))
  41. }
  42. // amplify the repulsion for clusters.
  43. repulsingForce *= (combinedClusterSize == 0) ? 1 : 1 + combinedClusterSize * this.constants.clustering.forceAmplification;
  44. repulsingForce = repulsingForce / Math.max(distance,0.01*minimumDistance);
  45. fx = dx * repulsingForce;
  46. fy = dy * repulsingForce;
  47. node1.fx -= fx;
  48. node1.fy -= fy;
  49. node2.fx += fx;
  50. node2.fy += fy;
  51. }
  52. }
  53. }
  54. };