Skip to content

Instantly share code, notes, and snippets.

@rsbowman
Last active February 22, 2016 03:07
Show Gist options
  • Save rsbowman/5fdff29f66ddc4c4df69 to your computer and use it in GitHub Desktop.
Save rsbowman/5fdff29f66ddc4c4df69 to your computer and use it in GitHub Desktop.
Rearrange force directed layout disks
license: bsd-3-clause

Nodes ordered in a line using force direced layout. Each node has a spot it wants to be in, but by dragging the circles you can rearrange the order.

<!DOCTYPE html>
<meta charset="utf-8">
<style>
.node {
stroke-width: 3px;
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var width = 960,
height = 500;
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var n_nodes = 8,
node_radius = 20,
node_y = height / 2,
padding = 50;
var x = d3.scale.linear()
.domain([0, n_nodes - 1])
.range([padding, width - padding]);
var delta_x = x(1) - x(0);
var color = d3.scale.category10();
var node_order = d3.range(n_nodes),
node_data = node_order.map(function(n) {
return {id: n, well: x(n), x: x(n), y: node_y};
});
var order_force = d3.layout.force()
.nodes(node_data)
.links([])
.charge(-1000)
.gravity(0)
.size([width, height])
.friction(0.2)
.on("tick", order_tick);
var node_drag = d3.behavior.drag()
.on("dragstart", dragstart)
.on("drag", dragmove)
.on("dragend", dragend);
var nodes = svg.selectAll(".node")
.data(node_data)
.enter()
.append("circle")
.attr("class", function(d) { return "node node-" + d.id; })
.attr("cx", function(d) { return x(d.id); })
.attr("cy", node_y)
.attr("r", node_radius)
.style("fill", function(d) { return color(d.id); })
.style("stroke", function(d) { return d3.rgb(color(d.id)).darker(1.5); })
.call(node_drag);
order_force.start()
order_tick();
function order_tick() {
nodes.each(function(d) { d.well = x(node_order[d.id]); });
nodes.each(gravity(0.5 * order_force.alpha()))
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
}
function gravity(alpha) {
return function(d) {
if (!d.fixed) {
d.y += (node_y - d.y) * alpha;
d.x += (d.well - d.x) * alpha;
}
};
}
function dragstart(d) {
d.fixed = true;
}
function dragmove(d) {
d.px += d3.event.dx;
d.py += d3.event.dy;
d.x += d3.event.dx;
d.y += d3.event.dy;
update_order(d);
order_tick();
order_force.resume();
}
function dragend(d) {
d.fixed = false;
update_order(d);
order_tick();
}
function update_order(d) {
var new_idx = Math.round((d.x - x(0)) / delta_x),
old_idx = node_order[d.id],
old_idx_idx = node_order.indexOf(old_idx);
if (old_idx < new_idx) {
for (var i = 0; i < node_order.length; ++i) {
if (old_idx + 1 <= node_order[i] && node_order[i] <= new_idx)
node_order[i] += -1;
}
node_order[old_idx_idx] = new_idx;
} else if (new_idx < old_idx) {
for (var i = 0; i < node_order.length; ++i) {
if (new_idx <= node_order[i] && node_order[i] <= old_idx - 1)
node_order[i] += 1;
}
node_order[old_idx_idx] = new_idx;
}
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment