2015-05-28 86 views
3

我有一個d3強制指導佈局,數據的結構如下。是否可以對其應用可摺疊力佈局(如http://bl.ocks.org/mbostock/1062288)?我希望節點在點擊時摺疊/展開。如何創建d3.js具有非樹數據的可摺疊的力佈局?

{ 
    "nodes": [ 
    {"x": 469, "y": 410}, 
    {"x": 493, "y": 364}, 
    {"x": 442, "y": 365}, 
    {"x": 467, "y": 314}, 
    ], 
    "links": [ 
    {"source": 0, "target": 1}, 
    {"source": 1, "target": 2}, 
    {"source": 2, "target": 0}, 
    {"source": 1, "target": 3}, 
    {"source": 3, "target": 2}, 
    ] 
} 

回答

0

試試這個:

var width = 960,height = 500; 

    var force = d3.layout.force().size([width, height]).charge(-400) 
       .linkDistance(40) 
       .on("tick", tick); 

     var drag = force.drag().on("dragstart", dragstart); 

      var svg = d3.select("body").append("svg").attr("width", width) 
         .attr("height", height); 

      var link = svg.selectAll(".link"), 
        node = svg.selectAll(".node"); 

      d3.json("graph.json", function(error, graph) { 
        force.nodes(graph.nodes).links(graph.links) 
         .start(); 

     link = link.data(graph.links).enter().append("line") 
         .attr("class", "link"); 

        node = node.data(graph.nodes) 
       .enter().append("circle") 
       .attr("class", "node") 
       .attr("r", 12) 
       .call(drag); 
     }); 

     function tick() { 
       link.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; }); 
      } 



      function dragstart(d) { 
        d3.select(this).classed("fixed", d.fixed = true); 
       } 

您應使用JSON文件是這樣的:

graph.json

 { 
     "nodes": [ 
     {"x": 469, "y": 410}, 
     {"x": 493, "y": 364}, 
     {"x": 442, "y": 365}, 
     {"x": 467, "y": 314}, 
    ], 
     "links": [ 
      {"source": 0, "target": 1}, 
      {"source": 1, "target": 2}, 
      {"source": 2, "target": 0}, 
      {"source": 1, "target": 3}, 
      {"source": 3, "target": 2}, 
     ] 
    } 
+0

謝謝您的回答,但我正在尋找在點擊摺疊和展開的節點。 –

+0

