javascript 增加我的 D3 树布局的节点之间的差距

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20797521/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 19:19:56  来源:igfitidea点击:

Increasing gap between nodes of my D3 tree layout

javascriptsvgd3.jstreehierarchy

提问by javalearner

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?

有没有办法在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();

这是代码,我用于构建树布局,当我使用separate()时,树布局的子节点在空间中没有对齐,它们粘在它们的位置,没有单独的方法,折叠的子节点将被包裹在一起/ 对齐空间 /** * */ 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);

    }

回答by VividD

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())

更好的方法是使用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)

下图是没有调用separation()的代码行的树:(我在前面的例子中添加了节点AA和ZZ,还有BB和CC,但这些节点至少在这种情况下显示OK)

enter image description here

在此处输入图片说明

... and here with that line:

...这里是那一行:

enter image description here

在此处输入图片说明

Live jsfiddles:

现场 jsfiddles:

hereand here

这里这里

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

只是为了笑,我进一步修改了从“? 3 : 1; })”到“ ? 5 : .6; })”的行,我得到了:

enter image description here

在此处输入图片说明

回答by VividD

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.

这里的问题是节点的位置是通过d3.js中的所谓Reingold-Tilford算法自动计算的,需要大量的知识来内部修改算法,或者使用其他算法。但是一些像我描述的那样调整的解决方案是可能的。