2016-10-02 100 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