How to find links in d3 v4? - d3.js

I have used the following code in d3 v3 to find nodes and links for a horizontal tree (top to bottom). Here is how the tree will look like:
var nodes = d3.layout.tree().nodes(jsonData).reverse();
var links = d3.layout.tree().links(nodes);
I'm trying to do the same in d3 v4. The v4 is missing the tree.links(nodes) method where it can accept the nodes.
How can I find the links in d3 v4?

I'm just adding this to save myself (and possibly others) time from having to dig the answers out of the demos. I'm new to D3 as well so I'm hoping this is as helpful to others as it was to me.
Use d3.hierarchy() & node.descendants() to get nodes and links.
// Assigns parent, children, height, depth, etc..
var root = d3.hierarchy(jsonData);
// Assigns the x and y coordinates for the nodes.
tree(root);
// Returns array of node objects.
var nodes = root.descendants();
// Returns array of link objects between nodes.
var links = root.descendants().slice(1);
//var links = root.links(); // to get objects with source and target properties.
Can also shorten this down a bit if wanted which still does all of the above.
var root = d3.hierarchy(jsonData),
nodes = tree(root).descendants(),
links = nodes.slice(1);
If you need to grab nodes/links within an event. For example on drag start of a node when using a tree diagram (and I'm sure this could be useful elsewhere as well).
var drag = d3.drag()
.on("start", function dragStart(d) {
var nodes = d.descendants(),
links = nodes.slice(1);
});
Or alternatively use node.links() where each link defines source and target properties.
var drag = d3.drag()
.on("start", function dragStart(d) {
var nodes = d.descendants(),
links = d.links();
});
You would think this would also work in this case but it doesn't (bummer).
var root = d3.hierarchy(jsonData),
nodes = tree(root).descendants(),
links = nodes.links(); // <-- only works on a single node, resort to slice(1).

Related

How to convert this d3 v3 graph to a v4?

I have been trying to convert this example in d3 v3 to a v4 version but still having trouble.
http://bl.ocks.org/eesur/be2abfb3155a38be4de4
Here is a JSFiddle of what I have so far: https://jsfiddle.net/echilee/sfbcntph/135/
I am able to console.log the LINKS and the NODES. I made some progress and am able to see the nodes and click to open and close those that are connected. But cannot see links and how they should connect the nodes.
I replaced the nodes and links declaration and force function with this code:
// create a hierarchy from the root
const treeRoot = hierarchy(root)
tree(treeRoot)
const nodes = flatten(treeRoot.descendants())
const links = treeRoot.links()
var simulation = d3.forceSimulation()
I am not able to see the links.

How do I "register" a dragged group to specific coordinates with d3?

I'm trying to do something that (it seems to me!) should be simple,
but my attempts are getting very convoluted, and I'm looking for d3
guidance.
Suppose I have a dragged group object (consisting of a rectangle and
its text) that has been dropped someplace at the end of a drag. I want
to "register" this group at specific coordinates. How do I do that?
I am adding my code to the dragended() function associated with
d3.drag's on("end") event.
function dragended(d) {
var move = d3.select(this);
var g = move._groups[0][0]; // same as this!
var rect = g.children[0]
rect.x = schedLeft;
rect.y = schedTop;
d3.select(this).classed("active", false);
}
I bind d3.select(this) to the variable move, and get an object
like that shown in the attached figure (Chrome developer Local).
EDIT: move._groups[0][0] is silly; it's the same as this!
Using this I can get the group (with child rect and
text nodes) that I want to move.
schedLeft is the x coordinate where I want the group dropped. The rect node has x and y attributes, but my rect.x = schedLeft
doesn't change anything (watching in the debugger).
Is that even the right way to have a transition of the entire group
(ie, including the attending text) to its new location?
Thanks to hints I found on SO here (from 2013!) I got it working using this:
function dragended(d) {
// register dragged move into hourSched
var top = schedTop + (nsched++) * menuWOHgt;
var transX = newDropX - d.x ;
var transY = newDropY - d.y;
var tstr = `translate( ${transX}, ${transY} )`;
d3.select(this).attr("transform", tstr)
.classed("active", false);
}

Hide root node and edges in D3 v4 Tree Diagram

For the following Fiddle I'd like to hide the root node. Any help is appreciated, to view the code please view the fiddle.
I imagine I would do something like the following but I'm unsure of how/where to implement it:
if (d.depth > 0) {
...node is drawn
}
Image below:
Not drawing it is not "drawing it with zero opacity" or "hidden display". It's actually not appending the element.
Therefore, the simplest option is removing it from the data array. Just filter out the first node:
nodes = nodes.filter(function(d){
return d.depth != 0;
})
As 0 is falsy, this is the same of:
nodes = nodes.filter(function(d){
return d.depth;
})
And also filter out all links from it:
links = links.filter(function(d){
return d.depth != 1;
})
Here is your updated fiddle: https://jsfiddle.net/wa21csbc/
Also, since those elements are not painted anymore, you can move the dataviz to the left, thus occupying the empty SVG space. That space is there because we're filtering out the first node after d3.tree() calculated the positions.

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")...

D3 js line overlaps node

I am doing force layout, on event click i add new node and connect by line. But
line overlaps node. Why? My code is shown http://jsfiddle.net/WRGtL/
function click(d) {
if (d3.event.defaultPrevented) return; // ignore drag
//alert("clicked");
var d = {id:"d"};
nodes.push(nodeId[index]);
if(index==0)
links.push({source: a, target: nodeId[index]});
else
links.push({source: nodes[1], target: nodeId[index]});
index++;
start();
}
In SVG, the Z order of elements is the order they appear in the file. The easiest way of having all lines appear below the circles is to group all lines and all circles in their own groups and let these groups define the Z order.
I've simply added two groups linksG and nodesG that the elements will be created in:
var linkG = svg.append("g"),
nodeG = svg.append("g");
var node = nodeG.selectAll(".node"),
link = linkG.selectAll(".link");
see the JSFiddle for a demo.
Edit: forgot to save the fiddle. Link fixed.

Resources