A dendrogram is a node-link diagram that places leaf nodes of the tree at the same depth. In this example, the classes (leaf nodes) are aligned on the right edge, with the packages (internal nodes) to the left. Data shows the Flare class hierarchy, courtesy Jeff Heer.
Compare to this Cartesian layout.
forked from mbostock's block: Radial Cluster Dendrogram - link
forked from MyAkosombo's block: Radial Cluster Dendrogram - link
xxxxxxxxxx
<meta charset="utf-8">
<style>
.node circle {
fill: #999;
}
.node text {
font: 10px sans-serif;
}
.node--internal circle {
fill: #555;
}
.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: #555;
stroke-opacity: 0.4;
stroke-width: 1.5px;
}
.tooltip{
position : absolute;
text-align : center;
max-width : 340px;
max-height : 450px;
padding : 8px;
border : none;
border-radius : 5px;
margin-top : -30px;
font : 14px sans-serif;
background : black;
color : white;
pointer-events: none;
opacity : 0.55;
}
</style>
<body>
<div id="container"></div>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
d3.csv("flare.csv", function(error, data) {
// data.forEach(function (d) {
// d.value = +d.value;
// d.file_type=d.file_type;});
if (error) throw error;
var margin = {top: 65, bottom: 50, left: 50, right: 30}, axisPadding = 10;
var Width = 900, Height = 1022;
var svgWidth = Width + margin.left + margin.right,
svgHeight = Height + margin.top + margin.bottom;
var svg = d3.select('#container')
.append('svg')
.attr("width", 1257)
.attr("height", 1067)
var g = svg.append('g')
.attr('class', 'graph')
.attr('transform', 'translate(' + [466, margin.top + 374] + ')');
var stratify = d3.stratify()
.parentId(function(d) { return d.id.substring(0, d.id.lastIndexOf(".")); });
var tree = d3.cluster()
.size([360, 390])
.separation(function(a, b) { return (a.parent == b.parent ? 1 : 2) / a.depth; });
var root = tree(stratify(data)
.sort(function(a, b) { return (a.height - b.height) || a.id.localeCompare(b.id); }));
var link = g.selectAll(".link")
.data(root.descendants().slice(1))
.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", 2.5);
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); })
.on('mouseover', mouseover)
.on('mousemove', mousemove)
.on('mouseout', mouseout);
function mouseover(){
div.style('display', 'inline');
d3.select(this).style("fill", d3.rgb(color = '#ddb640'))
}
function mousemove(){
var data = d3.select(this).data()[0];
var htmlData = [
data.id,
data.data.value
];
div
// .html(
// `${d.id}<hr/>${d.id}<hr/>${d.file_type}<hr/>${d.owner}<hr/>${d.method}`)
.html(htmlData.join("<br>"))
.style('left', (d3.event.pageX + 94) + 'px')
.style('top', (d3.event.pageY - 32) + 'px');
}
function mouseout(){
div.style('display', 'none');
d3.select(this).style("fill", d3.rgb(color ='#111111' ))
}
});
// tooltips
var div = d3.select('#container').append('div')
.attr('class', 'tooltip')
.style('display', 'none');
function project(x, y) {
var angle = (x - 90) / 180 * Math.PI, radius = y;
return [radius * Math.cos(angle), radius * Math.sin(angle)];
}
</script>
</body>
https://d3js.org/d3.v4.min.js