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.
Last active
February 22, 2016 03:07
-
-
Save rsbowman/5fdff29f66ddc4c4df69 to your computer and use it in GitHub Desktop.
Rearrange force directed layout disks
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
license: bsd-3-clause |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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