How do I dynamically update nested lists with d3? - d3.js

I have JSON with tree structure. I render it like this:
var lis = d3.select("#active ul")
.selectAll("li")
.data(getTopLevelChildren(), nodeId);
lis.enter().append("li").each(makeNodeView);
makeNodeView does this same thing recursively, which creates a ul/li tree in the DOM.
However, I also want to dynamically update the list. This straight-forward code doesn't work:
lis.each(updateNodeView);
lis.exit().remove();
The problem is that selectAll("li") selected all the li nodes recursively. So lis.exit().remove() removes all li tags anywhere on the page except for those at the root of the tree.
How do I select only 1 level of the tree at a time?

var ul = d3.select(this).append("ul");
var lis = ul.selectAll(function () { return ul[0][0].childNodes })

Related

removing all svg elements in D3 save some specified

const svg=d3.append("svg").attr(...)
const g1=svg.append("g").attr("id","g1").attr(...)
var v1=g1.append(...)
... // many other nested append operations
const g2=g1.append("g").attr("id","g2").attr(...)
var v2=g2.append(...)
... // many other nested append operations
Then how can I remove all elements from svg object apart groups g1 and g2?
Something similar to:
svg.selectAll("*:not('#g1'):not('#g2')").remove();
that does not work.
I would apply a class to all elements that you want to keep, e.g.:
const svg=d3.append("svg")
.attr(...)
const g1=svg.append("g")
.attr(...)
.classed('doKeep', true)
var v1=g1.append(...)
// After adding many nested elements to g1
g1.selectAll('*')
.classed('doKeep', true)
...
const g2=g1.append("g")
.attr(...)
.classed('doKeep', true)
var v2=g2.append(...)
...
// After adding many nested elements to g1
g2.selectAll('*')
.classed('doKeep', true)
Then you can select all elements in you SVG that do not have that class, with a :not() CSS selector as such:
svg.selectAll(':not(.doKeep)').remove()
The inverse would also work, where you mark all elements you want to delete, and then delete them after selecting them. But giving the phrasing of your question, this is the most accurate approach.
Hope this helps!
Edit: Updated to reflect updated question that specifies many nested elements.

In D3, how do you conditionally nest SVG elements (in the context of 'enter')?

Specifically, given this example: https://bl.ocks.org/mbostock/4062045
How would I nest circles inside of the others? And have those be able to link to other (parent) circles?
The key for me was to use what was returned from 'enter' for appending the children and parent SVG objects separately. e.g.:
var enter = svg...enter()
var node = enter.append("rect")...
var children = enter.append("rect")...
(see the link in the question for the entire code context)
To conditionally add children, you can use a filter as follows:
var children = enter.filter(...).append("rect")...

how to get silbling elements in sunburst

I am new to d3.js, I am creating a visualization based on surburst. Can somebody let me know how I can get siblings elements external element in d3.js.
The main part of building the hierarchy from your data will be done by d3. Check the spec for partition.nodes(root) on how this information is put into the nodes. Basically, d3 will populate each node with a reference to its parent and its children providing all that is needed to navigate the hierarchy.
As a starting point you may have a look at this sunburst diagram. When hovering over an arc, this arc as well as its ancestors up to the root node are highlighted. The selection of nodes up the hierarchy which are to be highlighted takes place in a single function:
// Given a node in a partition layout, return an array of all of its ancestor
// nodes, highest first, but excluding the root.
function getAncestors(node) {
var path = [];
var current = node;
while (current.parent) {
path.unshift(current);
current = current.parent;
}
return path;
}
An even simpler version of this function will select the node and its siblings instead of the ancestors:
function getAncestors(node) {
return node.parent.children;
}
I adapted the above example to a plunk demonstrating how this may help solve your problem. In this plunk the hovered node and its siblings will get highlighted.

Expand IndentedTree to specific element

Is there a way to programatically expand an nvd3 IndentedTree as in http://nvd3.org/examples/indentedtree.html to a specific element of the tree and add a class "active" to this element?
Thanks!
Found it.
NVD3 uses the "values" property of a tree node to mark expanded elements, and "_values" for collapsed elements.
So, if you want to expand/collapse a tree or part of it, you move the content from _values to values or vice versa. After that, call chart.update() to get a redraw.
In addition, to add a class "active" to the element containing the tree node, I used the "classes" callback of the columns array. The callback runs on the child element of the table data element:
classes: function(d) {
if (d.isSelected) {
d3.select(this.parentNode).attr("class", "active");
}
}
"isSelected" is a property I added to the current node.

d3.js How to make all the nodes collapsed in Collapsible indented Tree

I am trying to work on a sample d3 collapsible tree. mbostock’s block #1093025. Initially when the form is loaded, how do i make all the nodes collapsed initially?
The way the nodes are collapsed in this example is by removing the .children member of the data elements such that no children are drawn. You can do this statically to have everything collapsed to start with. The code would look like this.
function moveChildren(node) {
if(node.children) {
node.children.forEach(function(c) { moveChildren(c); });
node._children = node.children;
node.children = null;
}
}
moveChildren(json);
Modified example here.
You have to add a function for that in your json loading.
Check that example : http://mbostock.github.io/d3/talk/20111018/tree.html

Resources