So, that was how to find children using only the relationships in the data objects. Why is it so much more complicated than my first answer? It's because I assumed (emphasis on the A-S-S!) that when you said "parent" and "child" you were talking about the hierarchy of the actual web page as well as of the data.
I haven't used the D3 hierarchical layout tools much, and I was surprised to discover that most of Mike's examples don't actually create a hierarchical DOM structure to match the hierarchical data structure. There is a justification in not doing so, in that you reduce the total number of elements in your webpage, but at the cost of losing the semantic structure.
By semantic structure, I mean one that is reflective of the actual meaning of the content. For example, if you have a file system like this:
C drive
FolderA
FileA1
FileA2
File1
Your DOM representing it would look like this:
<g class="node depth0">
<rect ...>
<text>C drive</text>
<g class="children">
<g class="node depth1">
<rect ...>
<text>FolderA</text>
<g class="children">
<g class="node depth2">
<rect ...>
<text>FileA1</text>
</g>
<g class="node depth2">
<rect ...>
<text>FileA2</text>
</g>
</g>
<g class="node depth1">
<rect ...>
<text>File1</text>
</g>
</g>
</g>
By comparison, if you were to copy the approach from one of the layout examples(like this or this), you'd get something like this:
<g class="node">
<rect ...>
<text>C drive</text>
</g>
<g class="node">
<rect ...>
<text>FolderA</text>
</g>
<g class="node">
<rect ...>
<text>FileA1</text>
</g>
<g class="node">
<rect ...>
<text>FileA2</text>
</g>
<g class="node">
<rect ...>
<text>File1</text>
</g>
All the nodes are listed as siblings of each other, with nothing (not even a class) to differentiate between the root and the leaves. The Zoomable Icicle example is the same, except the nodes are just a single rectangle element rather than a group of rectangle plus text.
Now, the hierarchical DOM layout is a little bit more complex (and therefore has a slightly higher memory requirement for the browser). It also takes a little more code to create. But once you have it, then that's where my original comment of
If your child elements are actually DOM children of the parent element,
then they will automatically inherit the display:none;
or visibility:hidden;
style settings from the parent element.
comes into play.
So the trick is just to create the DOM structure that matches the data structure. But I'm going to go one step further and suggest you use HTML DOM elements instead of SVG elements. The end result should look like this fiddle.
Why HTML elements? Because then the browser will automatically collapse your display, shifting over later elements to fill the space that is opened up when you hide other elements. Of course, you can't use HTML elements if you want to draw fancy shapes like the arcs used to create the "sunburst" pattern shown in the API. But you can always replace <div>
elements with <g>
elements to create a semantic SVG structure like I outlined above.
Now, one complication of the semantic approach is that we can't create all the nodes at once; we have to follow the data structure, making children as sub-elements of their parents. And since we don't know how many levels of children a given element will have, that means another recursive function. Recursive functions and tree data structures were made for each other. Literally. This time, instead of getting descendents based on the data, we'll be making the descendents based on the data:
var makeDescendents = function(d,i){
//This function takes the <div> element that called it and appends
//a "rectangle" label for this data object, and then creates a
//a hierarchy of child <div> elements for each of its children
var root = d3.select(this)
.attr("class", function(d){return "depth" + d.depth;})
.classed("node", true)
.classed("first", function(d,i){return i==0;})
.style("width", function(d){return d.dx;});
//add a p to act as the label rectangle for this file/folder
//and style it according to the passed-in d object
root.append("p")
//you could also use a <div> (or any other block-display element)
//but I wanted to keep the nodes distinct from the labels
.classed("node-label", true)
.style("height", function(d) {return d.dy})
.style("background-color", function(d) {
return color((d.children ? d : d.parent).key);
})
.on("click", clicked)
//And so on for any other attributes and styles for the rectangles
//Remembering to use HTML/CSS style properties (e.g. background-color)
//not SVG style attributes (e.g. fill)
.text(function(d) {return d.name;});
//(or however the label value is stored in your data)
if (d.children === null){
//This object doesn't have any children, so label it a file and we're done.
root.classed("file", true);
return;
}
else {
//Label this a folder, then
//create a sub-selection of <div> elements representing the children
//and then call this method on each of them to fill in the content
root.classed("folder", true)
.selectAll("div.node")
.data(function(d) {return d.children;})
.enter()
.append("div")
.call(makeDescendents);
return;
}
}
To call this recursive function, we have to first use the partition layout function to analyze the data, but then we only attach the root data object directly to the top-level selection, and call the recursive function to create everything else. Instead of putting everything in an <svg>
element, I'm going to put it all in an HTML <figure>
element:
var figure = d3.select("body").append("figure")
.attr("width", width)
.attr("height", height);
var rootNode = figure.selectAll("figure > div.node");
d3.json("readme.json", function(error, rootData) {
rootNode = rootNode
.data(partition(d3.entries(rootData)[0])[0])
.enter().append("div")
.call(makeDescendents);
});
Finally (and this is important!), add the following style rules to your CSS:
div.node {
float:left;
}
div.node.first {
clear:left;
}
div.node::after, figure::after {
content:"";
display:block;
clear:both;
}
This tells the <div>
elements, which normally always start on a new row, to instead line themselves up nicely left-to-right, except for the nodes with class "first" (which we assigned to the nodes with index 0, i.e., the first child node of a given parent), which are told to start a new row. And the final rule is so that the height of the div will automatically include all the floating child elements.
And as to your original question on how to hide all the child elements of a folder, well now (after all that...) it is easy. Just hide the parent node, and all the child content will hide too:
figure.selectAll(".folder").filter(function (d) {
return d.dateAccessed > formattedD;
})
.style("display", "none");