你在找這樣的節點嗎? (http://bl.ocks.org/mbostock/4339083) – Gabriel

+0

更喜歡[http://bl.ocks.org/mbostock/1062288](http://bl.ocks.org/mbostock/1062288),但我的json的定義不同。 –

2

如果我理解正確的,也許這就是你尋找。我編輯了你鏈接到的演示。現在,當源節點摺疊時,我們遍歷所有邊,並查找它有邊的其他節點。

對於源節點有邊的每個目標節點,我們增加它的摺疊計數。如果某個節點的摺疊計數大於零,則不會顯示該摺疊計數。

當我們收縮一個節點時,我們做同樣的事情,除了我們從收縮計數遞減。

我們需要這個摺疊計數,因爲我們不在樹中,節點可能有多個節點會導致它們崩潰。

我對定向圖做了這項工作,但我不確定那是你想要的。

讓我知道你在想什麼!

的JSON我使用:

{ 
    "nodes": [ 
    {"x": 469, "y": 410}, 
    {"x": 493, "y": 364}, 
    {"x": 442, "y": 365}, 
    {"x": 467, "y": 314} 
], 
    "links": [ 
     {"source": 0, "target": 1}, 
     {"source": 1, "target": 2}, 
     {"source": 2, "target": 0}, 
     {"source": 1, "target": 3}, 
     {"source": 3, "target": 2} 
    ] 
} 

修改教程代碼:

<!DOCTYPE html> 
<meta charset="utf-8"> 
<title>Force-Directed Graph</title> 
<style> 

.node { 
    cursor: pointer; 
    stroke: #3182bd; 
    stroke-width: 1.5px; 
} 

.link { 
    fill: none; 
    stroke: #9ecae1; 
    stroke-width: 1.5px; 
} 

</style> 
<body> 
<script src="http://d3js.org/d3.v3.min.js"></script> 
<script> 

var width = 960, 
    height = 500, 
    root; 

var force = d3.layout.force() 
    .size([width, height]) 
    .on("tick", tick); 

var svg = d3.select("body").append("svg") 
    .attr("width", width) 
    .attr("height", height); 

//Added markers to indicate that this is a directed graph 
svg.append("defs").selectAll("marker") 
    .data(["arrow"]) 
    .enter().append("marker") 
    .attr("id", function(d) { return d; }) 
    .attr("viewBox", "0 -5 10 10") 
    .attr("refX", 15) 
    .attr("refY", -1.5) 
    .attr("markerWidth", 4) 
    .attr("markerHeight", 4) 
    .attr("orient", "auto") 
    .append("path") 
    .attr("d", "M0,-5L10,0L0,5"); 

var link = svg.selectAll(".link"), 
    node = svg.selectAll(".node"); 

d3.json("graph.json", function(json) { 
    root = json; 
    //Give nodes ids and initialize variables 
    for(var i=0; i<root.nodes.length; i++) { 
    var node = root.nodes[i]; 
    node.id = i; 
    node.collapsing = 0; 
    node.collapsed = false; 
    } 
    //Give links ids and initialize variables 
    for(var i=0; i<root.links.length; i++) { 
    var link = root.links[i]; 
    link.source = root.nodes[link.source]; 
    link.target = root.nodes[link.target]; 
    link.id = i; 
    } 

    update(); 
}); 

function update() { 
    //Keep only the visible nodes 
    var nodes = root.nodes.filter(function(d) { 
    return d.collapsing == 0; 
    }); 
    var links = root.links; 
    //Keep only the visible links 
    links = root.links.filter(function(d) { 
    return d.source.collapsing == 0 && d.target.collapsing == 0; 
    }); 

    force 
     .nodes(nodes) 
     .links(links) 
     .start(); 

    // Update the links… 
    link = link.data(links, function(d) { return d.id; }); 

    // Exit any old links. 
    link.exit().remove(); 

    // Enter any new links. 
    link.enter().insert("line", ".node") 
     .attr("class", "link") 
     .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; }) 
     .attr("marker-end", "url(#arrow)"); 

    // Update the nodes… 
    node = node.data(nodes, function(d){ return d.id; }).style("fill", color); 

    // Exit any old nodes. 
    node.exit().remove(); 

    // Enter any new nodes. 
    node.enter().append("circle") 
     .attr("class", "node") 
     .attr("cx", function(d) { return d.x; }) 
     .attr("cy", function(d) { return d.y; }) 
     .attr("r", function(d) { return Math.sqrt(d.size)/10 || 4.5; }) 
     .style("fill", color) 
     .on("click", click) 
     .call(force.drag); 
} 

function tick() { 
    link.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; }); 
} 

// Color leaf nodes orange, and packages white or blue. 
function color(d) { 
    return d.collapsed ? "#3182bd" : d.children ? "#c6dbef" : "#fd8d3c"; 
} 

// Toggle children on click. 
function click(d) { 
    if (!d3.event.defaultPrevented) { 
    //check if link is from this node, and if so, collapse 
    root.links.forEach(function(l) { 
     if(l.source.id == d.id) { 
     if(d.collapsed){ 
      l.target.collapsing--; 
     } else { 
      l.target.collapsing++; 
     } 
     } 
    }); 
    d.collapsed = !d.collapsed; 
    } 
    update(); 
} 

</script> 
+1

感謝您的代碼。它按預期工作。在這裏額外的需求,我需要鏈接節點的節點的ID而不是索引下面的這個例子[http://stackoverflow.com/questions/23986466/d3-force-layout-linking-nodes-by-na me -instead-的指數](ME-代替-的折射率http://stackoverflow.com/questions/23986466/d3-force-layout-linking-nodes-by-na)。此外,我想讓它們與svg框綁定並向節點添加文本。我應該如何修改代碼? –

+0

@ CY-你有沒有找到這個答案? – Mcestone

+0

有誰知道如何爲d3.js v4做到這一點? – deathlock