Svg 使用d3js,我如何使用树布局在父节点中直观地放置子节点?

Svg 使用d3js,我如何使用树布局在父节点中直观地放置子节点?,svg,d3.js,Svg,D3.js,我正在尝试使用d3js来绘制各个位置的服务器图。下面是输入数据的一个示例提取 {"type": "customer", "name": "Acme", "children": [ { "type": "site", "name": "Wichita", "children": [ { "type": "server", "name": "server1"

我正在尝试使用d3js来绘制各个位置的服务器图。下面是输入数据的一个示例提取

{"type": "customer", "name": "Acme", "children": [
    {
        "type": "site",
        "name": "Wichita",
        "children": [
            {
                "type": "server",
                "name": "server1"
            },
            {
                "type": "server",
                "name": "server2"
            }
        ]
    },
    {
        "type": "site",
        "name": "Springfield",
        "children": [
            {
                "type": "server",
                "name": "server1"
            },
            {
                "type": "server",
                "name": "server2"
            },
            {
                "type": "server",
                "name": "server3"
            }
        ]
    }
]}
这些站点将有不同数量的服务器。每个服务器都应该是代表站点的矩形中的一个矩形。 我可以分别创建站点和服务器矩形,但我想我希望服务器节点绑定在其父站点的矩形下 节点进行适当的分组,特别是我们以后将svg导入Visio时。输入json位于var treeData中。还有,我 在正确定位时遇到困难,通过适当的分组可能会更容易

var viz = d3.select("#viz").append("svg:svg")
    .attr("width", 1200)
    .attr("height", layoutHeight)
    .append("svg:g");

var tree = d3.layout.tree().size([layoutHeight, 300]);

var nodes = tree.nodes(treeData);

viz.append("svg:text")
    .attr("dx", "0")
    .attr("dy", 20)
    .attr("font-size", 24)
    .attr("text-anchor", "start")
    .text(json.customerName);

var siteNodes = viz.selectAll("g.node")
    .data(nodes)
    .enter().append("svg:g")
    .filter(function(d) { return d.type === "site" })
    .attr("transform", function(d) { return "translate(" + d.y + "," + (d.x * 1.5 - (d.children.length * serverHeight * 1.1 / 2)) + ")"; });

siteNodes.append("svg:rect")
    .attr("width", 300)
    .attr("height", function(d) { return serverHeight * (d.children.length + 1); })
    .attr("stroke", "black")
    .attr("stroke-width", "1")
    .attr("fill", "white");

var serverNodes = viz.selectAll("g.node")
    .data(nodes)
    .enter().append("svg:g")
    .filter(function(d) { return d.type === "server" })
    .attr("transform", function(d) { return "translate(" + (d.y - 125) + "," + d.x + ")"; });

serverNodes.append("svg:rect")
    .attr("width", 250)
    .attr("height", serverHeight)
    .attr("font-size", 10)
    .attr("stroke", "black")
    .attr("stroke-width", "1")
    .attr("fill-opacity", "0.1")
    .attr("fill", "blue");

我是d3js新手,我怀疑一个主要因素是我还没有以正确的方式思考d3js。

由于您没有提供完整的代码,我不得不对值进行一些假设。我所做的改变应该很容易理解。是帮助你摆脱困境的小提琴。我不清楚您在站点上使用的转换,我给出了一个近似值来让您继续。你肯定需要调整它。希望这有帮助

.attr("transform", function(d) { return "translate(" + (d.y) + "," + (d.x * 1.25 - (d.children.length * serverHeight * 0.9)) + ")"; });

以下是我在和的帮助下制定的解决方案:

我更改了数据中的一些字段名,使其看起来更像:

var treeData = {type: "customer", name: "Acme", children: [
    {type: "site", name: "Wichita", servers: [
        {type: "server", name: "server1", status: "Powered On"},
        {type: "server", name: "server2", status: "Powered On"}]},
    {type: "site", name: "Springfield", servers: [
        {type: "server", name: "server1", status: "Powered On"},
        {type: "server", name: "server2", status: "Powered On"},
        {type: "server", name: "server3", status: "Powered On"}]
    }
]};
计算布局所需的空间:

var serverHeight = 50;
var serverWidth = 250;

var siteWidth = serverWidth + 50;

var layoutVerticalOffset = 20;
var layoutHeight = 150 + (maxServerCount + 2) * serverHeight * 1.5;
var layoutWidth = treeData.children.length * siteWidth * 1.5;

var viz = d3.select("#viz").append("svg:svg")
    .attr("height", layoutHeight)
    .attr("width", layoutWidth + siteWidth)
    .append("svg:g");

var tree = d3.layout.tree().size([layoutWidth, 0]);
我向站点节点添加了一个类:

var siteNodes = viz.selectAll("g.node")
    .data(nodes)
    .enter().append("svg:g")
    .filter(function(d) { return d.type === "site" })
    .attr("class", "site")
    .attr("transform", function(d) {
        return "translate(" + d.x + "," + 100 + ")";
    });
<g class="site" transform="translate(300,35)">
    <rect width="300" height="165" stroke="black" stroke-width="1" fill="white"/>
    <text dx="0" dy="12" font-size="18" text-anchor="end">Site</text>
    <text dx="0" dy="34" font-size="18" text-anchor="end">Wichita</text>
    <g class="server" transform="translate(25,25)">
        <rect width="250" height="50" font-size="10" stroke="black" stroke-width="1" fill-opacity="0.1" fill="blue"/>
    </g>
    <g class="server" transform="translate(25,100)">
        <rect width="250" height="50" font-size="10" stroke="black" stroke-width="1" fill-opacity="0.1" fill="blue"/>
    </g>
</g>
并在构建服务器节点时使用该类进行选择:

var serverNodes = siteNodes.selectAll(".site")
    .data(function(d) { return d.servers; })
    .enter().append("svg:g")
    .attr("class", "server")
    .attr("transform", function(d, i) {
        return "translate(" + 25 + "," + (serverHeight / 2 + i * serverHeight * 1.5) + ")";
    });
结果是服务器由正确嵌套在站点节点中的g节点表示:

var siteNodes = viz.selectAll("g.node")
    .data(nodes)
    .enter().append("svg:g")
    .filter(function(d) { return d.type === "site" })
    .attr("class", "site")
    .attr("transform", function(d) {
        return "translate(" + d.x + "," + 100 + ")";
    });
<g class="site" transform="translate(300,35)">
    <rect width="300" height="165" stroke="black" stroke-width="1" fill="white"/>
    <text dx="0" dy="12" font-size="18" text-anchor="end">Site</text>
    <text dx="0" dy="34" font-size="18" text-anchor="end">Wichita</text>
    <g class="server" transform="translate(25,25)">
        <rect width="250" height="50" font-size="10" stroke="black" stroke-width="1" fill-opacity="0.1" fill="blue"/>
    </g>
    <g class="server" transform="translate(25,100)">
        <rect width="250" height="50" font-size="10" stroke="black" stroke-width="1" fill-opacity="0.1" fill="blue"/>
    </g>
</g>

场地
威奇托
这将形成适当的分组,这对导出非常重要,并通过使服务器图形与站点图形相对,简化了服务器图形的计算


谢谢您的回答,对于丢失的部分,我深表歉意。我在思考如何将子节点绑定到父节点。如果不是这样,我可以调整值,直到它们一致工作。在每个节点上由填充的属性之一是对父节点的引用。好的,我真正谈论的是发生在serverNodes.append()上的图形绑定,而不是发生在var nodes=tree.nodes(treeData);。