Skip to content

Instantly share code, notes, and snippets.

@ngopal
Created September 10, 2015 21:18
Show Gist options
  • Save ngopal/bbc7ffb934112e5b809a to your computer and use it in GitHub Desktop.
Save ngopal/bbc7ffb934112e5b809a to your computer and use it in GitHub Desktop.
Working on a simply implemented force-directed layout implementation
//constants
var K_r = 60;
var L = 50;
var delta_t = 0.4;
var MAX_DISP_SQ = 20;
var width = 300;
var height = width;
var body = d3.select('body');
var svg = body.append('svg')
.attr("width", width)
.attr("height", height);
var points = [];
var Cscale = d3.scale.linear()
.domain([0,1])
.range([0,height]);
function randomNode(nodes) {
return {"id":nodes.length+1,
"x":Cscale(Math.random()),
"y":Cscale(Math.random()),
"force_x":0,
"force_y":0,
"neighbors":[
Math.floor(Math.random() * nodes.length)
]};
}
for (var i = 0; i < 2; i++) {
points.push(randomNode(points));
}
var circles = svg.selectAll("circle")
.data(points)
.enter()
.append("circle")
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.attr("r", function(d) {
return 3;
});
var iterations = 800;
while (iterations > 0) {
// ensure the loop terminates
iterations = iterations - 1;
// calculate repulsion between all pairs
for (var j = 0; j < points.length; j++) {
for (var k = j+1; k < points.length; k++) {
var dx = points[j].x - points[k].x;
var dy = points[j].y - points[k].y;
if (dx !== 0 || dy !== 0) {
var dSQ = dx*dx + dy*dy;
var dist = Math.sqrt(dSQ);
var force = K_r / dSQ;
var fx = force*dx / dist;
var fy = force*dy / dist;
points[j].force_x = points[j].force_x - fx;
points[j].force_y = points[j].force_y - fy;
points[k].force_x = points[k].force_x + fx;
points[k].force_y = points[k].force_y + fy;
}
}
}
// calculate spring forces
for (var j = 0; j < points.length; j++) {
for (var n = 0; n < points[j].neighbors.length; n++) {
if (points[j].id < points[n].id) {
var dx = points[n].x - points[j].x;
var dy = points[n].y - points[j].y;
if (dx !== 0 || dy !== 0) {
var dist = Math.sqrt(dx*dx + dy*dy);
var force = K_s * (dist - L);
var fx = force * dx / dist;
var fy = force * dy / dist;
points[j].force_x = points[j].force_x + fx;
points[j].force_y = points[j].force_y + fy;
points[n].force_x = points[n].force_x - fx;
points[n].force_y = points[n].force_y - fy;
}
}
}
}
// update x and y positions
for (var i = 0; i < points.length; i++) {
var dx = delta_t * points[i].force_x;
var dy = delta_t * points[i].force_y;
var displacementSQ = dx*dx + dy*dy;
if (displacementSQ > MAX_DISP_SQ) {
var s = Math.sqrt( MAX_DISP_SQ / displacementSQ);
dx = dx * s;
dy = dy * s;
}
points[i].x = points[i].x + dx;
points[i].y = points[i].y + dy;
}
console.log(points);
//update circles
svg.selectAll("circle")
.data(points)
.append("circle")
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.attr("r", function(d) {
return 3;
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment