function _updateLinkShapes() { var v = vec2.create(); var right = vec2.create(1, 0); for (var i = 0, len = filteredLinks.length; i < len; i++) { var link = filteredLinks[i]; var linkShape = linkShapes[i]; var sourceShape = nodeShapes[link.source]; var targetShape = nodeShapes[link.target]; linkShape.style.xStart = sourceShape.position[0]; linkShape.style.yStart = sourceShape.position[1]; linkShape.style.xEnd = targetShape.position[0]; linkShape.style.yEnd = targetShape.position[1]; if (forceSerie.linkSymbol) { var arrowShape = arrowShapes[i]; vec2.copy(arrowShape.position, targetShape.position); vec2.sub(v, sourceShape.position, targetShape.position); vec2.normalize(v, v); vec2.scaleAndAdd( arrowShape.position, arrowShape.position, v, targetShape.style.r + 2 ); if (v[1] < 0) { var angle = 2 * Math.PI - Math.acos(-v[0]); } else { var angle = Math.acos(-v[0]); } arrowShape.rotation = angle - Math.PI / 2; } } }
_updateLinkShapes: function() { var v = vec2.create(); var n = vec2.create(); var p1 = vec2.create(); var p2 = vec2.create(); var edges = this._graph.edges; for (var i = 0, len = edges.length; i < len; i++) { var edge = edges[i]; var sourceShape = edge.node1.shape; var targetShape = edge.node2.shape; vec2.copy(p1, sourceShape.position); vec2.copy(p2, targetShape.position); var edgeShapeStyle = edge.shape.style; vec2.sub(v, p1, p2); vec2.normalize(v, v); if (edgeShapeStyle.offset) { n[0] = v[1]; n[1] = - v[0]; vec2.scaleAndAdd(p1, p1, n, edgeShapeStyle.offset); vec2.scaleAndAdd(p2, p2, n, edgeShapeStyle.offset); } else if (edge.shape.type === 'bezier-curve') { edgeShapeStyle.cpX1 = (p1[0] + p2[0]) / 2 - (p2[1] - p1[1]) / 4; edgeShapeStyle.cpY1 = (p1[1] + p2[1]) / 2 - (p1[0] - p2[0]) / 4; } edgeShapeStyle.xStart = p1[0]; edgeShapeStyle.yStart = p1[1]; edgeShapeStyle.xEnd = p2[0]; edgeShapeStyle.yEnd = p2[1]; edge.shape.modSelf(); if (edge.shape._symbolShape) { var symbolShape = edge.shape._symbolShape; vec2.copy(symbolShape.position, p2); vec2.scaleAndAdd( symbolShape.position, symbolShape.position, v, targetShape.style.width / 2 + 2 ); var angle = Math.atan2(v[1], v[0]); symbolShape.rotation = Math.PI / 2 - angle; symbolShape.modSelf(); } } },
_updateLinkShapes: function() { var v = vec2.create(); var links = this._filteredLinks; for (var i = 0, len = links.length; i < len; i++) { var link = links[i]; var linkShape = this._linkShapes[i]; var sourceShape = this._nodeShapes[link.source]; var targetShape = this._nodeShapes[link.target]; linkShape.style.xStart = sourceShape.position[0]; linkShape.style.yStart = sourceShape.position[1]; linkShape.style.xEnd = targetShape.position[0]; linkShape.style.yEnd = targetShape.position[1]; this.zr.modShape(linkShape.id); if (linkShape._symbolShape) { var symbolShape = linkShape._symbolShape; vec2.copy(symbolShape.position, targetShape.position); vec2.sub(v, sourceShape.position, targetShape.position); vec2.normalize(v, v); vec2.scaleAndAdd( symbolShape.position, symbolShape.position, v, targetShape.style.width / 2 + 2 ); var angle; if (v[1] < 0) { angle = 2 * Math.PI - Math.acos(-v[0]); } else { angle = Math.acos(-v[0]); } symbolShape.rotation = angle - Math.PI / 2; this.zr.modShape(symbolShape.id); } } },
_updateLinkShapes: function() { var v = vec2.create(); var edges = this._graph.edges; for (var i = 0, len = edges.length; i < len; i++) { var edge = edges[i]; var sourceShape = edge.node1.shape; var targetShape = edge.node2.shape; edge.shape.style.xStart = sourceShape.position[0]; edge.shape.style.yStart = sourceShape.position[1]; edge.shape.style.xEnd = targetShape.position[0]; edge.shape.style.yEnd = targetShape.position[1]; this.zr.modShape(edge.shape.id); if (edge.shape._symbolShape) { var symbolShape = edge.shape._symbolShape; vec2.copy(symbolShape.position, targetShape.position); vec2.sub(v, sourceShape.position, targetShape.position); vec2.normalize(v, v); vec2.scaleAndAdd( symbolShape.position, symbolShape.position, v, targetShape.style.width / 2 + 2 ); var angle; if (v[1] < 0) { angle = 2 * Math.PI - Math.acos(-v[0]); } else { angle = Math.acos(-v[0]); } symbolShape.rotation = angle - Math.PI / 2; this.zr.modShape(symbolShape.id); } } },
return function (pointSet, p0, p1, out) { // Limit the max turning angle var maxTurningAngleCos = Math.cos(this.maxTurningAngle); var maxTurningAngleTan = Math.tan(this.maxTurningAngle); vec2.sub(v10, p0, p1); vec2.normalize(v10, v10); // Simply copy the centroid point if no need to turn the angle vec2.copy(out, p0); var maxMovement = 0; for (var i = 0; i < pointSet.length; i++) { var p = pointSet[i]; vec2.sub(vTmp, p, p0); var len = vec2.len(vTmp); vec2.scale(vTmp, vTmp, 1 / len); var turningAngleCos = vec2.dot(vTmp, v10); // Turning angle is to large if (turningAngleCos < maxTurningAngleCos) { // Calculat p's project point on vector p1-p0 // and distance to the vector vec2.scaleAndAdd( project, p0, v10, len * turningAngleCos ); var distance = v2Dist(project, p); // Use the max turning angle to calculate the new meet point var d = distance / maxTurningAngleTan; vec2.scaleAndAdd(tmpOut, project, v10, -d); var movement = v2DistSquare(tmpOut, p0); if (movement > maxMovement) { maxMovement = movement; vec2.copy(out, tmpOut); } } } };
function _update(stepTime) { var len = nodePositions.length; var v12 = []; // 计算节点之间斥力 var k2 = k*k; // Reset force for (var i = 0; i < len; i++) { nodeForces[i][0] = 0; nodeForces[i][1] = 0; } for (var i = 0; i < len; i++) { for (var j = i+1; j < len; j++){ var w1 = nodeWeights[i]; var w2 = nodeWeights[j]; var p1 = nodePositions[i]; var p2 = nodePositions[j]; // 节点1到2的向量 vec2.sub(v12, p2, p1); var d = vec2.length(v12); // 距离大于500忽略斥力 if(d > 500){ continue; } if(d < 5){ d = 5; } vec2.scale(v12, v12, 1/d); var forceFactor = 1 * (w1 + w2) * k2 / d; vec2.scale(v12, v12, forceFactor); //节点1受到的力 vec2.sub(nodeForces[i], nodeForces[i], v12); //节点2受到的力 vec2.add(nodeForces[j], nodeForces[j], v12); } } // 计算节点之间引力 for (var i = 0, l = linksRawData.length; i < l; i++) { var link = linksRawData[i]; var w = linkWeights[i]; var s = link.source; var t = link.target; var p1 = nodePositions[s]; var p2 = nodePositions[t]; vec2.sub(v12, p2, p1); var d2 = vec2.lengthSquare(v12); vec2.normalize(v12, v12); var forceFactor = w * d2 / k; // 节点1受到的力 vec2.scale(v12, v12, forceFactor); vec2.add(nodeForces[s], nodeForces[s], v12); // 节点2受到的力 vec2.sub(nodeForces[t], nodeForces[t], v12); } // 到质心的向心力 for (var i = 0, l = nodesRawData.length; i < l; i++){ var p = nodePositions[i]; vec2.sub(v12, centroid, p); var d2 = vec2.lengthSquare(v12); vec2.normalize(v12, v12); // 100是可调参数 var forceFactor = d2 / 100 * centripetal; vec2.scale(v12, v12, forceFactor); vec2.add(nodeForces[i], nodeForces[i], v12); } // 计算加速度 for (var i = 0, l = nodeAccelerations.length; i < l; i++) { vec2.scale( nodeAccelerations[i], nodeForces[i], 1 / nodeMasses[i] ); } var velocity = []; var tmp = []; // 计算位置(verlet积分) for (var i = 0, l = nodePositions.length; i < l; i++) { if (nodesRawData[i].fixed) { // 拖拽同步 nodePositions[i][0] = mouseX + dx; nodePositions[i][1] = mouseY + dy; nodePrePositions[i][0] = mouseX + dx; nodePrePositions[i][1] = mouseY + dy; nodeShapes[i].position[0] = mouseX + dx; nodeShapes[i].position[1] = mouseY + dy; continue; } var p = nodePositions[i]; var __P = nodePrePositions[i]; vec2.sub(velocity, p, __P); __P[0] = p[0]; __P[1] = p[1]; vec2.add( velocity, velocity, vec2.scale(tmp, nodeAccelerations[i], stepTime) ); // Damping vec2.scale(velocity, velocity, temperature); // 防止速度太大 velocity[0] = Math.max(Math.min(velocity[0], 100), -100); velocity[1] = Math.max(Math.min(velocity[1], 100), -100); vec2.add(p, p, velocity); nodeShapes[i].position[0] = p[0] ; nodeShapes[i].position[1] = p[1] ; if(isNaN(p[0]) || isNaN(p[1])){ throw new Error('NaN'); } } }