Skip to content

Commit

Permalink
Add per-node gravity: force.gravityCenter.
Browse files Browse the repository at this point in the history
This allows the Dorling/Demers cartograms to be slightly closer to the real
geography.

Also, fix the Dorling collision detection as self-collisions were previously
being detected.  Thanks, Mike!

Lastly, I've removed the variable per-link distance as this is no longer needed.
  • Loading branch information
jasondavies committed Jul 8, 2011
1 parent 287b2ea commit ca88707
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 23 deletions.
12 changes: 12 additions & 0 deletions d3.layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ d3.layout.force = function() {
linkStrength = d3_layout_forceLinkStrength,
charge = -30,
gravity = .1,
gravityCenter = null,
theta = .8,
interval,
nodes = [],
Expand Down Expand Up @@ -282,6 +283,11 @@ d3.layout.force = function() {
y = size[1] / 2;
i = -1; while (++i < n) {
o = nodes[i];
if (gravityCenter != null) {
var gxy = gravityCenter.call(this, o, i);
x = gxy.x;
y = gxy.y;
}
o.x += (x - o.x) * kg;
o.y += (y - o.y) * kg;
}
Expand Down Expand Up @@ -369,6 +375,12 @@ d3.layout.force = function() {
return force;
};

force.gravityCenter = function(x) {
if (!arguments.length) return gravityCenter;
gravityCenter = x == null ? null : d3.functor(x);
return force;
};

force.theta = function(x) {
if (!arguments.length) return theta;
theta = x;
Expand Down
2 changes: 1 addition & 1 deletion d3.layout.min.js

Large diffs are not rendered by default.

34 changes: 24 additions & 10 deletions examples/cartogram/demers.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ var color = d3.scale.linear()
.range(["#aad", "#556"]);

var force = d3.layout.force()
.gravity(0)
.charge(0)
.distance(function(l) {
return l.length;
.gravity(0)
.gravityCenter(function(node) {
return node.gravity;
})
.size([960, 500]);

Expand All @@ -26,24 +26,38 @@ d3.json("../data/us-state-centroids.json", function(states) {
links = [],
nodes = states.features.map(function(d) {
var xy = project(d.geometry.coordinates);
return idToNode[d.id] = {x: xy[0], y: xy[1], r: Math.sqrt(data[+d.id] * 5000), value: data[+d.id]};
return idToNode[d.id] = {
x: xy[0],
y: xy[1],
gravity: {x: xy[0], y: xy[1]},
r: Math.sqrt(data[+d.id] * 5000),
value: data[+d.id]
};
});

force
.nodes(nodes)
.links(links)
.start()
.on("tick", function(e) {
var k = .1 * e.alpha;
var k = e.alpha;
nodes.forEach(function(a, i) {
nodes.forEach(function(b, i) {
nodes.slice(i + 1).forEach(function(b, i) {
// Check for collision
var dx = a.x - b.x,
dy = a.y - b.y,
dr = a.r + b.r;
if (dx * dx < dr * dr && dy * dy < dr * dr) {
a.x += dx * k;
a.y += dy * k;
d = a.r + b.r,
lx = Math.abs(dx),
ly = Math.abs(dy);
if (lx < d && ly < d) {
lx = (lx - d) / lx * k;
ly = (ly - d) / ly * k;
dx *= lx;
dy *= ly;
a.x -= dx;
a.y -= dy;
b.x += dx;
b.y += dy;
}
});
});
Expand Down
40 changes: 28 additions & 12 deletions examples/cartogram/dorling.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,39 +11,55 @@ var color = d3.scale.linear()
.range(["#aad", "#556"]);

var force = d3.layout.force()
.gravity(0)
.charge(0)
.distance(function(l) {
return l.length;
.gravity(0)
.gravityCenter(function(node) {
return node.gravity;
})
.size([960, 500]);

var svg = d3.select("#chart").append("svg:svg");
var svg = d3.select("#chart").append("svg:svg")
.attr("width", 960 + 100)
.attr("height", 500 + 100)
.append("svg:g")
.attr("transform", "translate(50,50)");

d3.json("../data/us-state-centroids.json", function(states) {
var project = d3.geo.albersUsa(),
idToNode = {},
links = [],
nodes = states.features.map(function(d) {
var xy = project(d.geometry.coordinates);
return idToNode[d.id] = {x: xy[0], y: xy[1], r: Math.sqrt(data[+d.id] * 5000), value: data[+d.id]};
return idToNode[d.id] = {
x: xy[0],
y: xy[1],
gravity: {x: xy[0], y: xy[1]},
r: Math.sqrt(data[+d.id] * 5000),
value: data[+d.id]
};
});

force
.nodes(nodes)
.links(links)
.start()
.on("tick", function(e) {
var k = .1 * e.alpha;
var k = e.alpha;
nodes.forEach(function(a, i) {
nodes.forEach(function(b, i) {
// Check for collision
nodes.slice(i + 1).forEach(function(b, i) {
// Check for collisions.
var dx = a.x - b.x,
dy = a.y - b.y,
dr = a.r + b.r;
if (dx * dx + dy * dy < dr * dr) {
a.x += dx * k;
a.y += dy * k;
l = Math.sqrt(dx * dx + dy * dy),
d = a.r + b.r;
if (l < d) {
l = (l - d) / l * k;
dx *= l;
dy *= l;
a.x -= dx;
a.y -= dy;
b.x += dx;
b.y += dy;
}
});
});
Expand Down
12 changes: 12 additions & 0 deletions src/layout/force.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ d3.layout.force = function() {
linkStrength = d3_layout_forceLinkStrength,
charge = -30,
gravity = .1,
gravityCenter = null,
theta = .8,
interval,
nodes = [],
Expand Down Expand Up @@ -76,6 +77,11 @@ d3.layout.force = function() {
y = size[1] / 2;
i = -1; while (++i < n) {
o = nodes[i];
if (gravityCenter != null) {
var gxy = gravityCenter.call(this, o, i);
x = gxy.x;
y = gxy.y;
}
o.x += (x - o.x) * kg;
o.y += (y - o.y) * kg;
}
Expand Down Expand Up @@ -163,6 +169,12 @@ d3.layout.force = function() {
return force;
};

force.gravityCenter = function(x) {
if (!arguments.length) return gravityCenter;
gravityCenter = x == null ? null : d3.functor(x);
return force;
};

force.theta = function(x) {
if (!arguments.length) return theta;
theta = x;
Expand Down

0 comments on commit ca88707

Please sign in to comment.