我是D3新手,看起来很酷。我以为我会尝试使用Directional Force Layout来构建一些东西。
我想做什么
我通过for循环创建一个json对象,以添加所有准备好在force.start()上使用的项目。这很好。但是我想通过不同的json源添加更多数据。为此,我在第一个循环中有另一个循环,以根据我的第一个循环中的数据添加更多数据(请参阅代码)。
我有多远
我已登录控制台,我可以看到项目被推入我的json对象,但是它们没有获得force.nodes()的正确属性;见:
group: 2
name: "Alt-J"
px: NaN
py: NaN
x: NaN
y: NaN
这是为什么? 对我来说,似乎图是在循环完成之前构建的,并且项目已正确添加。
继承我的代码:
// Get the users top played artists
d3.json("http://ws.audioscrobbler.com/2.0/?method=user.gettopartists.gettopartists&user="+ username +"&api_key=be4ff3242bdb1d653517df99df39cfe2&format=json", function(error, graph) {
// Loops through them and push them in nodes.names[]
for (var i = 0; i < graph.topartists.artist.length; i++) {
var item = graph.topartists.artist[i];
// Then get for each top artist their respect related artists
d3.json("http://ws.audioscrobbler.com/2.0/?method=artist.getsimilar&artist="+ item.name +"&api_key=be4ff3242bdb1d653517df99df39cfe2&format=json", function(error, related) {
// Do this just for 5 item to reduce load
for (var i2 = 0; i2 < 5; i2++) {
var relatedItem = related.similarartists.artist[i2];
console.log(i2);
// Add those to our json object like with top artists
nodes.names.push({
"name" : relatedItem.name,
"group" : 2
});
nodes.links.push({
"source" : i + i2 ,
"target" : 0
});
}
console.log(nodes.names);
});
nodes.names.push({
"name" : item.name,
"group" : 1
});
nodes.links.push({
"source" : i,
"target" : 0
});
}
force
.nodes(nodes.names)
.links(nodes.links)
.distance(20)
.start();
答案 0 :(得分:2)
原因是d3.json
是异步的。也就是说,回调不会立即执行,而是在获取JSON的调用返回时执行。这意味着初始化和启动强制布局的代码块在嵌套的d3.json
调用返回并添加数据之前运行。
这不是问题 - 您当然可以将新项目添加到您为force.nodes()
和force.links()
提供的数组中。问题是这些新项目的位置没有初始化,只发生在force.start()
上。因此,在添加新节点/链接后,您需要再次启动强制布局。
您应该能够在代码中通过声明force
进一步向上并在每个嵌套回调结束时调用force.start()
来解决此问题。