2016-03-06 98 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坐标。