Skip to content

Instantly share code, notes, and snippets.

@thatismatt
Forked from mbostock/.block
Last active June 15, 2016 16:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thatismatt/e855ccb68ae8fc4df75d04c3d02a0865 to your computer and use it in GitHub Desktop.
Save thatismatt/e855ccb68ae8fc4df75d04c3d02a0865 to your computer and use it in GitHub Desktop.
Force-Directed Tree
license: gpl-3.0
height: 400

An example to illustrate the utility of a simulation.isFixed(node) function. See comments for locations where this function would be useful.

<!DOCTYPE html>
<meta charset="utf-8">
<canvas width="960" height="400"></canvas>
<script src="https://d3js.org/d3.v4.0.0-alpha.40.min.js"></script>
<script>
var nodes = d3.range(10).map(function(i) {
return {
index: i
};
});
var links = d3.range(nodes.length - 1).map(function(i) {
return {
source: Math.floor(Math.sqrt(i)),
target: i + 1
};
});
var simulation = d3.forceSimulation(nodes)
.force("charge", d3.forceManyBody())
.force("link", d3.forceLink(links).distance(20).strength(1))
.force("x", d3.forceX())
.force("y", d3.forceY())
.on("tick", ticked);
var fixed = [{ id: 0, x: -100, y: -100 },
{ id: 9, x: -200, y: 0 }];
fixed.forEach(function(f) {
simulation.fix(nodes[f.id], f.x, f.y);
});
var canvas = document.querySelector("canvas"),
context = canvas.getContext("2d"),
width = canvas.width,
height = canvas.height;
d3.select(canvas)
.call(d3.drag()
.container(canvas)
.subject(dragsubject)
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
function ticked() {
context.clearRect(0, 0, width, height);
context.save();
context.translate(width / 2, height / 2);
context.beginPath();
links.forEach(drawLink);
context.strokeStyle = "#aaa";
context.stroke();
nodes.forEach(drawNode);
context.restore();
}
function dragsubject() {
return simulation.find(d3.event.x - width / 2, d3.event.y - height / 2);
}
function dragstarted() {
if (!d3.event.active) simulation.alphaTarget(0.3).restart()
simulation.fix(d3.event.subject);
}
function dragged() {
simulation.fix(d3.event.subject, d3.event.x, d3.event.y);
}
function dragended() {
if (!d3.event.active) simulation.alphaTarget(0);
// simulation.isFixed(d) would be nice here
var wasFixed = fixed.filter(function(f) { return d3.event.subject.index == f.id; }).length;
if (!wasFixed) {
simulation.unfix(d3.event.subject);
}
}
function drawLink(d) {
context.moveTo(d.source.x, d.source.y);
context.lineTo(d.target.x, d.target.y);
}
function drawNode(d) {
context.moveTo(d.x + 3, d.y);
context.beginPath();
context.arc(d.x, d.y, 5, 0, 2 * Math.PI);
context.fill();
context.lineWidth = 4;
// simulation.isFixed(d) would be nice here too
var isFixed = fixed.filter(function(f) { return d.index == f.id; }).length;
context.strokeStyle = isFixed ? "#099" : "#999";
context.stroke();
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment