1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
| class Node { constructor() { this.x = null; this.y = null; } }
class Edge { constructor(source, target) { this.source = source; this.target = target; } }
const CANVAS_WIDTH = 1000; const CANVAS_HEIGHT = 1000;
class ForceDirected { constructor(n) { this.mNodeList = new Array(n).fill(0).map(new Node()); this.mEdgeList = [] this.mDxMap = []; this.mDyMap = []; this.ejectFactor = 6; this.condenseFactor = 3; for (let i = 0; i < n; i++) { const edgeCount = Math.random() * 8 + 1; for (let j = 0; j < edgeCount; j++) { let targetId = Math.floor(Math.random() * n); let edge = new Edge(i, targetId); this.mEdgeList.push(edge); } }
this.coefficient = Math.sqrt(CANVAS_WIDTH * CANVAS_HEIGHT / mNodeList.length);
const initialSize = 40.0; const initialX = CANVAS_WIDTH * .5; const initialY = CANVAS_HEIGHT * .5; for (let i in this.mNodeList) { this.mNodeList[i].x = initialX + initialSize * (Math.random() - .5); this.mNodeList[i].y = initialY + initialSize * (Math.random() - .5); } }
calculateRepulsive() { let distX, distY, dist; for (let i = 0; i < this.mNodeList.length; i++) { for (let j = 0; j < this.mNodeList.length; j++) { distX = this.mNodeList[i].x - this.mNodeList[j].x; distY = this.mNodeList[i].y - this.mNodeList[j].y; dist = Math.sqrt(distX * distX + distY * distY); if (dist > 0 && dist < 250) { this.mDxMap[i] = distX * this.ejectFactor / Math.pow(dist, 2); this.mDyMap[i] = distY * this.ejectFactor / Math.pow(dist, 2); } } } }
calculateTraction() { let startNode, endNode; for (let e = 0; e < mEdgeList.length; e++) { const eStartID = mEdgeList[e].source; const eEndID = mEdgeList[e].target; startNode = this.mNodeList[eStartID]; endNode = this.mNodeList[eEndID]; let distX, distY, dist; distX = startNode.x - endNode.x; distY = startNode.y - endNode.y; dist = Math.sqrt(distX * distX + distY * distY); this.mDxMap[eStartID] = this.mDxMap[eStartID] - distX * dist / k * this.condenseFactor; this.mDyMap[eStartID] = this.mDyMap[eStartID] - distY * dist / k * this.condenseFactor; this.mDxMap[eEndID] = this.mDxMap[eEndID] + distX * dist / k * this.condenseFactor; this.mDyMap[eEndID] = this.mDyMap[eEndID] + distY * dist / k * this.condenseFactor; } }
updateCoordinates() { let maxt = 4, maxty = 3; for (let v = 0; v < mNodeList.length; v++) { let node = mNodeList[v]; let dx = Math.floor(mDxMap[v]); let dy = Math.floor(mDyMap[v]); if (dx < -maxt) dx = -maxt; if (dx > maxt) dx = maxt; if (dy < -maxty) dy = -maxty; if (dy > maxty) dy = maxty; node.x = node.x + dx >= CANVAS_WIDTH || node.x + dx <= 0 ? node.x - dx : node.x + dx; node.y = node.y + dy >= CANVAS_HEIGHT || node.y + dy <= 0 ? node.y - dy : node.y + dy; } }
update(iterateCount) { for (let i = 0; i < iterateCount; i++) { calculateRepulsive(); calculateTraction(); updateCoordinates(); } } }
|