2014-03-19 51 views
1

我正在使用d3.nest()将平面JSON文件转换为分层树。如果您事先知道数据中发现的级别,那么这很好:d3.nest()会为您传递的每个关键函数创建一个嵌套级别。D3.js:使用d3.nest()动态添加密钥

但是,我想知道是否有一种优雅的方式来动态传递关键功能。这可能是一个基本的问题,但我的Javascript技能也是基本的。

这是一个静态的例子与存储阵列中的键名工作:

var levels = ['first', 'second', 'third'] 

var root = { 
    "key":"root", 
    "values": 
     d3.nest() 
      .key(function(d){ return d[levels[0]] }) 
      .key(function(d){ return d[levels[1]] }) 
      .key(function(d){ return d[levels[2]] }) 
      .entries(data) 
} 

我的解决方案,现在是一个if-else的循环,伪动态创建不同的嵌套:

// build the nested tree pseudo-dynamically 
if (levels.length === 1) { 
    var nest = d3.nest() 
      .key(function(d){return d[levels[0]]}) 
      .entries(data); 
} else if (levels.length === 2) { 
    var nest = d3.nest() 
      .key(function(d){return d[levels[0]]}) 
      .key(function(d){return d[levels[1]]}) 
      .entries(data); 
} else if (levels.length === 3) { 
    var nest = d3.nest() 
      .key(function(d){return d[levels[0]]}) 
      .key(function(d){return d[levels[1]]}) 
      .key(function(d){return d[levels[2]]}) 
      .entries(data); 
} 
[...] 

是有一个优雅的方式动态传递密钥到d3.nest()?我想要的是原则上的东西,如下面的示例(哪个不起作用):

var root = { 
    "key":"root", 
    "values": 
     d3.nest() 
      for (var i = 0; i < levels.length; i++) { 
       .key(function(d){return d[levels[i]]}) 
      } 
      .entries(data) 
} 

感谢您的时间!

+0

听起来像嵌套是不是在这里正确的事情。 [这个问题](http://stackoverflow.com/questions/20913689/complex-d3-nest-manipulation)可能会有所帮助。 –

回答

4

这并不像你假设的优雅代码那么简单,但是与if-else方法相比,你当然可以简化它。

的第一个反应就是做这样的事情:

var levels = ['first', 'second', 'third'] 

var nest = d3.nest(); 
for (var i = 0; i < levels.length; i++) { 
    nest = nest.key(function(d){return d[levels[i]]}); 
    //create a new nesting function that has one more key function added 
    //and save it in the variable 
} 

var root = { 
     "key":"root", 
     "values": nest.entries(data) //compute the nest 
    } 

然而,这不起作用,因为您的嵌套功能将无法使用直到您创建的所有嵌套功能后,所以到巢的时间实际运行你的i变量等于3和levels[i]返回未定义,因此d[levels[i]]返回未定义。 Example here

您需要创建一个单独的函数的外壳,以便从levels正确的值被锁定在:

function createNestingFunction(propertyName){ 
    return function(d){ 
      return d[propertyName]; 
     }; 
} 

var levels = ['first', 'second', 'third'] 

var nest = d3.nest(); 
for (var i = 0; i < levels.length; i++) { 
    nest = nest.key(createNestingFunction(levels[i])); 
    //create a new nesting function that has one more key function added 
    //and save it in the variable 

    //the function `createNestingFunction` is called *immediately* 
    //with a parameter based on the current value of `i` 
    //the returned function will always use that parameter, 
    //regardless of how many times createNestingFunction is called 
} 

var root = { 
     "key":"root", 
     "values": nest.entries(data) //compute the nest 
    } 

这个例子的工作版本:http://fiddle.jshell.net/brVLH/1/

+0

感谢您的回答!这工作得很好,实际上它非常优雅! – emiguevara

+0

如果我需要根据分组来识别等级,该怎么办? 假设我有两组作为关键比我应该怎么知道这个级别是基于这个值?不知何故,我可以添加attr,我用attkey等关键属性组? –

+0

@AmitRana我不太清楚你的意思。也许开始一个新的问题,以便你可以更完整地解释它(用简单的例子),其他人可以尝试帮助? – AmeliaBR

0

发现了另一个可能的解决方案张贴的问题后, 。它使用forEach并描述为here

+0

没有添加多个键是没有问题的......我想要什么当我添加多个键时,基于该键对它们进行分组...对于每个级别,我只想要哪个级别是按哪个键... –

+0

我严重不理解您的评论,@Amit – emiguevara

+0

按照此处的最后一个示例 http://stackoverflow.com/questions/31723061/add-attribute-with-nested-entries-in-d3-js –