循环D3方向力布局中的额外数据

时间:2014-01-26 13:41:56

标签: javascript json d3.js nested-loops

我是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();

1 个答案:

答案 0 :(得分:2)

原因是d3.json是异步的。也就是说,回调不会立即执行,而是在获取JSON的调用返回时执行。这意味着初始化和启动强制布局的代码块在嵌套的d3.json调用返回并添加数据之前运行。

这不是问题 - 您当然可以将新项目添加到您为force.nodes()force.links()提供的数组中。问题是这些新项目的位置没有初始化,只发生在force.start()上。因此,在添加新节点/链接后,您需要再次启动强制布局。

您应该能够在代码中通过声明force进一步向上并在每个嵌套回调结束时调用force.start()来解决此问题。