2016-10-02 182 views
1

让我首先说明我对D3和Javascript是全新的。通过一点点实验,我试图开发一个Tree Like结构,节点可以有多个父母。D3图形布局 - 具有多个父级的树结构

输入:

的Json与节点链接信息一样,

var graph = { 
    "nodes": [ { "id" : 0}, 
       { "id" : 1}, 
       { "id" : 2}, 
       { "id" : 3}, 
       { "id" : 4}, 
       { "id" : 5} 
      ], 
    "links": [ { "target": 5, "source": 1 }, 
       { "target": 2, "source": 0 }, 
       { "target": 3, "source": 4 }, 
       { "target": 1, "source": 2}, 
       { "target": 1, "source": 0 }, 

      ] 
    }; 

注:这只是参考,因为我怎么有数据,也可能是数千节点。

输出:

我要像树结构的输出,有点像this,如说的节点必须等与根是在顶部和相同的水平结构的深度/水平被绘制节点以这样的方式排列以最小化链路重叠。

编辑:上面提供的输入输出是this假设零是根。

问题,我面对:

  1. 由于我只给节点及其来源&目标,而不是它们的坐标,我经历了整个列表解析计算的水平,然后除以基于高度在那个级别上,然后绘制节点。处理这类问题的最有效方法是什么?我应该深入研究算法解决方案吗?

