Built with blockbuilder.org.
Click on Open in a new window to see responsiveness.
forked from coderextreme's block: Responsive Double Hierarchy DAG cluster
| license: mit |
Built with blockbuilder.org.
Click on Open in a new window to see responsiveness.
forked from coderextreme's block: Responsive Double Hierarchy DAG cluster
| <!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} | |
| ] | |
| } | |
| ] | |
| } |