Increasing gap between nodes of my D3 tree layout

14,970

Solution 1

Better approach would be to use separation() method. Please look at documentation for details, in principle with that method you define minimum distance between nodes, but in your case you need to restrict making gapos only to some nodes, thats why there is condition inside separation())

var tree = d3.layout.tree()
    .separation(function(a, b) { return ((a.parent == root) && (b.parent == root)) ? 3 : 1; })
    .size([height, width - 160]);

On the following pictures is the tree without the line of code with call to separation(): (I added nodes AA and ZZ to my previous example, and also BB and CC, but these nodes display OK atleast for this case)

enter image description here

... and here with that line:

enter image description here

Live jsfiddles:

here and here

Just for laughs, I further modified the line from " ? 3 : 1; })" to " ? 5 : .6; })", and I got:

enter image description here

Solution 2

If you add a child to the nodes that you need to move, and than make that child and its correspondent link invisible, that you will have the gap you need. However, I admit this solution is a little quick and dirty.

The problem here that position of the nodes are computed by so-called Reingold-Tilford algorithm automatically within d3.js, and it requires a lot of knowledge to modify the algorithm internally, or use some other algorithm. But some solutions with twaeaking like I described are possible.

Share:
14,970

Related videos on Youtube

javalearner
Author by

javalearner

Updated on September 15, 2022