或者

  • 是否有D3一些图表描绘函数,它接受这个JSON作为输入并执行该作业的其余部分?
  • 请不说,节点可以有多个父和我在这里主要焦点正密谋在适当/等级秩序这些节点的,所以我现在面临的主要问题是计算X/Y坐标的所有节点只给出如上所述的输入。

    请帮我更好的理解这个话题,谢谢。

    +0

    我无法弄清楚你的预期输出。 **假设零**是根节点,它会[看起来像这样](http://imgur.com/a/FZCrP)。由于父母/子女关系失败,3到4会消失...这是您的预期产出吗? – Mark

    +0

    @Mark实际上,输入只是作为输入的参考,它可能包含数千个节点,例外的输出不管是哪个根节点应该出现在顶部,然后是它的子节点等等最小链路重叠。希望我能够解释我自己;) – Mohit

    +0

    但是,我的图是预期的输出给你的样本数据? – Mark

    回答

    2

    一直在思考这个问题。使用内置的d3构造,我认为this就像您将要获得的一样近。我已经采取了你的数据,并将其转换为一个版本4例如:

    <!DOCTYPE html> 
     
    <meta charset="utf-8"> 
     
    <style> 
     
        .links line { 
     
        stroke: #aaa; 
     
        stroke-width: 5px; 
     
        } 
     
        
     
        .nodes circle { 
     
        pointer-events: all; 
     
        stroke: none; 
     
        } 
     
    </style> 
     
    <svg width="600" height="300"></svg> 
     
    <script src="https://d3js.org/d3.v4.min.js"></script> 
     
    <script> 
     
        var svg = d3.select("svg"), 
     
        width = +svg.attr("width"), 
     
        height = +svg.attr("height"); 
     
    
     
        var simulation = d3.forceSimulation() 
     
        .force("link", d3.forceLink().id(function(d) { 
     
         return d.id; 
     
        })) 
     
        .force("charge", d3.forceManyBody()) 
     
        .force("center", d3.forceCenter(width/2, height/2)) 
     
        .force("y", d3.forceY()) 
     
    
     
        var graph = { 
     
        "nodes": [{ 
     
         "id": 0 
     
        }, { 
     
         "id": 1 
     
        }, { 
     
         "id": 2 
     
        }, { 
     
         "id": 3 
     
        }, { 
     
         "id": 4 
     
        }, { 
     
         "id": 5 
     
        }], 
     
        "links": [{ 
     
         "target": 5, 
     
         "source": 1 
     
         }, { 
     
         "target": 2, 
     
         "source": 0 
     
         }, { 
     
         "target": 3, 
     
         "source": 4 
     
         }, { 
     
         "target": 1, 
     
         "source": 2 
     
         }, { 
     
         "target": 1, 
     
         "source": 0 
     
         }, 
     
    
     
        ] 
     
        }; 
     
    
     
        var link = svg.append("g") 
     
        .attr("class", "links") 
     
        .selectAll("line") 
     
        .data(graph.links) 
     
        .enter().append("line"); 
     
    
     
        var node = svg.append("g") 
     
        .attr("class", "nodes") 
     
        .selectAll("circle") 
     
        .data(graph.nodes) 
     
        .enter().append("circle") 
     
        .attr("r", 10); 
     
    
     
        node.append("title") 
     
        .text(function(d) { 
     
         return d.id; 
     
        }); 
     
    
     
        simulation 
     
        .nodes(graph.nodes) 
     
        .on("tick", ticked); 
     
    
     
        simulation.force("link") 
     
        .links(graph.links); 
     
    
     
        function ticked() { 
     
    
     
        var k = 6 * simulation.alpha(); 
     
    
     
        // Push sources up and targets down to form a weak tree. 
     
        link 
     
         .each(function(d) { 
     
         d.source.y -= k, d.target.y += k; 
     
         }) 
     
         .attr("x1", function(d) { 
     
         return d.source.x; 
     
         }) 
     
         .attr("y1", function(d) { 
     
         return d.source.y; 
     
         }) 
     
         .attr("x2", function(d) { 
     
         return d.target.x; 
     
         }) 
     
         .attr("y2", function(d) { 
     
         return d.target.y; 
     
         }); 
     
    
     
        node 
     
         .attr("cx", function(d) { 
     
         return d.x; 
     
         }) 
     
         .attr("cy", function(d) { 
     
         return d.y; 
     
         }); 
     
    
     
        } 
     
    </script>

    如果你不想运动和解决的效果,你可以预先计算的布局,使它static


    我也尝试用你的数据转换为分层格式为使用d3.tree但没有多少运气复制你的形象:

    <!DOCTYPE html> 
     
    <meta charset="utf-8"> 
     
    <style> 
     
        .node circle { 
     
        fill: #999; 
     
        } 
     
        
     
        .node text { 
     
        font: 10px sans-serif; 
     
        } 
     
        
     
        .node--internal circle { 
     
        fill: #555; 
     
        } 
     
        
     
        .node--internal text { 
     
        text-shadow: 0 1px 0 #fff, 0 -1px 0 #fff, 1px 0 0 #fff, -1px 0 0 #fff; 
     
        } 
     
        
     
        .link { 
     
        fill: none; 
     
        stroke: #555; 
     
        stroke-opacity: 0.4; 
     
        stroke-width: 1.5px; 
     
        } 
     
    </style> 
     
    <svg width="300" height="300"></svg> 
     
    <script src="//d3js.org/d3.v4.min.js"></script> 
     
    <script> 
     
        var graph = { 
     
        "nodes": [{ 
     
         "id": 0 
     
        }, { 
     
         "id": 1 
     
        }, { 
     
         "id": 2 
     
        }, { 
     
         "id": 3 
     
        }, { 
     
         "id": 4 
     
        }, { 
     
         "id": 5 
     
        }], 
     
        "links": [{ 
     
         "target": 5, 
     
         "source": 1 
     
        },{ 
     
         "target": 2, 
     
         "source": 0 
     
        }, { 
     
         "target": 3, 
     
         "source": 4 
     
        }, { 
     
         "target": 1, 
     
         "source": 2 
     
        }, { 
     
         "target": 1, 
     
         "source": 0 
     
        }] 
     
        }; 
     
    
     
        var root = { 
     
        id: 0, 
     
        data: graph.nodes[0], 
     
        children: [] 
     
        } 
     
    
     
        function recurChild(obj) { 
     
        graph.links.forEach(function(d) { 
     
         if (d.source === obj.id) { 
     
         var c = { 
     
          id: d.target, 
     
          data: graph.nodes[d.target], 
     
          children: [] 
     
         }; 
     
         obj.children.push(c); 
     
         recurChild(c); 
     
         } 
     
        }); 
     
        } 
     
        recurChild(root); 
     
    
     
        root = d3.hierarchy(root); 
     
    
     
        var svg = d3.select("svg"), 
     
        width = +svg.attr("width"), 
     
        height = +svg.attr("height"), 
     
        g = svg.append("g").attr("transform", "translate(40,0)"); 
     
    
     
        var tree = d3.tree() 
     
        .size([height, width - 160]); 
     
    
     
        tree(root); 
     
        
     
        console.log(root.descendants()) 
     
    
     
        var link = g.selectAll(".link") 
     
        .data(root.descendants().slice(1)) 
     
        .enter().append("path") 
     
        .attr("class", "link") 
     
        .attr("d", function(d) { 
     
         return "M" + d.y + "," + d.x + "C" + (d.y + d.parent.y)/2 + "," + d.x + " " + (d.y + d.parent.y)/2 + "," + d.parent.x + " " + d.parent.y + "," + d.parent.x; 
     
        }); 
     
    
     
        var node = g.selectAll(".node") 
     
        .data(root.descendants()) 
     
        .enter().append("g") 
     
        .attr("class", function(d) { 
     
         return "node" + (d.children ? " node--internal" : " node--leaf"); 
     
        }) 
     
        .attr("transform", function(d) { 
     
         return "translate(" + d.y + "," + d.x + ")"; 
     
        }) 
     
    
     
        node.append("circle") 
     
        .attr("r", 2.5); 
     
    
     
        node.append("text") 
     
        .attr("dy", 3) 
     
        .attr("x", function(d) { 
     
         return d.children ? -8 : 8; 
     
        }) 
     
        .style("text-anchor", function(d) { 
     
         return d.children ? "end" : "start"; 
     
        }) 
     
        .text(function(d) { 
     
         return d.data.id; 
     
        }); 
     
    </script>

    d3.hierarchy真这意味着,没有多个父结构的直接层次结构。

    +0

    酷!它似乎适用于一小部分节点,让我试试更大的数目,将回传结果。 – Mohit

    +0

    我跟着你的链接强制定向树它更多的是我正在寻找的答案,但问题是与大数量的节点其种类成为一个群集....有没有办法为每个节点提供深度属性,像一级? – Mohit

    +0

    @Mohit,你有任何编码的例子吗?我试图用随机数据重新创建,但没有适当的父母/孩子结构,这是一团糟。在上面的代码'var k = 6 * simulation.alpha();'中,'6'是每个节点的强制距离。 – Mark