D3树布局 - 具有子节点的子节点之间的距离

时间:2014-01-15 19:23:29

标签: javascript d3.js

尝试在D3中获取树布局,以使子节点与子节点更加靠近。这是代码:

var margin = {
            top: 20,
            right: 120,
            bottom: 20,
            left: 120
    },
    width = 960 - margin.right - margin.left,
    height = 800 - margin.top - margin.bottom;

    var i = 0,
            duration = 750,
            rectW = 185,
            rectH = 45;

    var tree = d3.layout.tree()
        .nodeSize([200, 40]);

    var diagonal = d3.svg.diagonal()
        .projection(function (d) {
        return [d.x + rectW / 2, d.y + rectH / 2];
    });

    var svg = d3.select("#body").append("svg").attr("width", 1000).attr("height", 1000)
        .call(zm = d3.behavior.zoom().scaleExtent([0,1]).on("zoom", redraw))
        .append("g")
        .attr("transform", "translate(" + 30 + "," + 20 + ")");

    //necessary so that zoom knows where to zoom and unzoom from
    zm.translate([350, 20]);

    root.x0 = width / 2;
    root.y0 = 0;

    update(root);

    d3.select("#body").style("height", "800px");

    function update(source) {

        // Compute the new tree layout.
        var nodes = tree.nodes(root).reverse(),
            links = tree.links(nodes);


        // Normalize for fixed-depth.
        nodes.forEach(function (d) {
            d.y = (d.depth * 120);
        });

        // Update the nodes…
        var node = svg.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")
            .attr("class", "node")
            .attr("transform", function (d) {
                return "translate(" + source.x0 + "," + source.y0 + ")";
            })
            .on("click", click);

        // Add rectangles to nodes
        nodeEnter.append("rect")
            .attr("width", function (d) {                   
                return rectW;
                //return d._children ? "lightsteelblue" : "#fff";
            })
            .attr("height", rectH)
            .attr("class", function (d) {
                return "rect-" + d.state;
            });

        // Add text to nodes
        nodeEnter.append("text")
            .attr("x", rectW / 2)
            .attr("y", rectH / 2)
            .attr("dy", ".35em")
            .attr("text-anchor", "middle")
            .text(function (d) {
                return d.name;
            });

        // Transition nodes to their new position.
        var nodeUpdate = node.transition()
            .duration(duration)
            .attr("transform", function (d) {
                return "translate(" + d.x + "," + d.y + ")";
            });

        nodeUpdate.select("rect")
            .attr("width", rectW)
            .attr("height", rectH)
            .attr("class", function (d) {
                return "rect-" + d.state;
            });

        nodeUpdate.select("text")
            .style("fill-opacity", 1);

        // Update the links…
        var link = svg.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", function (d) {
                return "link " + d.target.dest;
            })
            .attr("x", rectW / 2)
            .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();


        // Update the link labels…
        var linkLabel = svg.selectAll("text.link-label")
            .data(links, function (d) {
                return d.target.id;
            });

        // Enter any new links at the parent's previous position.
        linkLabel.enter().insert("text", "path")
            .text(function (d) {
                return (d.target.state !== "open") ? null : "If " + d.target.dest;
            })
            .attr("class", function (d) {
                return "link-label " + d.target.dest;
            })
            .attr("x",  function (d) {
                return d.target.x + rectW / 2;
            })
            .attr("y", function (d) {
                return d.target.y + rectH * 2 - 30;
            })              
            .attr('text-anchor', 'middle')
            .style("fill-opacity", 0);;

        // Transition link labels
        linkLabel.transition()
            .delay(duration)
            .style("fill-opacity", 1);


        // Stash the old positions for transition.
        nodes.forEach(function (d) {
            d.x0 = d.x;
            d.y0 = d.y;
        });
    }

    // Toggle children on click.
    function click(d) {
        return false;
        if (d.children) {
            d._children = d.children;
            d.children = null;
        } else {
            d.children = d._children;
            d._children = null;
        }
        update(d);
    }

    //Redraw for zoom
    function redraw() {
        //console.log("here", d3.event.translate, d3.event.scale);
        svg.attr("transform",
            "translate(" + d3.event.translate + ")"
            + " scale(" + d3.event.scale + ")");
    }

Here is a jsbin上述代码。我希望看到的是海军色的“节点1”和“节点2”更接近,同时保留没有子节点的节点之间的距离(灰色节点)。

这可能,我该怎么做?

1 个答案:

答案 0 :(得分:6)

我找到了答案。这是分离方法。这让我得到了我想要的东西:

tree.separation(function separation(a, b) {
            return a.parent == b.parent ? 1 : 1.5;
        });