我在使用D3.js工作时遇到了一些麻烦。也就是说,我正在尝试使用http://bl.ocks.org/mbostock/1021953中的基本代码创建节点树。
我将其切换为内联加载数据,而不是从文件加载,因为我在Rails应用程序中使用它并且不希望有重复信息。我切换了线路,以便您可以看到我的数据格式。
无论如何,这是我的大部分代码:
<%= javascript_tag do %>
var nodes = [{"title":"Duncan's Death","id":"265"},{"title":"Nature Thrown Off","id":"266"},{"title":"Cows Dead","id":"267"},{"title":"Weather Bad","id":"268"},{"title":"Lighting kills man","id":"269"},{"title":"Macbeth's Rise","id":"270"}];
var links = [{"source":"265","target":"266","weight":"1"},{"source":"266","target":"267","weight":"1"},{"source":"266","target":"268","weight":"1"},{"source":"268","target":"269","weight":"1"}];
var firstelement = +links[0].source;
links.forEach(function(l) {
l.source = +l.source;
l.source = l.source-firstelement;
l.target = +l.target
l.target = l.target-firstelement;
});
var width = 960,
height = 500;
var color = d3.scale.category20();
var force = d3.layout.force()
.charge(-1000)
.linkDistance(300)
.size([width, height]);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
force
.nodes(nodes)
.links(links)
.start();
var link = svg.selectAll(".link")
.data(links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.weight); });
var node = svg.selectAll(".node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
.call(force.drag);
node.append("circle")
.attr("class", "circle_node")
.attr("r", 50)
.style("fill", function(d) { return color(d.id); })
node.append("title")
.text(function(d) { return d.title; });
node.append("text")
.attr("x", function(d) { return d.x; } )
.attr("y", function(d) { return d.y; })
.text(function(d) { return d.title; });
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("x", function(a) { return a.x; })
.attr("y", function(a) { return a.y; });
});
<% end %>
这似乎应该对我有用,但我似乎可以管理它。链接有效,但节点都保留在左上角。我试过直接输入圆圈并将文本附加到它们(保持接近我上面列出的源代码),但是当圆圈表现正常时,它不会显示文本。我希望标题集中在节点中。
更一般地说,我对这是如何工作感到困惑。 “d”在
之类的行中引用了什么function(d) { return d.source.x; }
似乎是在声明一个函数并同时调用它。我知道它不一定是特定的字符“d”(例如,将“d”切换为“a”似乎没有区别,只要它在声明和函数内完成。 )但它指的是什么?输入正在修改的对象的数据?例如,如果我想打印出来,(在属性之外),我该怎么做?
对不起,我是D3的新手(对于JavaScript来说还是新手),所以我觉得答案很明显,但我一直在查找并通过教程,我仍然迷失方向。提前谢谢。
答案 0 :(得分:2)
首先,您的代码存在一个简单问题,导致所有节点都停留在左上角。您正尝试使用代码定位每个节点:
node.attr("x", function(a) { return a.x; })
.attr("y", function(a) { return a.y; });
但是,node
是g
s 的选择,不会采用x
和y
属性。相反,您可以使用translate transform移动每个node
,例如
node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
进行此更改应允许节点四处移动。
接下来,转到关于“d”的问题,我认为您需要了解的第一件事是您可以使用D3中的一系列元素来完成。来自the docs:选择(例如nodes
)“是从当前文档中提取的元素数组。”一旦选择了元素,就可以应用运算符来更改元素的属性或样式。您还可以将数据绑定到每个元素。
在您的情况下,您将数据绑定到选择的g
s(节点):
var node = svg.selectAll(".node")
.data(nodes)
.enter().append("g")
然后您使用attr
更改每个节点的位置。但是,您不是将每个元素的x
和y
属性设置为相同的值,而是传递attr
和anonymous function,它将返回(可能是不同的)位置每个节点:
node.attr("x", function(a) { return a.x; })
.attr("y", function(a) { return a.y; });
attr
的文档中也解释了这种行为:
属性值等指定为常量或 功能;后者将针对每个元素进行评估。
因此,d
表示nodes
中的单个元素(对象)。
所以回到你的代码,每一个滴答都会发生两件事情:
force
重新计算。force.on
的匿名函数将每个对应的元素移动到新位置。