Skip to content

Instantly share code, notes, and snippets.

@emeeks
Last active March 17, 2016 02:17
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 emeeks/d8b1c5f7bc975de83d99 to your computer and use it in GitHub Desktop.
Save emeeks/d8b1c5f7bc975de83d99 to your computer and use it in GitHub Desktop.
Orbital Layout 3

This is an early draft of a hierarchical orbital layout. Like other hierarchical layouts (pack, tree, treemap, etc) It takes nested data annotates it with xy values for display, in this case arranging the data into orbits, with child nodes orbiting parents and the root node at the center.

This example shows the animated layout, like d3.force, animation is initiated with orbit.start(), which adjusts coordinates and fires a "tick" event regularly. You can change the revolution speed with orbit.speed() which sets the number of degrees of shift every 10ms (defaulting to .5 degrees). Currently the speed is the same for all orbits but this should eventually support accessors to set differing speeds.

You can stop the animation with orbit.stop().

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Orbits 3</title>
<meta charset="utf-8" />
</head>
<style>
#viz, svg {
width: 500px;
height: 500px;
}
</style>
<script>
function makeViz() {
nodes = [];
///All of this is just to fake some nested data
randomCountry = d3.scale.quantize().domain([0,1]).range(["USA", "FRA", "MEX", "GBR", "CAN"])
randomStatus = d3.scale.quantize().domain([0,1]).range(["amazing","okay", "cool", "boss", "dope", "lame"])
randomRole = d3.scale.quantize().domain([0,1]).range(["capital","metropole", "port"])
trafficCategories = ["high","medium","low","fargo"];
quantizeTraffic = d3.scale.quantize().domain([0,500]).range(trafficCategories);
//200 random things with random categorical attributes
nodes = d3.range(200).map(function(d,i) {return {i: i} })
nodes.forEach(function (node) {
node.country = randomCountry(Math.random());
node.status = randomStatus(Math.random());
node.traffic = parseInt(Math.random() * 500);
node.trafficRank = quantizeTraffic(node.traffic);
node.role = randomRole(Math.random())
})
var nest = d3.nest()
.key(function(d) {return d.country})
.key(function(d) {return d.trafficRank})
.key(function(d) {return d.status})
.key(function(d) {return d.role})
var awesomeFakeNestedData = nest.entries(nodes);
//If you already have some nested data, just send it to drawOrbit
drawOrbit(awesomeFakeNestedData)
}
function drawOrbit(_data) {
//down with category20a()!!
colors = d3.scale.category20b();
orbit = d3.layout.orbit().size([500,500]).nodes(_data);
d3.select("svg").selectAll("circle").data(orbit.nodes())
.enter()
.append("circle")
.attr("r", function(d) {return Math.max(1, 5 - d.depth)})
.attr("cx", function(d) {return d.x})
.attr("cy", function(d) {return d.y})
.style("fill", function(d) {return colors(d.depth)})
d3.select("svg").selectAll("circle.orbits")
.data(orbit.orbitalRings())
.enter()
.insert("circle", "circle")
.attr("r", function(d) {return d.r})
.attr("cx", function(d) {return d.x})
.attr("cy", function(d) {return d.y})
.style("fill", "none")
.style("stroke", "black")
.style("stroke-width", "1px")
.style("stroke-opacity", .15)
orbit.on("tick", function() {
d3.selectAll("circle")
.attr("cx", function(d) {return d.x})
.attr("cy", function(d) {return d.y})
});
orbit.start();
}
</script>
<body onload="makeViz()">
<div id="viz"><svg></svg></div>
<footer>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script src="http://bl.ocks.org/emeeks/raw/531f107a0ff6eff5d543/d3.layout.orbit.js" charset="utf-8" type="text/javascript"></script>
</footer>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment