After muddling through the code of this awesome example of @mbostck I found a solution and rewrote my code from treelist layout to the tree layout. But I've splitted the code in two parts: one is to build the list with ul
and li
HTML element. The other part is to draw the paths with just one big svg.
So the code of the first part was following:
// This is my HTML container element
var $treelistContainer = d3.select('#treelist');
var tree = d3.layout.tree();
var indent = 15,
nodeTree = 0;
var ul = $treelistContainer.append("ul").classed("treelist",true);
var nodes = tree.nodes(data);
var nodeEls = ul.selectAll("li.item").data(nodes);
//list nodes
var listEnter = nodeEls
.enter()
.append("li")
.attr("class", function(d) {
// set class to node and to leaf (for endpoints) or to root (for stem)
var output = 'item'+(d.parent ? d.children ? '' : ' leaf' : ' root');
// set class to even or to odd, based on its level;
output += ((d.depth % 2) === 0 ? ' even' : ' odd');
return output;
})
.attr("id", function(d,i){return "id"+i})
.style("opacity", 1)
.style("background-color", function(d) {
return colorgrey(d.depth);
})
.append("span").attr("class", "value")
.style("padding-left", function (d) {
return 20 + d.depth * indent + "px";
})
.html(function (d) { return d.name; });
That builds the whole HTML list for the project. Now here comes the magic of the next part: you have to recalculate the x
, y
. I also used a value called nodeTree
to give every hierarchy an own ID to choose a different color for it. So here's the code:
var nodeTree = 0;
var rootTop = d3.selectAll('li.item')
.filter(function(d,i) {
return i == 0;
})
.node()
.getBoundingClientRect()
.top;
nodes.forEach(function(n, i) {
// Get position of li element
var top = d3.selectAll('li.item')
.filter(function(d2,i2) {
return i2 == i;
})
.node()
.getBoundingClientRect()
.top;
n.x = top - rootTop;//i * 38;
n.y = n.depth * indent;
if (n.depth == 1) nodeTree++;
n.value = nodeTree;
});
Now I simply read out x, y and the value to calculate it's diagonal position. Before I have to build the container and calculate some other things
var width = $treelistContainer.node().getBoundingClientRect().width,
height = $treelistContainer.node().getBoundingClientRect().height,
i = 0,
id = 0,
margin = {top: 20, right: 10, bottom: 10, left: 15};
var diagonal = d3.svg.diagonal()
.projection(function(d) { return [d.y, d.x]; });
var svg = $treelistContainer
.append("svg")
.attr("width", width - margin.left - margin.right+"px")
.attr("height", height+"px")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var link = svg.selectAll("path.link")
.data(tree.links(nodes))
.enter()
.insert("path", "g")
.attr("class", "link")
.attr("stroke", function(d) {
// Setting the color based on the hierarchy
console.log(d.target.value);
return color(d.target.value);
})
.attr("d", function(d,i) {
var source = {x: d.source.x, y: d.source.y};
var target = {x: d.target.x, y: d.target.y};
return diagonal({source: source, target: target});
});
And here's how it looks like: https://www.dropbox.com/s/ysbszycoiost72t/result.png?dl=0
I will try to optimize it by changing the interpolation type, adding some little colorful node circles and so on.
Hope this will help someone.