Skip to content

Commit 8d4444a

Browse files
committed
Add base code for Chapter 22 to git
1 parent 210c847 commit 8d4444a

File tree

1 file changed

+156
-0
lines changed

1 file changed

+156
-0
lines changed

code/chapter/22_fast.js

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
var GraphNode = class GraphNode {
2+
constructor() {
3+
this.pos = new Vec(Math.random() * 1000,
4+
Math.random() * 1000);
5+
this.edges = [];
6+
}
7+
connect(other) {
8+
this.edges.push(other);
9+
other.edges.push(this);
10+
}
11+
hasEdge(other) {
12+
return this.edges.includes(other);
13+
}
14+
}
15+
16+
function treeGraph(depth, branches) {
17+
let graph = [new GraphNode()];
18+
if (depth > 1) {
19+
for (let i = 0; i < branches; i++) {
20+
let subGraph = treeGraph(depth - 1, branches);
21+
graph[0].connect(subGraph[0]);
22+
graph = graph.concat(subGraph);
23+
}
24+
}
25+
return graph;
26+
}
27+
28+
var springLength = 40;
29+
var springStrength = 0.1;
30+
31+
var repulsionStrength = 1500;
32+
33+
function forceDirected_simple(graph) {
34+
for (let node of graph) {
35+
for (let other of graph) {
36+
if (other == node) continue;
37+
let apart = other.pos.minus(node.pos);
38+
let distance = Math.max(1, apart.length);
39+
let forceSize = -repulsionStrength / (distance * distance);
40+
if (node.hasEdge(other)) {
41+
forceSize += (distance - springLength) * springStrength;
42+
}
43+
let normalized = apart.times(1 / distance);
44+
node.pos = node.pos.plus(normalized.times(forceSize));
45+
}
46+
}
47+
}
48+
49+
function runLayout(implementation, graph) {
50+
function run(steps, time) {
51+
let startTime = Date.now();
52+
for (let i = 0; i < 100; i++) {
53+
implementation(graph);
54+
}
55+
time += Date.now() - startTime;
56+
drawGraph(graph);
57+
58+
if (steps == 0) console.log(time);
59+
else requestAnimationFrame(() => run(steps - 100, time));
60+
}
61+
run(4000, 0);
62+
}
63+
64+
function forceDirected_noRepeat(graph) {
65+
for (let i = 0; i < graph.length; i++) {
66+
let node = graph[i];
67+
for (let j = i + 1; j < graph.length; j++) {
68+
let other = graph[j];
69+
let apart = other.pos.minus(node.pos);
70+
let distance = Math.max(1, apart.length);
71+
let forceSize = -repulsionStrength / (distance * distance);
72+
if (node.hasEdge(other)) {
73+
forceSize += (distance - springLength) * springStrength;
74+
}
75+
let applied = apart.times(forceSize / distance);
76+
node.pos = node.pos.plus(applied);
77+
other.pos = other.pos.minus(applied);
78+
}
79+
}
80+
}
81+
82+
var skipDistance = 175;
83+
84+
function forceDirected_skip(graph) {
85+
for (let i = 0; i < graph.length; i++) {
86+
let node = graph[i];
87+
for (let j = i + 1; j < graph.length; j++) {
88+
let other = graph[j];
89+
let apart = other.pos.minus(node.pos);
90+
let distance = Math.max(1, apart.length);
91+
let hasEdge = node.hasEdge(other);
92+
if (!hasEdge && distance > skipDistance) continue;
93+
let forceSize = -repulsionStrength / (distance * distance);
94+
if (hasEdge) {
95+
forceSize += (distance - springLength) * springStrength;
96+
}
97+
let applied = apart.times(forceSize / distance);
98+
node.pos = node.pos.plus(applied);
99+
other.pos = other.pos.minus(applied);
100+
}
101+
}
102+
}
103+
104+
GraphNode.prototype.hasEdgeFast = function(other) {
105+
for (let i = 0; i < this.edges.length; i++) {
106+
if (this.edges[i] === other) return true;
107+
}
108+
return false;
109+
};
110+
111+
function forceDirected_hasEdgeFast(graph) {
112+
for (let i = 0; i < graph.length; i++) {
113+
let node = graph[i];
114+
for (let j = i + 1; j < graph.length; j++) {
115+
let other = graph[j];
116+
let apart = other.pos.minus(node.pos);
117+
let distance = Math.max(1, apart.length);
118+
let hasEdge = node.hasEdgeFast(other);
119+
if (!hasEdge && distance > skipDistance) continue;
120+
let forceSize = -repulsionStrength / (distance * distance);
121+
if (hasEdge) {
122+
forceSize += (distance - springLength) * springStrength;
123+
}
124+
let applied = apart.times(forceSize / distance);
125+
node.pos = node.pos.plus(applied);
126+
other.pos = other.pos.minus(applied);
127+
}
128+
}
129+
}
130+
131+
function forceDirected_noVector(graph) {
132+
for (let i = 0; i < graph.length; i++) {
133+
let node = graph[i];
134+
for (let j = i + 1; j < graph.length; j++) {
135+
let other = graph[j];
136+
let apartX = other.pos.x - node.pos.x;
137+
let apartY = other.pos.y - node.pos.y;
138+
let distance = Math.max(1, Math.sqrt(apartX * apartX + apartY * apartY));
139+
let hasEdge = node.hasEdgeFast(other);
140+
if (!hasEdge && distance > skipDistance) continue;
141+
let forceSize = -repulsionStrength / (distance * distance);
142+
if (hasEdge) {
143+
forceSize += (distance - springLength) * springStrength;
144+
}
145+
let forceX = apartX * forceSize / distance;
146+
let forceY = apartY * forceSize / distance;
147+
node.pos.x += forceX; node.pos.y += forceY;
148+
other.pos.x -= forceX; other.pos.y -= forceY;
149+
}
150+
}
151+
}
152+
153+
var mangledGraph = treeGraph(4, 4);
154+
for (let node of mangledGraph) {
155+
node[`p${Math.floor(Math.random() * 999)}`] = true;
156+
}

0 commit comments

Comments
 (0)