Built with blockbuilder.org
forked from wrigh3tl's block: Radial Tree
forked from Thanaporn-sk's block: Radial Cluster with Offsets
xxxxxxxxxx
<meta charset="utf-8">
<style>
.node circle {
fill: #c9c9c9;
fill-opacity: 0.8;
}
.node text {
font: 10px sans-serif;
}
.node--internal circle {
fill: #898989;
}
.node--internal text {
text-shadow: 0 1px 0 #fff, 0 -1px 0 #fff, 1px 0 0 #fff, -1px 0 0 #fff;
}
.link {
fill: none;
stroke: #afafaf;
stroke-opacity: 0.4;
stroke-width: 1.5px;
}
</style>
<svg width="960" height="1060"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var svg = d3.select("svg"),
width = 960//+svg.attr("width"),
height = 500//+svg.attr("height"),
g = svg.append("g").attr("transform", "translate(" + (width / 2 + 40) + "," + (height / 2 + 90) + ")");
var nodeRadius = 6;
var radius = 200;
var stratify = d3.stratify()
.parentId(function(d) { return d.id.substring(0, d.id.lastIndexOf(".")); });
var tree = d3.cluster()
.size([360, radius])
.separation(function(a, b) { return (a.parent == b.parent ? 1 : 2) / a.depth; });
var center = { x: 0, y: 0 }
// g.append("circle")
// .attr("cx", 0)
// .attr("cy", 0)
// .attr("r", 20)
//.style("fill", "#f00")
d3.csv("flare.csv", function(error, data) {
if (error) throw error;
var stratified = stratify(data)
.sort(function(a, b) {
if(a.depth === 1 && b.depth === 1) {
var alen = a.children ? a.children.length : 0
var blen = b.children ? b.children.length : 0
return blen - alen
}
return (a.height - b.height) || a.data.id.localeCompare(b.data.id);
});
var root = tree(stratified);
var nodes = root.descendants().slice(1)
var leaves = nodes.filter(function(d) { return !d.children})
var nested = d3.nest()
.key(function(d) { return d.parent.data.id})
.rollup(function(ls) { return ls })
.entries(leaves)
nested.forEach(function(n) {
var maxTheta = d3.max(n.value, function(d) { return d.x })
var minTheta = d3.min(n.value, function(d) { return d.x })
var theta = maxTheta - minTheta
var arclen = (theta/360) * radius * Math.PI * 2
var comfort = Math.floor(arclen/(nodeRadius * .85)) // TODO: figure out this formula
// TODO: comfort should shrink as levels progress...
console.log(n.key, theta, arclen, comfort)
var maxlevel = Math.floor(n.value.length/comfort*2);
if(n.value.length === 1) return;
n.value.forEach(function(d,i) {
// TODO: figure out how to spread these out
var level = Math.floor(i/comfort)// % maxlevel
d.y -= nodeRadius * level * 1.5
// if(i % 2 == 0) {
// d.dx = -(center.x - d.x)/radius * nodeRadius * 1.5
// d.x += d.dx
// d.dy = -(center.y - d.y)/radius * nodeRadius * 1.5
// d.y += d.dy
//d.y -= nodeRadius * 1.5
// }
})
})
console.log("nested", nested)
var link = g.selectAll(".link")
.data(nodes)
.enter().append("path")
.attr("class", "link")
.attr("d", function(d) {
return "M" + project(d.x, d.y)
+ "C" + project(d.x, (d.y + d.parent.y) / 2)
+ " " + project(d.parent.x, (d.y + d.parent.y) / 2)
+ " " + project(d.parent.x, d.parent.y);
});
var node = g.selectAll(".node")
.data(root.descendants())
.enter().append("g")
.attr("class", function(d) { return "node" + (d.children ? " node--internal" : " node--leaf"); })
.attr("transform", function(d) { return "translate(" + project(d.x, d.y) + ")"; });
node.append("circle")
.attr("r", nodeRadius)
.on("click", function(d) { console.log("d", d) })
/*
node.append("text")
.attr("dy", ".31em")
.attr("x", function(d) { return d.x < 180 === !d.children ? 6 : -6; })
.style("text-anchor", function(d) { return d.x < 180 === !d.children ? "start" : "end"; })
.attr("transform", function(d) { return "rotate(" + (d.x < 180 ? d.x - 90 : d.x + 90) + ")"; })
.text(function(d) { return d.id.substring(d.id.lastIndexOf(".") + 1); });
*/
});
function project(x, y) {
var angle = (x - 90) / 180 * Math.PI, radius = y;
return [radius * Math.cos(angle), radius * Math.sin(angle)];
}
</script>
https://d3js.org/d3.v4.min.js