Skip to content

Instantly share code, notes, and snippets.

@emeeks
Last active September 14, 2015 21:38
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save emeeks/10014250 to your computer and use it in GitHub Desktop.
Save emeeks/10014250 to your computer and use it in GitHub Desktop.
Topojson Import into Force-Directed II

An update that uses a mercator projection to place each country at its centroid so you can understand how Europe is connected to South America.

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>topojson import into force directed network II</title>
<meta charset="utf-8" />
</head>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>
<style>
</style>
<body onload="forceDirected();">
<div id="controls">
</div>
<div id="vizcontainer">
<svg style="width:500px;height:500px;border:1px lightgray solid;" />
</div>
<footer>
<script>
function forceDirected() {
d3.json("/emeeks/raw/9980626/world.json", createForceLayout)
function createForceLayout(world) {
var nodes = topojson.feature(world, world.objects.countries).features;
var neighbors = topojson.neighbors(world.objects.countries.geometries);
var edges = [];
console.log(nodes);
var nodeHash = {};
for (x in nodes) {
nodeHash[x] = nodes[x];
}
for (x in neighbors) {
for (y in neighbors[x]) {
var newEdge = {source: nodeHash[x], target: nodeHash[neighbors[x][y]]};
edges.push(newEdge);
}
}
projection = d3.geo.mercator()
.scale(80)
.translate([250, 250]);
geoPath = d3.geo.path().projection(projection);
force = d3.layout.force()
.charge(-20)
.gravity(.05)
.linkDistance(10)
.size([500,500]).nodes(nodes)
.links(edges).on("tick", forceTick);
d3.select("svg").selectAll("line.link").data(edges).enter()
.append("line")
.attr("class", "link")
.style("stroke", "black")
.style("opacity", .5)
.style("stroke-width", 1);
var nodeEnter = d3.select("svg").selectAll("g.node").data(nodes).enter()
.append("g")
.attr("class", "node")
.call(force.drag())
.on("click", fixNode)
.each(function(d) {
var c = geoPath.centroid(d);
d.x = c[0];
d.px = c[0];
d.y = c[1];
d.py = c[1];
});
//You need to start the force to calculate degree centrality
forceTick();
force.start();
force.stop();
sizeByDegree();
function fixNode(d) {
d3.select(this).select("circle").style("stroke-width", 4);
d.fixed = true;
}
nodeEnter.append("circle")
.attr("r", 1)
.style("fill", "lightgray")
.style("stroke", "black")
.style("stroke-width", "1px");
nodeEnter.append("text")
.style("text-anchor", "middle")
.attr("y", 15)
// The topojson data file I'm using doesn't have names...
// .text(function(d) {return d.properites.name})
function forceTick() {
d3.selectAll("line.link")
.attr("x1", function (d) {return d.source.x})
.attr("x2", function (d) {return d.target.x})
.attr("y1", function (d) {return d.source.y})
.attr("y2", function (d) {return d.target.y});
d3.selectAll("g.node")
.attr("transform", function (d) {return "translate("+d.x+","+d.y+")"})
}
function sizeByDegree() {
force.stop();
d3.selectAll("circle")
.attr("r", function(d) {return 1 + (d.weight * .2)})
}
d3.select("#controls").append("button").on("click", sizeByDegree).html("Degree Size");
d3.select("#controls").append("button").on("click", function() {force.start()}).html("Force-directed");
}
}
</script>
</footer>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment