/** * Created by Alex on 2/6/14. */ var physicsMixin = { _toggleBarnesHut : function() { this.constants.physics.barnesHut.enabled = !this.constants.physics.barnesHut.enabled; this._loadSelectedForceSolver(); this.moving = true; this.start(); }, /** * Before calculating the forces, we check if we need to cluster to keep up performance and we check * if there is more than one node. If it is just one node, we dont calculate anything. * * @private */ _initializeForceCalculation : function() { // stop calculation if there is only one node if (this.nodeIndices.length == 1) { this.nodes[this.nodeIndices[0]]._setForce(0,0); } else { // if there are too many nodes on screen, we cluster without repositioning if (this.nodeIndices.length > this.constants.clustering.clusterThreshold && this.constants.clustering.enabled == true) { this.clusterToFit(this.constants.clustering.reduceToNodes, false); } // we now start the force calculation this._calculateForces(); } }, /** * Calculate the external forces acting on the nodes * Forces are caused by: edges, repulsing forces between nodes, gravity * @private */ _calculateForces : function() { this.barnesHutTree = undefined; // Gravity is required to keep separated groups from floating off // the forces are reset to zero in this loop by using _setForce instead // of _addForce this._calculateGravitationalForces(); this._calculateNodeForces(); this._calculateSpringForces(); }, _calculateGravitationalForces : function() { var dx, dy, angle, fx, fy, node, i; var nodes = this.nodes; var gravity = this.constants.physics.centralGravity; for (i = 0; i < this.nodeIndices.length; i++) { node = nodes[this.nodeIndices[i]]; // gravity does not apply when we are in a pocket sector if (this._sector() == "default") { dx = -node.x;// + screenCenterPos.x; dy = -node.y;// + screenCenterPos.y; angle = Math.atan2(dy, dx); fx = Math.cos(angle) * gravity; fy = Math.sin(angle) * gravity; } else { fx = 0; fy = 0; } node._setForce(fx, fy); node.updateDamping(this.nodeIndices.length); } }, _calculateSpringForces : function() { var dx, dy, angle, fx, fy, springForce, length, edgeLength, edge, edgeId; var edges = this.edges; // forces caused by the edges, modelled as springs for (edgeId in edges) { if (edges.hasOwnProperty(edgeId)) { edge = edges[edgeId]; if (edge.connected) { // only calculate forces if nodes are in the same sector if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) { dx = (edge.to.x - edge.from.x); dy = (edge.to.y - edge.from.y); edgeLength = edge.length; // this implies that the edges between big clusters are longer edgeLength += (edge.to.growthIndicator + edge.from.growthIndicator) * this.constants.clustering.edgeGrowth; length = Math.sqrt(dx * dx + dy * dy); angle = Math.atan2(dy, dx); springForce = this.constants.physics.springConstant * (edgeLength - length); fx = Math.cos(angle) * springForce; fy = Math.sin(angle) * springForce; edge.from._addForce(-fx, -fy); edge.to._addForce(fx, fy); } } } } } }