Comments

  • javalearner
    javalearner over 1 year

    As shown in the diagram, I am trying to increase the gap between last nodes on either side of the tree layout as they are overlapping

    Is there any way to do it in D3?

    enter image description here

    treelayout with nodes

                {
                "name": "",
                "type": "network",
                "children": [{
                    "name": "",
                    "type": "lb",
                    "children": [{
                            "name": "",
                            "type": "mm",
                            "id": "app",
                            "connServer": "s",
                            "size": 3938
                        }]
                },
                {
                    "name": "",
                    "type": "vm",
                    "children": [{
                        "name": "",
                        "type": "container",
                        "children": [{
                            "name": "",
                            "type": "appServer",
                            "id": "app1",
                            "connServer": "db1",
                            "size": 3938
                        }]
                    },
                    {
                        "name": "",
                        "type": "container",
                        "children": [{
                            "name": "",
                            "type": "webServer",
                            "id": "web1",
                            "connServer": "app1",
                            "size": 3534
                        }]
                    },
                    {
                        "name": "",
                        "type": "container",
                        "children": [{
                            "name": "",
                            "type": "dataServer",
                            "id": "db1",
                            "connServer": "app1",
                            "size": 7074
                        }]
                    }]
                },
                {
                    "name": "",
                    "type": "vm",
                    "children": [{
                        "name": "",
                        "type": "container",
                        "children": [{
                            "name": "",
                            "type": "webServer",
                            "id": "web2",
                            "connServer": "app1",
                            "size": 721
                        }]
                    },
                    {
                        "name": "",
                        "type": "container",
                        "children": [{
                            "name": "",
                            "type": "dataServer",
                            "id": "db2",
                            "connServer": "db1",
                            "size": 721
                        }]
                    }]
                },
                {
                    "name": "",
                    "type": "vm",
                    "children": [{
                        "name": "",
                        "type": "container",
                        "children": [{
                            "name": "",
                            "type": "appServer",
                            "id": "app2",
                            "connServer": "db3",
                            "size": 721
                        }]
                    },
                    {
                        "name": "",
                        "type": "container",
                        "children": [{
                            "name": "",
                            "type": "webServer",
                            "id": "web3",
                            "connServer": "app2",
                            "size": 721
                        }]
                    },
                    {
                        "name": "",
                        "type": "container",
                        "children": [{
                            "name": "",
                            "type": "dataServer",
                            "id": "db3",
                            "connServer": "app2",
                            "size": 721
                        }]
                    }]
                },
                {
                    "name": "",
                    "type": "vm",
                    "children": [{
                        "name": "",
                        "type": "container",
                        "children": [{
                            "name": "",
                            "type": "appServer",
                            "id": "app3",
                            "connServer": "db4",
                            "size": 721
                        }]
                    },
                    {
                        "name": "",
                        "type": "container",
                        "children": [{
                            "name": "",
                            "type": "webServer",
                            "id": "web4",
                            "connServer": "app3",
                            "size": 721
                        }]
                    },
                    {
                        "name": "",
                        "type": "container",
                        "children": [{
                            "name": "",
                            "type": "dataServer",
                            "id": "db4",
                            "connServer": "app3",
                            "size": 721
                        }]
                    }]
                },{
                    "name": "",
                    "type": "sto",
                    "children": [{
                            "name": "",
                            "type": "mm",
                            "id": "app",
                            "connServer": "s",
                            "size": 3938
                        }]
                }]
            }
    

    Here is the code ,i am using for building the tree layout,when i use separate() the child nodes of tree layout are not aligned together in space,they stick to their places,without separate method,collpased child node will be wrapped together/aligned in space /** * */ var tooltipMap = d3.map();

        // Get JSON data
        treeJSON = d3.json("network.json", function(error, treeData) {
            // Calculate total nodes, max label length
            var totalNodes = 0;
            var maxLabelLength = 15;
            // variables for drag/drop
            var selectedNode = null;
            var draggingNode = null;
            // panning variables
            var panSpeed = 200;
            var panBoundary = 20; // Within 20px from edges will pan when
            // dragging.
            // Misc. variables
            var i = 0;
            var duration = 750;
            var root;
    
            // size of the diagram
            var docWidth = $(document).width();
            var viewerWidth = docWidth / (1.361);
            var docHeight = $(document).height();
            var halfHeight = docHeight / 2;
            var quarterHeight = docHeight / 4;
            viewerHeight = halfHeight + quarterHeight;
            var tree = d3.layout.tree().size([ viewerHeight, viewerWidth ]);
            /*
             * var tree = d3.layout.tree().separation(function(a, b) { return ((a.parent ==
             * root) && (b.parent == root)) ? 3 : 1; }).size([ viewerHeight, viewerWidth -
             * 160 ]);
             */
            // define a d3 diagonal projection for use by the node paths
            // later on.
            var diagonal = d3.svg.diagonal().projection(function(d) {
                return [ d.x, -d.y ];
            });
    
            // A recursive helper function for performing some setup by
            // walking through all nodes
    
            function visit(parent, visitFn, childrenFn) {
                if (!parent)
                    return;
    
                visitFn(parent);
    
                var children = childrenFn(parent);
                if (children) {
                    var count = children.length;
                    for ( var i = 0; i < count; i++) {
                        visit(children[i], visitFn, childrenFn);
                    }
                }
            }
    
            // Call visit function to establish maxLabelLength
            visit(treeData, function(d) {
                totalNodes++;
                maxLabelLength = Math.max(d.name.length, maxLabelLength);
    
            }, function(d) {
                return d.children && d.children.length > 0 ? d.children : d.children;
            });
    
            function getConServers(element, event, status) {
                var conServerNode;
                var targetElement = event.target;
                var targetId = targetElement.id;
                if (targetId != null) {
                    var server = tooltipMap.get(targetElement.id);
                    if (server != null) {
                        var connectedServer = server.get("connId");
                        var outerTarget = d3.select("#" + "outer" + targetId);
                        var outerCon = d3.select("#" + "outer" + connectedServer);
                        if (status == "enter") {
    
                            outerTarget.style("stroke", "#48C127");
                            outerTarget.style("stroke-width", 3);
                            outerCon.style("stroke", "#F07A0B");
                            outerCon.style("stroke-width", 3);
    
                        } else if (status == "exit") {
    
                            outerTarget.style("stroke", "#fff");
                            outerCon.style("stroke", "#fff");
                            outerTarget.style("stroke-width", 1);
                            outerCon.style("stroke-width", 1);
    
                        }
                    }
                }
    
            }
    
            // sort the tree according to the node names
    
            function sortTree() {
                tree.sort(function(a, b) {
                    return b.name.toLowerCase() < a.name.toLowerCase() ? 1 : -1;
                });
            }
            // Sort the tree initially incase the JSON isn't in a sorted
            // order.
            sortTree();
    
            // TODO: Pan function, can be better implemented.
    
            function pan(domNode, direction) {
                var speed = panSpeed;
                if (panTimer) {
                    clearTimeout(panTimer);
                    translateCoords = d3.transform(svgGroup.attr("transform"));
                    if (direction == 'left' || direction == 'right') {
                        translateX = direction == 'left' ? translateCoords.translate[0] + speed : translateCoords.translate[0]
                                - speed;
                        translateY = translateCoords.translate[1];
                    } else if (direction == 'up' || direction == 'down') {
                        translateX = translateCoords.translate[0];
                        translateY = direction == 'up' ? translateCoords.translate[1] + speed : translateCoords.translate[1]
                                - speed;
                    }
                    scaleX = translateCoords.scale[0];
                    scaleY = translateCoords.scale[1];
                    scale = zoomListener.scale();
                    svgGroup.transition().attr("transform",
                            "translate(" + translateX + "," + translateY + ")scale(" + scale + ")");
                    d3.select(domNode).select('g.node').attr("transform", "translate(" + translateX + "," + translateY + ")");
                    zoomListener.scale(zoomListener.scale());
                    zoomListener.translate([ translateX, translateY ]);
                    panTimer = setTimeout(function() {
                        pan(domNode, speed, direction);
                    }, 50);
                }
            }
    
            // Define the zoom function for the zoomable tree
    
            function zoom() {
                svgGroup.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
            }
    
            // define the zoomListener which calls the zoom function on the
            // "zoom" event constrained within the scaleExtents
            var zoomListener = d3.behavior.zoom().scaleExtent([ 0.1, 3 ]).on("zoom", zoom);
    
            function initiateDrag(d, domNode) {
                draggingNode = d;
                d3.select(domNode).select('.ghostCircle').attr('pointer-events', 'none');
                d3.selectAll('.ghostCircle').attr('class', 'ghostCircle show');
                d3.select(domNode).attr('class', 'node activeDrag');
    
                svgGroup.selectAll("g.node").sort(function(a, b) { // select
                    // the
                    // parent
                    // and
                    // sort
                    // the
                    // path's
                    if (a.id != draggingNode.id)
                        return 1; // a is not the hovered element,
                    // send "a" to the back
                    else
                        return -1; // a is the hovered element,
                    // bring "a" to the front
                });
                // if nodes has children, remove the links and nodes
                if (nodes.length > 1) {
                    // remove link paths
                    links = tree.links(nodes);
                    nodePaths = svgGroup.selectAll("path.link").data(links, function(d) {
                        return d.target.id;
                    }).remove();
                    // remove child nodes
                    nodesExit = svgGroup.selectAll("g.node").data(nodes, function(d) {
                        return d.id;
                    }).filter(function(d, i) {
                        if (d.id == draggingNode.id) {
                            return false;
                        }
                        return true;
                    }).remove();
                }
    
                // remove parent link
                parentLink = tree.links(tree.nodes(draggingNode.parent));
                svgGroup.selectAll('path.link').filter(function(d, i) {
                    if (d.target.id == draggingNode.id) {
                        return true;
                    }
                    return false;
                }).remove();
    
                dragStarted = null;
            }
    
            // define the baseSvg, attaching a class for styling and the
            // zoomListener
            var baseSvg = d3.select("#tree-container").append("svg").attr("width", viewerWidth).attr("height", viewerHeight)
                    .attr("class", "overlay").attr("id", "treesvg").call(zoomListener);
    
            // Define the drag listeners for drag/drop behaviour of nodes.
            dragListener = d3.behavior.drag().on("dragstart", function(d) {
                if (d == root) {
                    return;
                }
                dragStarted = true;
                nodes = tree.nodes(d);
                d3.event.sourceEvent.stopPropagation();
                // it's important that we suppress the mouseover
                // event on the node being dragged. Otherwise it
                // will absorb the mouseover event and the
                // underlying node will not detect it
                // d3.select(this).attr('pointer-events',
                // 'none');
            }).on("drag", function(d) {
                if (d == root) {
                    return;
                }
                if (dragStarted) {
                    domNode = this;
                    initiateDrag(d, domNode);
                }
    
                // get coords of mouseEvent relative to svg
                // container to allow for panning
                relCoords = d3.mouse($('svg').get(0));
                if (relCoords[0] < panBoundary) {
                    panTimer = true;
                    pan(this, 'left');
                } else if (relCoords[0] > ($('svg').width() - panBoundary)) {
    
                    panTimer = true;
                    pan(this, 'right');
                } else if (relCoords[1] < panBoundary) {
                    panTimer = true;
                    pan(this, 'up');
                } else if (relCoords[1] > ($('svg').height() - panBoundary)) {
                    panTimer = true;
                    pan(this, 'down');
                } else {
                    try {
                        clearTimeout(panTimer);
                    } catch (e) {
    
                    }
                }
    
                d.x0 += d3.event.dy;
                d.y0 += d3.event.dx;
                var node = d3.select(this);
                node.attr("transform", "translate(" + d.y0 + "," + d.x0 + ")");
                updateTempConnector();
            }).on("dragend", function(d) {
                if (d == root) {
                    return;
                }
                domNode = this;
                if (selectedNode) {
                    // now remove the element from the
                    // parent, and insert it into the new
                    // elements children
                    var index = draggingNode.parent.children.indexOf(draggingNode);
                    if (index > -1) {
                        draggingNode.parent.children.splice(index, 1);
                    }
                    if (typeof selectedNode.children !== 'undefined' || typeof selectedNode._children !== 'undefined') {
                        if (typeof selectedNode.children !== 'undefined') {
                            selectedNode.children.push(draggingNode);
                        } else {
                            selectedNode._children.push(draggingNode);
                        }
                    } else {
                        selectedNode.children = [];
                        selectedNode.children.push(draggingNode);
                    }
                    // Make sure that the node being added
                    // to is expanded so user can see added
                    // node is correctly moved
                    expand(selectedNode);
                    sortTree();
                    endDrag();
                } else {
                    endDrag();
                }
            });
    
            function endDrag() {
                selectedNode = null;
                d3.selectAll('.ghostCircle').attr('class', 'ghostCircle');
                d3.select(domNode).attr('class', 'node');
                // now restore the mouseover event or we won't be able to
                // drag a 2nd time
                d3.select(domNode).select('.ghostCircle').attr('pointer-events', '');
                updateTempConnector();
                if (draggingNode !== null) {
                    update(root);
                    centerNode(draggingNode);
                    draggingNode = null;
                }
            }
    
            // Helper functions for collapsing and expanding nodes.
    
            function collapse(d) {
                if (d.children) {
                    d._children = d.children;
                    d._children.forEach(collapse);
                    d.children = null;
                }
            }
    
            function expand(d) {
                if (d._children) {
                    d.children = d._children;
                    d.children.forEach(expand);
                    d._children = null;
                }
            }
    
            var overCircle = function(d) {
                selectedNode = d;
                updateTempConnector();
            };
            var outCircle = function(d) {
                selectedNode = null;
                updateTempConnector();
            };
    
            // Function to update the temporary connector indicating
            // dragging affiliation
            var updateTempConnector = function() {
                var data = [];
                if (draggingNode !== null && selectedNode !== null) {
                    // have to flip the source coordinates since we did this
                    // for the existing connectors on the original tree
                    data = [ {
                        source : {
                            x : selectedNode.y0,
                            y : selectedNode.x0
                        },
                        target : {
                            x : draggingNode.y0,
                            y : draggingNode.x0
                        }
                    } ];
                }
                var link = svgGroup.selectAll(".templink").data(data);
    
                link.enter().append("path").attr("class", "templink").attr("d", d3.svg.diagonal()).attr('pointer-events',
                        'none');
    
                link.attr("d", d3.svg.diagonal());
    
                link.exit().remove();
            };
    
            // Function to center node when clicked/dropped so node doesn't
            // get lost when collapsing/moving with large amount of
            // children.
    
            function centerNode(source) {
                scale = zoomListener.scale();
                x = -source.y0;
                y = -source.x0;
                x = x * scale + viewerWidth / 2;
                y = y * scale + viewerHeight / 2;
                var mySvg = d3.select("#tree-container");
                mySvg.select('g').transition().duration(duration).attr("transform",
                        "translate(" + (x - 230) + "," + (y + 411) + ")scale(" + scale + ")");
                zoomListener.scale(scale);
                zoomListener.translate([ x, y ]);
    
                var shootX, shootY;
    
                // shootX=x+270;
                // shootY=y+350;
    
                shootX = "850.242468772961", shootY = "450.75";
                getShootImage(shootX, shootY);
            }
    
            /**
             * This function is used to add shooting image and text into the frame.
             * 
             * @param shootImgX
             * @param shootTextX
             * @return
             */
            function getShootImage(shootImgX, shootImgY) {
                d3.select("#shootCircle").remove();
                var imgUrl = "image/target-icon.png";
                baseSvg.append("image").attr("id", "shootCircle").attr("xlink:href", imgUrl).attr("x", shootImgX).attr("y",
                        shootImgY).attr("width", 50).attr("height", 50).style("fill", "red").classed("shoot", true);
    
                baseSvg.append("text").text("Shooting Gun").attr("x", shootImgX).attr("y", shootImgY + 50).attr("width", 50)
                        .attr("height", 50).style("font-weight", "bold");
    
                var loadButton = document.createElement("input");
                loadButton.setAttribute("type", "button");
                loadButton.setAttribute("value", "Add Load");
                loadButton.setAttribute("class", "btn btn-cust-info");
                loadButton.setAttribute("id", "addload");
                loadButton.setAttribute("x", shootImgX);
                loadButton.setAttribute("y", shootImgY);
                loadButton.setAttribute("width", 500);
                loadButton.setAttribute("height", 500);
                loadButton.style.align = "left";
            }
    
            // Toggle children function
    
            function toggleChildren(d) {
                if (d.children) {
                    d._children = d.children;
                    d.children = null;
                } else if (d._children) {
                    d.children = d._children;
                    d._children = null;
                }
                return d;
            }
    
            // Toggle children on click.
    
            function click(d) {
                if (d3.event.defaultPrevented)
                    return; // click suppressed
                d = toggleChildren(d);
                update(d);
                centerNode(d);
            }
    
            function update(source) {
                // Compute the new height, function counts total children of
                // root node and sets tree height accordingly.
                // This prevents the layout looking squashed when new nodes
                // are made visible or looking sparse when nodes are removed
                // This makes the layout more consistent.
                var levelWidth = [ 1 ];
                var childCount = function(level, n) {
    
                    if (n.children && n.children.length > 0) {
                        if (levelWidth.length <= level + 1)
                            levelWidth.push(10);
    
                        levelWidth[level + 1] += n.children.length;
                        n.children.forEach(function(d) {
                            childCount(level + 1, d);
                        });
                    }
                };
                childCount(0, root);
                var newHeight = d3.max(levelWidth) * 25; // 25 pixels per
                // line
                tree = tree.size([ newHeight, viewerWidth ]);
    
                // Compute the new tree layout.
                var nodes = tree.nodes(root).reverse(), links = tree.links(nodes);
    
                // Set widths between levels based on maxLabelLength.
                nodes.forEach(function(d) {
                    d.y = (d.depth * (maxLabelLength * 7)); // maxLabelLength
                    // * 10px
                    // alternatively to keep a fixed scale one can set a
                    // fixed depth per level
                    // Normalize for fixed-depth by commenting out below
                    // line
                    // d.y = (d.depth * 500); //500px per level.
    
                    /** My code -starts here * */
                    if (nodes[i] != null && nodes[i] != 'undefined') {
                        if (nodes[i].type == "appServer") {
                            var toolMap = d3.map();
                            toolMap.set("connId", d.connServer);
                            toolMap.set("id", d.id);
                            toolMap.set("type", "Web server");
                            tooltipMap.set(d.id, toolMap);
                        } else if (nodes[i].type == "webServer") {
                            var toolMap = d3.map();
                            toolMap.set("connId", d.connServer);
                            toolMap.set("id", d.id);
                            toolMap.set("type", "Web server");
                            tooltipMap.set(d.id, toolMap);
                        } else if (nodes[i].type == "dataServer") {
                            var toolMap = d3.map();
                            toolMap.set("connId", d.connServer);
                            toolMap.set("id", d.id);
                            toolMap.set("type", "Web server");
                            tooltipMap.set(d.id, toolMap);
                        }
                    }
                    /** My code ends here */
    
                });
    
                // Update the nodes…
                node = svgGroup.selectAll("g.node").data(nodes, function(d) {
                    return d.id || (d.id = ++i);
                });
    
                // Enter any new nodes at the parent's previous position.
                var nodeEnter = node.enter().append("g").call(dragListener).attr("class", "node").attr("transform",
                        function(d) {
                            return "translate(" + source.y0 + "," + source.x0 + ")";
                        }).on('click', click);
    
                // Adding the outer circle to highlight the connected servers
                nodeEnter.append("circle").attr({
                    r : 15
                }).attr("id", function(d, i) {
                    if (nodes[i].type == "appServer") {
                        return "outer" + nodes[i].id;
                    } else if (nodes[i].type == "webServer") {
                        return "outer" + nodes[i].id;
                    } else if (nodes[i].type == "dataServer") {
                        return "outer" + nodes[i].id;
                    }
                }).style("fill", "transparent").style("stroke-width", function(d, i) {
                    if (nodes[i].type == "appServer") {
                        return "1";
                    } else if (nodes[i].type == "webServer") {
                        return "1";
                    } else if (nodes[i].type == "dataServer") {
                        return "1";
                    } else {
                        return "0";
                    }
                }).style("stroke", "#fff");
    
                nodeEnter.append("circle").attr("r", 5).attr("id", function(d, i) {
                    if (nodes[i].type == "appServer") {
                        return nodes[i].id;
                    } else if (nodes[i].type == "webServer") {
                        return nodes[i].id;
                    } else if (nodes[i].type == "dataServer") {
                        return nodes[i].id;
                    }
                }).style("filter", function(d, i) {
                    if (nodes[i].type == "vm") {
                        return "url(#virtualMac)";
                    } else if (nodes[i].type == "container") {
                        return "url(#container)";
                    } else if (nodes[i].type == "appServer") {
                        return "url(#appserver)";
                    } else if (nodes[i].type == "webServer") {
                        return "url(#webserver)";
                    } else if (nodes[i].type == "sto") {
                        return "url(#storage)";
                    } else if (nodes[i].type == "dataServer") {
                        return "url(#dbserver)";
                    } else if (nodes[i].type == "network") {
                        return "url(#network)";
                    } else if (nodes[i].type == "lb") {
                        return "url(#loadbalancer)";
                    }
                }).style("fill", function(d) {
                    return d._children ? "lightsteelblue" : "#fff";
                }).on("mouseover", function(d) {
                    getConServers(this, d3.event, "enter");
                }).on("mouseout", function(d) {
                    getConServers(this, d3.event, "exit");
                });
    
                nodeEnter.append("text").attr("x", function(d) {
                    return d.children || d._children ? -10 : 10;
                }).attr("dy", ".35em").attr('class', 'nodeText').attr("text-anchor", function(d) {
                    return d.children || d._children ? "end" : "start";
                }).text(function(d) {
                    return d.name;
                }).style("fill-opacity", 0);
    
                // phantom node to give us mouseover in a radius around it
                nodeEnter.append("circle").attr('class', 'ghostCircle').attr("r", 30).attr("opacity", 0.2) // change
                // this
                // to zero to
                // hide the
                // target area
                .style("fill", "red").attr('pointer-events', 'mouseover').on("mouseover", function(node) {
                    overCircle(node);
                }).on("mouseout", function(node) {
                    outCircle(node);
                });
    
                // Update the text to reflect whether node has children or
                // not.
                node.select('text').attr("x", function(d) {
                    return d.children || d._children ? -10 : 10;
                }).attr("text-anchor", function(d) {
                    return d.children || d._children ? "end" : "start";
                }).text(function(d) {
                    return d.name;
                });
    
                // Change the circle fill depending on whether it has
                // children and is collapsed
                node.select("circle.nodeCircle").attr("r", 4.5).style("fill", function(d) {
                    return d._children ? "lightsteelblue" : "#fff";
                });
    
                // Transition nodes to their new position.
                var nodeUpdate = node.transition().duration(duration).attr("transform", function(d) {
                    return "translate(" + (d.x - 8) + "," + -d.y + ")";
                });
    
                // Fade the text in
                nodeUpdate.select("text").style("fill-opacity", 1);
    
                // Transition exiting nodes to the parent's new position.
                var nodeExit = node.exit().transition().duration(duration).attr("transform", function(d) {
                    return "translate(" + source.y + "," + source.x + ")";
                }).remove();
    
                nodeExit.select("circle").attr("r", 0);
    
                nodeExit.select("text").style("fill-opacity", 0);
    
                // Update the links…
                var link = svgGroup.selectAll("path.link").data(links, function(d) {
                    return d.target.id;
                });
    
                // Enter any new links at the parent's previous position.
                link.enter().insert("path", "g").attr("class", "link").attr("stroke-dasharray", function(d) {
                    return (d.source.parent) ? "6,6" : "1,0";
                }).attr("d", function(d) {
                    var o = {
                        x : source.x0,
                        y : source.y0
                    };
                    return diagonal({
                        source : o,
                        target : o
                    });
                });
    
                // Transition links to their new position.
                link.transition().duration(duration).attr("d", diagonal);
    
                // Transition exiting nodes to the parent's new position.
                link.exit().transition().duration(duration).attr("d", function(d) {
                    var o = {
                        x : source.x,
                        y : source.y
                    };
                    return diagonal({
                        source : o,
                        target : o
                    });
                }).remove();
    
                // Stash the old positions for transition.
                nodes.forEach(function(d) {
                    d.x0 = d.x;
                    d.y0 = d.y;
                });
            }
    
            // Append a group which holds all nodes and which the zoom
            // Listener can act upon.
    
            var svgGroup = baseSvg.append("g");
    
            // Define the root
            root = treeData;
            root.x0 = viewerHeight / 2;
            root.y0 = 0;
    
            // Layout the tree initially and center on the root node.
            update(root);
            centerNode(root);
            addLoadSLAButtons();
    
        });
    
        function addLoadSLAButtons() {
            var slaDiv = document.createElement("div");
            slaDiv.setAttribute("id", "slaDiv");
            slaDiv.style.position = "relative";
            slaDiv.style.left = "35px";
            slaDiv.style.top = "-250px";
            slaDiv.style.width = "100px";
    
            var slaButton = document.createElement("input");
            slaButton.setAttribute("type", "button");
            slaButton.setAttribute("value", "View/Modify ServiceContract");
            slaButton.setAttribute("class", "btn btn-info");
            slaButton.setAttribute("id", "addSla");
            slaButton.style.position = "absolute";
            slaButton.setAttribute("onclick", "");// this will be modified once we
            // receive clarification on the
            // functionality.
    
            document.getElementById("tree-container").appendChild(slaDiv);
            document.getElementById("slaDiv").appendChild(slaButton);
    
            var relDiv = document.createElement("div");
            relDiv.setAttribute("id", "relDiv");
            relDiv.style.position = "relative";
            relDiv.style.left = "35px";
            relDiv.style.top = "-190px";
            relDiv.style.width = "100px";
    
            var loadButton = document.createElement("input");
            loadButton.setAttribute("type", "button");
            loadButton.setAttribute("value", "Add Load");
            loadButton.setAttribute("class", "btn btn-cust-info");
            loadButton.setAttribute("id", "addload");
            loadButton.style.position = "absolute";
            loadButton.style.align = "left";
    
            loadButton.setAttribute("onclick", ""); // reLoadPage()
    
            document.getElementById("tree-container").appendChild(relDiv);
            document.getElementById("relDiv").appendChild(loadButton);
    
        }
    
  • VividD
    VividD over 10 years
    I have another answer for you, let me just prepare jsfiddle.
  • javalearner
    javalearner over 10 years
    hi Vivid,after adding the above code ,second level nodes are not getting re-arranged after collapsing them,first level childs are getting re-arranged as usually..any suggestions for this?
  • VividD
    VividD over 10 years
    I am not sure, I have to take a look at your exact code. Maybe you put another question? Or @Manoj caould help?
  • javalearner
    javalearner over 10 years
    hi VividD ,can you let us know ,how to make childrens invisible.so that i will follow your previous approach
  • javalearner
    javalearner over 10 years
    updated the latest tree layout where i am geting extra child on right side with a circle
  • VividD
    VividD over 10 years
    Similar as you did for dashed links. I would create two new classes and styles, node_invisible, and link_invisible, both with "display: none", which would mean invisible. Than in the area of code that you changed for dashed lines, there should be some modification that examines if the link should be invisible, and if yes, assign its class to link_invisible. The same for nodes. One problem is how to "mark"nodes that should be invisible. Maybe with some special string. Anyway, this method is good as a practice, but it looks to me that the second method with "separation()" is the way to go.
  • javalearner
    javalearner about 10 years
    Hi vividD,i have posted the code which is used for tree layout.child nodes are not getting aligned together when collapsed after using separate method.could you plz help me out of this
  • VividD
    VividD about 10 years
    Hi, javalearner, can you put somewhere file network.json, so that I can see the file structure, try your code, etc....?
  • user588324
    user588324 about 10 years
    I am getting error Uncaught TypeError: Cannot set property 'x0' of undefined for line root.x0 = viewerHeight / 2;. root is root = treeData; Not sure what will be treeData here. Can you please help why I am getting this error on above line?