Узлы расположения кластера d3 на определенной глубине не выровнены - PullRequest
0 голосов
/ 06 сентября 2018

У меня есть следующий код JSFiddle:

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

Я хочу, чтобы node2 и node3 были выровнены по вертикали, поскольку они находятся на одинаковой глубине.

Я также хочу, чтобы все листовые узлы также были выровнены.

Однако этот код выравнивает только конечные узлы, а остальные узлы находятся на разных уровнях.

1 Ответ

0 голосов
/ 06 сентября 2018

Самым простым является использование макета дерева , он выравнивает узлы на 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>

Теперь возникает другая проблема.Сортировка путей.Это совершенно другая игра с мячом, потому что вы должны делать это рекурсивно в зависимости от количества глубин до конечного узла.

Это также можно сделать с помощью кластера .

Найдите минимальное значение для каждой глубины и отрегулируйте положение узла, если он является источником

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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...