You can use ordinal scale to match colors with different node names. Implementing this will require only minor changes to existing code.
Step 1. Create an ordinal scale for the colors
Instead of colors being just a list of color names hardcoded for specific names, use d3.scale.ordinal() and set .range() be the array of colors you want to use. For instance:
var colors = d3.scale.ordinal() .range(["#5687d1","#7b615c","#de783b","#6ab975","#a173d1","#bbbbbb"]);
This will create an ordinal scale that uses the same colors as the original render. Since your data will require more colors, you would like to add a few more to your range, otherwise the colors will repeat.
You can use d3.scale.category20() as a shortcut so that d3 d3.scale.category20() range of 20 categorical colors for you.
Now that you set the fill colors for your path arcs, as well as your breadcrumbs, you simply use colors(d.name) instead of colors[d.name] .
Step 2. Use your data to build a scale domain
.domain() this scale will be set after we receive the data, as this will depend on the list of unique names contained in the data. To do this, we can scroll through the data and create an array of unique names. There are probably several ways to do this, but it works well here:
var uniqueNames = (function(a) { var output = []; a.forEach(function(d) { if (output.indexOf(d.name) === -1) { output.push(d.name); } }); return output; })(nodes);
This creates an empty array, then loops through each element of the nodes array, and if the name node does not yet exist in the new array, it is added.
Then you can simply set the new array as the color bar area:
colors.domain(uniqueNames);
Step 3. Use a scale domain to create a legend
Since the legend will depend on the domain, make sure that the drawLegend() function is called after the domain is installed.
You can find the number of elements in the domain (to set the legend height) by calling colors.domain().length . Then for the .data() legend, you can use the domain itself. Finally, to set the fill color for the legend fields, you call up the color scale on d , since each element in the domain is name . Here, these three changes to the legend look in practice:
var legend = d3.select("#legend").append("svg:svg") .attr("width", li.w) .attr("height", colors.domain().length * (li.h + li.s)); var g = legend.selectAll("g") .data(colors.domain()) .enter().append("svg:g") .attr("transform", function(d, i) { return "translate(0," + i * (li.h + li.s) + ")"; }); g.append("svg:rect") .attr("rx", li.r) .attr("ry", li.r) .attr("width", li.w) .attr("height", li.h) .style("fill", function(d) { return colors(d); });
And about that. Hope this helps.
Here updated JSFiddle .