d3 树 <g> 标签 padding/border 整体样式

d3 tree <g> tag padding/border overall styling

所以我构建了一棵树,它将 collapse/expand 使用 d3 的库制作动画。我对 d3 还是很陌生,我不确定如何将我的特定样式添加到战斗中。关于如何设置 <g> 标签的样式有什么建议吗?

这是我想要的样子:

这是目前的样子:

相关代码如下:

<!DOCTYPE html>
<meta charset="utf-8">
<style>
    .node {
        cursor: pointer;
    }

    .node circle {
      fill: #fff;
      stroke: steelblue;
      stroke-width: 3px;
    }

    .node text {
      font: 12px sans-serif;
    }

    .link {
      fill: none;
      stroke: #ccc;
      stroke-width: 2px;
    }
</style>

<body>
    <script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
    <script src="//d3js.org/d3.v3.min.js"></script>
    <script>
        var margin = {
                top: 20,
                right: 120,
                bottom: 20,
                left: 120
            },
            width = $(window).width() - margin.right - margin.left,
            height = $(window).height() - margin.top - margin.bottom;

        var i = 0,
            duration = 750,
            root;

        var tree = d3.layout.tree()
            .size([height, width])

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

        buildJson(function (data) {
            var svg = d3.select("body").append("svg")
                .attr("width", width + margin.right + margin.left)
                .attr("height", height + margin.top + margin.bottom)
                .append("g")
                .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

            root = data;
            root.x0 = height / 2;
            root.y0 = 0;

            function collapse(d) {
                if (d.children) {
                    d._children = d.children;
                    d._children.forEach(collapse);
                    d.children = null;
                }
            }

            root.children.forEach(collapse);
            update(root);

            d3.select(self.frameElement).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 * 350;
                });

                // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                // 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.y0 + "," + source.x0 + ")";
                    })
                    .on("click", click);

                nodeEnter.append("circle")
                    .attr("r", 1e-6)
                    .style("fill", function(d) {
                        return d._children ? "lightsteelblue" : "#fff";
                    });

                nodeEnter.append("text")
                    .attr("x", function(d) {
                        return d.children || d._children ? -12 : 12;
                    })
                    .attr("dy", ".35em")
                    .attr("text-anchor", function(d) {
                        return d.children || d._children ? "end" : "start";
                    })
                    .text(function(d) {
                        return d.name;
                    })
                    .style("fill-opacity", 1e-6);

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

                nodeUpdate.select("circle")
                    .attr("r", 4.5)
                    .style("fill", function(d) {
                        return d._children ? "lightsteelblue" : "#fff";
                    });

                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", 1e-6);

                nodeExit.select("text")
                    .style("fill-opacity", 1e-6);

                // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                // 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", "link")
                    .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;
                });

                // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                // Remove Root Node, ultra mega important!!!
                // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                node.each(function(d){
                    if (d.name == "flare") 
                        d3.select(this).remove();});
                link.each(function(d){
                    if (d.source.name == "flare") 
                        d3.select(this).remove();});
            }

            // Toggle children on click.
            function click(d) {
                if (d.children) {
                    d._children = d.children;
                    d.children = null;
                }
                else {
                    d.children = d._children;
                    d._children = null;
                }
                // If the node has a parent, then collapse its child nodes
                // except for this clicked node.
                if (d.parent) {
                    d.parent.children.forEach(function(element) {
                        if (d !== element) {
                            collapse(element);
                        }
                    });
                }
                update(d);
            }

            function collapse(d) {
                if (d.children) {
                    d._children = d.children;
                    d._children.forEach(collapse);
                    d.children = null;
                }
            }

        });

        // Get Data and format it properly for presentation
       function getJsonData (pathToData, callback) {
            $.getJSON( pathToData, function() {
                console.log( "Retrieving: " + pathToData );
            }).done(function(data) {
                callback({
                    error: false,
                    data: data
                });
            })
            .fail(function() {
                callback({
                    error: true
                });
            });
        }

        function buildJson (builder) {
            var runOnce = true, categories_raw, technologies_raw, formatted_json = {
                'name' : 'flare', 
                'children' : []
            }

            //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
            // First get all of the categories and subcategories
            //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
            getJsonData('assets/json/categories.json', function (data) {
                if (!data.error) {
                    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                    // Categories and Subcategories Retreived now build it out
                    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                    categories_raw = data.data

                    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                    // Technologies retreived now build it out
                    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                    getJsonData('assets/json/technologies.json', function (data) {
                        if (!data.error) {
                            technologies_raw = data.data

                            var categories = categories_raw[0], subcategories = categories_raw[1], technologies = technologies_raw, formatted_categories = [], formatted_subcategories = [], formatted_technologies = []

                            subcategories.forEach ( function (value, index) {
                                formatted_subcategories.push({
                                    'name' : value.label,
                                    'id' : value.id,
                                    'children' : [],
                                    'parent' : value.parent
                                })
                            })

                            technologies.forEach ( function (value, index) {
                                var result = formatted_subcategories.filter(function( obj ) {
                                    return obj.id == value.subCat;
                                });

                                if (typeof result[0] != 'undefined') {
                                    result[0].children.push({
                                        'name' : value.label
                                    })
                                }
                            })

                            categories.forEach ( function (value, index) {
                                var result = formatted_subcategories.filter(function( obj ) {
                                    return obj.parent == value.id;
                                });

                                formatted_json.children.push({
                                    'name' : value.label,
                                    'id' : value.id,
                                    'children' : result
                                })
                            })

                            builder(formatted_json)
                        }
                    })
                }
            })
        }
    </script>

好吧,尽管这被否决了,但我仍然认为存在答案很重要。

https://gist.github.com/Quixomatic/f39d338bb4b4790d38f7d08b52f34b98

这个 link 指出了一个要点,显示了我对问题的解决方案。感谢帮助,没有人。