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.

113 lines
3.5 KiB

  1. /**
  2. * Created by Alex on 2/6/14.
  3. */
  4. var physicsMixin = {
  5. _toggleBarnesHut : function() {
  6. this.constants.physics.barnesHut.enabled = !this.constants.physics.barnesHut.enabled;
  7. this._loadSelectedForceSolver();
  8. this.moving = true;
  9. this.start();
  10. },
  11. /**
  12. * Before calculating the forces, we check if we need to cluster to keep up performance and we check
  13. * if there is more than one node. If it is just one node, we dont calculate anything.
  14. *
  15. * @private
  16. */
  17. _initializeForceCalculation : function() {
  18. // stop calculation if there is only one node
  19. if (this.nodeIndices.length == 1) {
  20. this.nodes[this.nodeIndices[0]]._setForce(0,0);
  21. }
  22. else {
  23. // if there are too many nodes on screen, we cluster without repositioning
  24. if (this.nodeIndices.length > this.constants.clustering.clusterThreshold && this.constants.clustering.enabled == true) {
  25. this.clusterToFit(this.constants.clustering.reduceToNodes, false);
  26. }
  27. // we now start the force calculation
  28. this._calculateForces();
  29. }
  30. },
  31. /**
  32. * Calculate the external forces acting on the nodes
  33. * Forces are caused by: edges, repulsing forces between nodes, gravity
  34. * @private
  35. */
  36. _calculateForces : function() {
  37. this.barnesHutTree = undefined;
  38. // Gravity is required to keep separated groups from floating off
  39. // the forces are reset to zero in this loop by using _setForce instead
  40. // of _addForce
  41. this._calculateGravitationalForces();
  42. this._calculateNodeForces();
  43. this._calculateSpringForces();
  44. },
  45. _calculateGravitationalForces : function() {
  46. var dx, dy, angle, fx, fy, node, i;
  47. var nodes = this.nodes;
  48. var gravity = this.constants.physics.centralGravity;
  49. for (i = 0; i < this.nodeIndices.length; i++) {
  50. node = nodes[this.nodeIndices[i]];
  51. // gravity does not apply when we are in a pocket sector
  52. if (this._sector() == "default") {
  53. dx = -node.x;// + screenCenterPos.x;
  54. dy = -node.y;// + screenCenterPos.y;
  55. angle = Math.atan2(dy, dx);
  56. fx = Math.cos(angle) * gravity;
  57. fy = Math.sin(angle) * gravity;
  58. }
  59. else {
  60. fx = 0;
  61. fy = 0;
  62. }
  63. node._setForce(fx, fy);
  64. node.updateDamping(this.nodeIndices.length);
  65. }
  66. },
  67. _calculateSpringForces : function() {
  68. var dx, dy, angle, fx, fy, springForce, length, edgeLength, edge, edgeId;
  69. var edges = this.edges;
  70. // forces caused by the edges, modelled as springs
  71. for (edgeId in edges) {
  72. if (edges.hasOwnProperty(edgeId)) {
  73. edge = edges[edgeId];
  74. if (edge.connected) {
  75. // only calculate forces if nodes are in the same sector
  76. if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) {
  77. dx = (edge.to.x - edge.from.x);
  78. dy = (edge.to.y - edge.from.y);
  79. edgeLength = edge.length;
  80. // this implies that the edges between big clusters are longer
  81. edgeLength += (edge.to.growthIndicator + edge.from.growthIndicator) * this.constants.clustering.edgeGrowth;
  82. length = Math.sqrt(dx * dx + dy * dy);
  83. angle = Math.atan2(dy, dx);
  84. springForce = this.constants.physics.springConstant * (edgeLength - length);
  85. fx = Math.cos(angle) * springForce;
  86. fy = Math.sin(angle) * springForce;
  87. edge.from._addForce(-fx, -fy);
  88. edge.to._addForce(fx, fy);
  89. }
  90. }
  91. }
  92. }
  93. }
  94. }