Skip to content

Commit

Permalink
Restructure force example.
Browse files Browse the repository at this point in the history
  • Loading branch information
mbostock committed Feb 27, 2011
1 parent 6363881 commit 7b1df15
Show file tree
Hide file tree
Showing 5 changed files with 219 additions and 227 deletions.
2 changes: 1 addition & 1 deletion examples/force/cluster.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<title>Clustered Network</title>
<script type="text/javascript" src="../../d3.js"></script>
<script type="text/javascript" src="../../d3.geom.js"></script>
<script type="text/javascript" src="force.js"></script>
<script type="text/javascript" src="layout.js"></script>
<style type="text/css">
svg {
border: 1px solid #ccc;
Expand Down
9 changes: 9 additions & 0 deletions examples/force/force.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
circle.node {
fill: lightsteelblue;
stroke: steelblue;
stroke-width: 1.5px;
}

line.link {
stroke: #333;
}
73 changes: 4 additions & 69 deletions examples/force/force.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,76 +3,11 @@
<head>
<title>Force-Directed Layout</title>
<script type="text/javascript" src="../../d3.js"></script>
<script type="text/javascript" src="force.js"></script>
<style type="text/css">

body {
font: 10px sans-serif;
}

circle.node {
fill: lightsteelblue;
stroke: steelblue;
stroke-width: 1.5px;
}

line.link {
stroke: #333;
}

</style>
<script type="text/javascript" src="layout.js"></script>
<link type="text/css" rel="stylesheet" href="force.css"/>
</head>
<body>
<script type="text/javascript">

var w = 960,
h = 500;

var vis = d3.select("body")
.append("svg:svg")
.attr("width", w)
.attr("height", h);

d3.json("miserables.json", function(json) {
var force = layout_force()
.nodes(json.nodes)
.links(json.links)
.size({x: w, y: h})
.start();

var link = vis.selectAll("line.link")
.data(json.links)
.enter().append("svg:line")
.attr("class", "link")
.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });

var node = vis.selectAll("circle.node")
.data(json.nodes)
.enter().append("svg:circle")
.attr("class", "node")
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.attr("r", 4.5);

vis.attr("opacity", 0)
.transition()
.duration(1000)
.attr("opacity", 1);

force.on("tick", function() {
link.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });

node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});
});

</script>
<div id="chart"></div>
<script type="text/javascript" src="force.js"></script>
</body>
</html>
204 changes: 47 additions & 157 deletions examples/force/force.js
Original file line number Diff line number Diff line change
@@ -1,157 +1,47 @@
function layout_force() {
var force = {},
event = d3.dispatch("tick"),
size = {x: 1, y: 1},
alpha = .1,
nodeDistance = 60,
linkDistance = 30,
interval,
nodes,
links;

// TODO
// slow the interval as the graph stabilizes
// allow the nodes to be dragged interactively

function tick() {
var n = nodes.length,
m = links.length,
i, // current index
j, // current index
o, // current link
s, // current source
t, // current target
l, // current distance
x,
y;

// repel nodes
for (i = 0; i < n; ++i) {
s = nodes[i];
for (j = i + 1; j < n; ++j) {
t = nodes[j];
x = t.x - s.x;
y = t.y - s.y;
l = Math.sqrt(x * x + y * y);
if (l < nodeDistance) {
l = alpha * (l - nodeDistance) / l;
x *= l;
y *= l;
if (s.fixed) {
if (t.fixed) continue;
t.x -= x;
t.y -= y;
} else if (t.fixed) {
s.x += x;
s.y += y;
} else {
s.x += x;
s.y += y;
t.x -= x;
t.y -= y;
}
}
}
}

// position constraint for links
for (i = 0; i < m; ++i) {
o = links[i];
s = o.source;
t = o.target;
x = t.x - s.x;
y = t.y - s.y;
l = Math.sqrt(x * x + y * y);
if (l <= 0) l = 0.01;
l = alpha * (l - linkDistance) / l;
x *= l;
y *= l;
if (s.fixed) {
if (t.fixed) continue;
t.x -= x;
t.y -= y;
} else if (t.fixed) {
s.x += x;
s.y += y;
} else {
s.x += x;
s.y += y;
t.x -= x;
t.y -= y;
}
}

event.tick.dispatch({type: "tick"});
}

force.on = function(type, listener) {
event[type].add(listener);
return force;
};

force.nodes = function(x) {
if (!arguments.length) return nodes;
nodes = x;
return force;
};

force.links = function(x) {
if (!arguments.length) return links;
links = x;
return force;
};

force.size = function(x) {
if (!arguments.length) return size;
size = x;
return force;
};

force.nodeDistance = function(d) {
if (!arguments.length) return nodeDistance;
nodeDistance = d;
return force;
};

force.linkDistance = function(d) {
if (!arguments.length) return linkDistance;
linkDistance = d;
return force;
};

force.start = function() {
var i,
n = nodes.length,
m = links.length,
w = size.x,
h = size.y,
o;
for (i = 0; i < n; ++i) {
o = nodes[i];
o.x = o.x || Math.random() * w;
o.y = o.y || Math.random() * h;
o.fixed = 0;
}
for (i = 0; i < m; ++i) {
o = links[i];
o.source = nodes[o.source];
o.target = nodes[o.target];
}
if (interval) clearInterval(interval);
interval = setInterval(tick, 24);
return force;
};

force.resume = function() {
if (interval) clearInterval(interval);
interval = setInterval(tick, 24);
return force;
};

force.stop = function() {
interval = clearInterval(interval);
return force;
};

return force;
}
var w = 960,
h = 500;

var vis = d3.select("#chart")
.append("svg:svg")
.attr("width", w)
.attr("height", h);

d3.json("miserables.json", function(json) {
var force = layout_force()
.nodes(json.nodes)
.links(json.links)
.size({x: w, y: h})
.start();

var link = vis.selectAll("line.link")
.data(json.links)
.enter().append("svg:line")
.attr("class", "link")
.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });

var node = vis.selectAll("circle.node")
.data(json.nodes)
.enter().append("svg:circle")
.attr("class", "node")
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.attr("r", 4.5);

vis.attr("opacity", 0)
.transition()
.duration(1000)
.attr("opacity", 1);

force.on("tick", function() {
link.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });

node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});
});
Loading

0 comments on commit 7b1df15

Please sign in to comment.