特定深度的d3群集布局节点未对齐

时间:2018-09-05 22:04:09

标签: d3.js svg hierarchical-clustering

我有以下JSFiddle代码:

http://jsfiddle.net/s4Mjx/27/

我希望class A{ public B body { get; set; } } class B{ public List<C> positions { get; set; } } class C{ public string NameOfWeek { get; set; } } class week{ public int ID { get; set; } public string NameOfWeek { get; set; } } class SomeX{ public List<A> MapWeekID(List<week> weekList, List<A> AList) { foreach (var a in AList) { foreach (var position in a.body.positions) { position.NameOfWeek = weekList .Where(x => x.NameOfWeek.ToString() == position.NameOfWeek) .Select(y => y.NameOfWeek) .FirstOrDefault(); } } return AList; } } node2在相同深度处垂直对齐。

我也希望所有叶节点也要对齐。

但是,此代码仅对齐叶节点,其余节点处于不同级别。

1 个答案:

答案 0 :(得分:1)

最简单的方法是使用树布局,它将节点depth对齐,然后将叶节点移动到最大深度的位置。

var root = getData();
var nodes = tree.nodes(root);
var links = tree.links(nodes);
var maxY = d3.max(nodes, d => d.y);
var linkSources = new Set(links.map(d => d.source.name));
nodes.forEach( d => { if (!linkSources.has(d.name)) { d.y = maxY; } });

完整的示例:

var width = 500,
    height = 500;
var diameter = 300;
var duration = 2000;

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

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

var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height)
    .append("g")
    .attr("transform", "translate(80,0)");

    var root = getData();
    var nodes = tree.nodes(root);
    var links = tree.links(nodes);
    var maxY = d3.max(nodes, d => d.y);
    var linkSources = new Set(links.map(d => d.source.name));
    nodes.forEach( d => { if (!linkSources.has(d.name)) { d.y = maxY; } });

    var link = svg.selectAll(".link")
        .data(links)
       .enter()
        .append("path")
        .attr("class", "link")
        .style("stroke", "#8da0cb")
        .attr("d", diagonal);

    var node = svg.selectAll(".node")
        .data(nodes)
       .enter()
        .append("g")
        .attr("class", "node")
        .attr("transform", function (d) {
        return "translate(" + d.y + "," + d.x + ")";
    })

    node.append("circle")
        .attr("r", 4.5);

    node.append("text")
        .attr("dx", function (d) { return d.children ? -8 : 8; })
        .attr("dy", 3)
        .style("text-anchor", function (d) { return d.children ? "end" : "start"; })
        .text(function (d) { return d.name; });

function getData() {
    return {
       name: "node1",
       id: "1",
       children: [
         {
            name: "node2",
            id: "2",
            children: [
            	{
              	name: "node5",
            		id: "5",
                children: [
                {
                  name: "node6",
                  id: "6",
                   children: [
                {
                  name: "node7",
                  id: "7",
                  
                }
            ]
                }
            ]
              }
            ]
         },
         {
            name: "node3",
            id: "3",
             children: [
                {
                  name: "node8",
                  id: "8",
                }
            ]
         },
         {
            name: "node4",
            id: "4",
         }
       ]
    };
}
.node circle {
    fill: #fff;
    stroke: steelblue;
    stroke-width: 1.5px;
}
.node {
    font: 10px sans-serif;
}
.link {
    fill: none;
    stroke: tan;
    stroke-width: 1.5px;
}
<script type="text/javascript" src="https://d3js.org/d3.v3.js"></script>

现在出现了另一个问题。排序路径。这是一个完全不同的球类游戏,因为您必须根据直到叶子节点的深度数来进行递归操作。


也可以使用集群布局来完成。

找到每个深度的最小值y并调整节点的位置(如果它是来源)

var root = getData(),
    nodes = cluster.nodes(root),
    links = cluster.links(nodes);
var depthMinY = {};
nodes.forEach( d => { if (!depthMinY[d.depth]) { depthMinY[d.depth] = d.y;}
                      depthMinY[d.depth] = Math.min(depthMinY[d.depth], d.y);});
var linkSources = new Set(links.map(d => d.source.name));
nodes.forEach( d => { if (linkSources.has(d.name)) { d.y = depthMinY[d.depth]; } });

完整的示例:

var width = 500,
    height = 500;
var diameter = 300;
var duration = 2000;

var cluster = d3.layout.cluster()
    .size([height, width - 160]);

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

var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height)
    .append("g")
    .attr("transform", "translate(80,0)");

    var root = getData(),
        nodes = cluster.nodes(root),
        links = cluster.links(nodes);
    var depthMinY = {};
    nodes.forEach( d => { if (!depthMinY[d.depth]) { depthMinY[d.depth] = d.y;}
                          depthMinY[d.depth] = Math.min(depthMinY[d.depth], d.y);});
    var linkSources = new Set(links.map(d => d.source.name));
    nodes.forEach( d => { if (linkSources.has(d.name)) { d.y = depthMinY[d.depth]; } });
    
    var link = svg.selectAll(".link")
        .data(links)
       .enter()
        .append("path")
        .attr("class", "link")
        .style("stroke", "#8da0cb")
        .attr("d", diagonal);

    var node = svg.selectAll(".node")
        .data(nodes)
       .enter()
        .append("g")
        .attr("class", "node")
        .attr("transform", function (d) {
        return "translate(" + d.y + "," + d.x + ")";
    })

    node.append("circle")
        .attr("r", 4.5);

    node.append("text")
        .attr("dx", function (d) { return d.children ? -8 : 8; })
        .attr("dy", 3)
        .style("text-anchor", function (d) { return d.children ? "end" : "start"; })
        .text(function (d) { return d.name; });


function getData() {
    return {
       name: "node1",
       id: "1",
       children: [
         {
            name: "node2",
            id: "2",
            children: [
            	{
              	name: "node5",
            		id: "5",
                children: [
                {
                  name: "node6",
                  id: "6",
                   children: [
                {
                  name: "node7",
                  id: "7",
                  
                }
            ]
                }
            ]
              }
            ]
         },
         {
            name: "node3",
            id: "3",
             children: [
                {
                  name: "node8",
                  id: "8",
             children: [
                {
                  name: "node9",
                  id: "9",
                }
                 ] 
                }
            ]
         },
         {
            name: "node4",
            id: "4",
         }
       ]
    };
}
.node circle {
    fill: #fff;
    stroke: steelblue;
    stroke-width: 1.5px;
}
.node {
    font: 10px sans-serif;
}
.link {
    fill: none;
    stroke: tan;
    stroke-width: 1.5px;
}
<script type="text/javascript" src="https://d3js.org/d3.v3.js"></script>