Skip to content

Instantly share code, notes, and snippets.

@coderextreme
Last active January 11, 2016 01:49
Show Gist options
  • Save coderextreme/1333c72dd1301f60be24 to your computer and use it in GitHub Desktop.
Save coderextreme/1333c72dd1301f60be24 to your computer and use it in GitHub Desktop.
Responsive Double Hierarchy DAG cluster

Built with blockbuilder.org.
Click on Open in a new window to see responsiveness.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Double Hierarchy DAG</title>
<style>
body {
width:100%;
height:100%;
}
</style>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
</head>
<body>
<div style="width:100%;height:100%"></div>
<script type="text/javascript">
function setup(json) {
var domain = [];
var range = [];
var i = 0;
for (ch in json.children) {
child = json.children[ch];
domain.push(child.name);
range.push(i);
for (gc in child.children) {
grandchild = child.children[gc];
domain.push(grandchild.name);
range.push(i);
}
i++;
}
var map = d3.scale.ordinal()
.domain(domain)
.range(range);
d3.select(window)
.on("resize", function() {
/*
width = window.innerWidth;
height = window.innerHeight;
d3.select("svg")
.attr("width", width)
.attr("height", height);
*/
d3.select("svg").remove();
redraw(json, map);
})
redraw(json, map);
}
function getLinks(json, count) {
var map = {};
var other = [];
json.forEach(function(d) {
map[d.name] = d;
count[d.name] = 0;
});
json.forEach(function(d) {
if (d.other) d.other.forEach(function(o) {
count[o.name]++;
other.push({source: map[d.name], target: map[o.name]});
});
// once the big circles have been plotted, move y inward
if (d.depth == 2) {
d.y /= 1.15;
}
});
json.forEach(function(d) {
if (d.depth == 2 && count[d.name] > 1) {
d.x -= count[d.name] + 0.5;
}
});
return other;
}
function redraw(json, map) {
var width = $("div").width() || Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
var height = $("div").height() || Math.max(document.documentElement.clientHeight, window.innerHeight || 0)
var min = width < height ? width : height;
var rx = width/2;
var ry = height/2;
var rm = min/2;
var color = d3.scale.category20();
var pi = Math.PI;
var bundle = d3.layout.bundle();
var line = d3.svg.line.radial()
.interpolate("bundle")
.tension(0.50)
.radius(function(d) { return d.y; })
.angle(function(d) { return d.x / 180 * pi; });
var arc = d3.svg.arc()
.innerRadius(0)
.outerRadius(function(d,i) {return min/7; })
.startAngle(function(d,i) { return 0;})
.endAngle(function(d) { return 2*pi;});
var svg = d3.select("div")
.append("svg:svg")
.attr("viewBox", "0 0 " + width + " " + height);
svg.append('defs')
.append('path')
.attr("d", arc)
.attr("id", "curvedPath");
var center = svg.append("svg:g")
.attr("transform", "translate(" + rx + "," + ry + ")");
var cluster = d3.layout.cluster()
.separation(function(d) { return 1;})
.size([360, min/4])
.sort(null);
var nodes = cluster.nodes(json);
var node = center.selectAll("g.node")
.data(nodes)
.enter().append("svg:g")
node.append("svg:text")
.attr("text-anchor", function(d) { return "middle"; })
.append('textPath')
.attr("startOffset", function(d) {
var percent = 100*d.x/360;
return (percent >= 50 ? percent - 50 : percent + 50) +"%";
})
.attr("xlink:href", function(d) { return (d.depth == 1 ? "#curvedPath" : null); })
.attr("fill", function(d, i) { return color(map(d.name)); } )
.style("font-size", min/45 + "px")
.text(function(d) { return (d.depth == 1 ? d.name : ""); });
var g = node.append("svg:g")
.attr("class", "node")
.attr("transform", function(d) { return "rotate(" + (d.x - 90) + ") translate(" + d.y + ")"; });
g.append("svg:circle")
.attr("r", function(d) { return d.size * min / 900; })
.attr("fill", function (d,i) { return color(map(d.name));});
g.append("svg:text")
.attr("dx", function(d) { return d.x < 180 ? 18 : -18; })
.attr("dy", ".31em")
.attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
.attr("transform", function(d) { return d.x < 180 ? "" : "rotate(180)"; })
.style("font-size", min/45 + "px")
.text(function(d) { return (d.depth == 2 ? d.name : ""); })
// minor links
var count = {};
var links = getLinks(nodes, count);
var splines = bundle(links);
center.selectAll(".path")
.data(links)
.enter().append("svg:path")
.attr("stroke", function(d) {return color(map(d.source.name));})
.attr("fill", "none")
.attr("class", "path")
.attr("d", function(d, i) {
var o = splines[i][3];
if (o.depth == 2 && count[o.name] > 1) {
o.x += 2.5;
}
return line(splines[i]); });
// set o.x back
for (i in splines) {
var o = splines[i][3];
if (o.depth == 2 && count[o.name] > 1) {
o.x -= 2.5;
}
}
// minor circles
center.selectAll(".circle")
.data(links)
.enter().append("svg:g")
.attr("class", "circle")
.attr("transform", function(d,i) {
var o = splines[i][3];
if (o.depth == 2 && count[o.name] > 1) {
o.x += 2.5;
}
return "rotate(" + (o.x - 90) + ") translate(" + d.target.y + ")";
})
.append("svg:circle")
.attr("r", function(d) { return d.source.size * min / 900; })
.attr("fill", function (d,i) { return color(map(d.source.name));});
}
$(document).ready(function() {
d3.json("sw.json", function(error, json) {
if (error) return console.warn(error);
setup(json);
});
});
</script>
<script type="text/javascript">
// Hack to make this example display correctly in an iframe on bl.ocks.org
d3.select(self.frameElement).style("height", "700px");
</script>
</body>
</html>
{
"name": "Center",
"size": 0,
"children": [
{
"name": "Research",
"size": 5,
"children": [
{ "name": "Blanc Brain", "size": 15},
{ "name": "Consultation", "size": 15}
]
},
{
"name": "Plan",
"size": 5,
"children": [
{ "name": "Information Architecture", "size": 15},
{ "name": "Accessibility", "size": 15}
],
"other": [
{ "name": "Consultation", "size": 5},
{ "name": "High availability", "size": 5},
{ "name": "Open Source", "size": 5}
]
},
{
"name": "Create",
"size": 5,
"children": [
{ "name": "Creative/Design", "size": 15},
{ "name": "User Interface", "size": 15},
{ "name": "Content Creation", "size": 15},
{ "name": "Photography & Video Production", "size": 15},
{ "name": "Infographics", "size": 15}
],
"other": [
{ "name": "Responsive Design", "size": 5},
{ "name": "Information Architecture", "size": 5},
{ "name": "Accessibility", "size": 5}
]
},
{
"name": "Build",
"size": 5,
"children": [
{ "name": "Website Development", "size": 15},
{ "name": "Web App Development", "size": 15},
{ "name": "Bespoke CMS", "size": 15},
{ "name": "Django", "size": 15},
{ "name": "Python", "size": 15},
{ "name": "Open Source", "size": 15},
{ "name": "Responsive Design", "size": 15}
],
"other": [
{ "name": "Information Architecture", "size": 5},
{ "name": "Accessibility", "size": 5}
]
},
{
"name": "Launch",
"size": 5,
"children": [
{ "name": "High availability", "size": 15},
{ "name": "Hosting", "size": 15},
{ "name": "Support & Maintenance", "size": 15}
],
"other": [
{ "name": "Blanc Brain", "size": 5}
]
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment