2016-03-06 71 views
1

我試圖用d3js來創建一個樹形圖與兩個節點相互連接。我的JS如下:d3.js樹佈局是聚集在頂部

var width = window.innerWidth; 
var height = window.innerHeight; 

var nodes = [{"id":"1","name":"a"},{"id":"2","name":"b"}]; 
var links = [{"source":0,"target":1}]; 

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

var tree = d3.layout.tree(); 
tree.size([width, height]); 
tree.nodes(nodes); 
tree.links(links); 

var diagonal = d3.svg.diagonal.radial() 
    .projection(function(d) { return [d.y, d.x/180 * Math.PI]; }); 

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

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

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

    node.append("text") 
     .text(function(d) { return d.name; }); 

所以我設置SVG的寬度和高度等於窗口寬度/高度。然而,一切都集中在右上角。

我的JS小提琴:https://jsfiddle.net/eeLfog4m/1/

任何想法?

什麼是有益的是沒有所有的花裏胡哨的d3js演示。圍繞中心旋轉一切。 http://bl.ocks.org/d3noob/8375092似乎有很多額外的代碼來處理重繪/摺疊節點,而https://github.com/mbostock/d3/wiki/Tree-Layout根本沒有任何示例。

回答

2

您看到左上角所有東西都被擠壓的原因是因爲所有屬性都是NaNundefined。這是因爲你使用

.projection(function(d) { return [d.y, d.x/180 * Math.PI]; }); 

.attr("transform", function(d) { 
     return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; 
}); 

被訪問d.xd.y,這是不確定的。

理想情況下,d.xd.y由佈局算法生成,如d3.layout.tree()。但是,在您提供的代碼中,傳遞給樹佈局算法的數據不正確。

d3.tree.layout()期望一個分層的數據結構,而您提供鏈接和節點,如果沒有一些主要的解決方法,這將無法正常工作。如果你想使用樹型佈局,我建議你將你的數據轉換成分層結構,然後將其可視化。這裏是這樣做

var width = window.innerWidth; 
var height = window.innerHeight; 

var root = { 
"name": "1", 
"children": [ 
    {"name": "2"} 
] 
}; 

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

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

var nodes = tree.nodes(root); 
var links = tree.links(nodes); 

var path = d3.svg.line() 
    .x(function(d) { return d.x; }) 
    .y(function(d) { return d.y; }); 

    var link = svg.selectAll(".link") 
     .data(links) 
     .enter() 
     .append("path") 
     .attr("class", "link") 
     .attr("stroke", "black") 
     .attr("stroke-width", 2); 
     .attr("d", function(d){ 
     return path([d.source, d.target]) 
     }); 

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

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

    node.append("text") 
     .text(function(d) { return d.name; }); 

但是,如果你想堅持使用當前數據格式的例子:

var nodes = [{"id":"1","name":"a"},{"id":"2","name":"b"}]; 
var links = [{"source":0,"target":1}]; 

你應該使用力導向佈局。

下面是使用力導向佈局與數據結構的一個例子,你有(http://jsfiddle.net/ankit89/3kL11j6j/

var graph = { 
"nodes": [ 
    {"name": "Leo"}, 
    {"name": "Mike"}, 
    {"name": "Raph"}, 
    {"name": "Don"}, 
    {"name": "Splinter"} 
], 
"links": [ 
    {"source": 0, "target": 4, "relation": "son"}, 
    {"source": 1, "target": 4, "relation": "son"}, 
    {"source": 2, "target": 4, "relation": "son"}, 
    {"source": 3, "target": 4, "relation": "son"} 
]} 


var force = d3.layout.force() 
    .nodes(graph.nodes) 
    .links(graph.links) 
    .size([400, 400]) 
    .linkDistance(120) 
    .charge(-30) 
    .start(); 


var svg = d3.select("svg"); 

var link = svg.selectAll("line") 
.data(graph.links) 
.enter().append("line") 
.style("stroke", "black"); 

var node = svg.selectAll("circle") 
.data(graph.nodes) 
.enter().append("circle") 
.attr("r", 20) 
.style("fill", "grey") 
.call(force.drag); 

node.append("title") 
.text(function(d) { return d.name; }); 

force.on("tick", function() { 
    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; }); 
}) 

最後,你不一定需要D3的佈局,你甚至可以使用自定義佈局像這樣

http://jsfiddle.net/ankit89/uts5orrd/5/

var graph = { 
"nodes": [ 
    {"name": "Leo", "level": 1}, 
    {"name": "Mike", "level": 1}, 
    {"name": "Raph", "level": 1}, 
    {"name": "Don", "level": 1}, 
    {"name": "Splinter", "level": 2} 
], 
"links": [ 
    {"source": 0, "target": 4, "relation": "son"}, 
    {"source": 1, "target": 4, "relation": "son"}, 
    {"source": 2, "target": 4, "relation": "son"}, 
    {"source": 3, "target": 4, "relation": "son"} 
]} 

var svg = d3.select("svg"); 

svg.selectAll("circle") 
.data(graph.nodes) 
.enter() 
.append("circle") 
.attr({ 
    "cx": function(d, i){ 
     var x; 
     if(d.level == 1){ 
      x = i*100 + 100; 
     }else{ 
      x = 250; 
     } 
     d.x = x; 
     return x; 
    }, 
    "cy": function(d, i){ 
      var y; 
      if(d.level == 1){ 
       y = 260; 
      }else{ 
       y = 60; 
      } 

      d.y = y; 
      return y; 
     }, 
    "r" : 30, 
    "fill": "gray", 
    "opacity": .5 
}) 

svg.selectAll("text") 
.data(graph.nodes) 
.enter() 
.append("text") 
.attr({ 
    "x": function(d){return d.x}, 
    "y": function(d){return d.y}, 
    fill: "steelblue" 
}) 
.text(function(d){ 
    return d.name; 
}) 


svg.selectAll("line") 
.data(graph.links) 
.enter() 
.append("line") 
.attr({ 
    "x1": sourceX, 
    "y1": sourceY, 
    "x2": targetX, 
    "y2": targetY, 
    "stroke-width": 2, 
    "stroke": "grey" 
}) 

function sourceX(d, i){ 
    var t = graph.nodes[d.source].x; 
    return t; 
} 

function sourceY(d, i){ 
    var t = graph.nodes[d.source].y; 
    return t; 
} 

function targetX(d, i){ 
    var t = graph.nodes[d.target].x; 
    return t; 
} 

function targetY(d, i){ 
    var t = graph.nodes[d.target].y; 
    return t; 
} 
//console.log(graph.nodes) 

這裏是故事的要點:

  1. 如果使用d3佈局,使您的數據結構與佈局所期望的數據結構匹配,並且d3將爲您計算x和y座標。

  2. 如果使用需要自定義佈局,編寫函數來確定節點和鏈接的x和y座標。