2011-12-30 80 views
3

我有一个像d3.js:使用selection.on

[ 
    {"name":"foo", "links":["a", "b", "c"]}, 
    {"name":"bar", "links":["d", "e", "f"]} 
] 

的数据结构创建一个可扩展的列表即我想打表像

<ul> 
    <li> foo </li> 
    <li> bar </li> 
</ul> 

,当我点击在foo上,扩展像

<ul> 
    <li> foo 
     <ul> 
      <li> a </li> 
      <li> b </li> 
      <li> c </li> 
     </ul> 
    </li> 
    <li> bar </li> 
</ul> 

我想使用d3.js来做到这一点。它的方便和乐趣,使顶部的列表:

toplist = d3.select("body").append("ul"); 
toplist.selectAll("li") 
    .data(data) 
    .enter() 
    .append("li") 
     .text(function(d){return d.name;}) 

它甚至很容易添加子列表:

items = toplist.append("ul") 
    .selectAll("li") 
    .data(function(d){return d.links}) 
    .enter() 
    .append("li") 
     .text(function(d){return d}) 

我可以一个on("click"..添加到toplist每个li,像

toplist.selectAll("li") 
    .data(data) 
    .enter() 
    .append("li") 
     .text(function(d){return d.name;}) 
     .on("click", expand) 

并将子列表代码移入名为expand的函数。它看起来像

function expand(d,i){ 

,然后具有上述items = ...代码在里面。

问题在于,这会同时扩大foobar

如何给foo列表元素一个单独的点击事件bar只扩展该元素?本质上,我需要通过expand数据元素的索引,并让它只对DOM的特定部分进行操作。

任何帮助,将不胜感激!

+0

我应该补充说,如果我控制台。log d,i,this和d3.event在展开函数中只能看到我单击的元素 – 2011-12-30 20:23:43

回答

9

当您调用expand时,您可获得所需的一切。 this上下文是单击的li元素,d是关联的数据。如果你只想要扩展(而不是展开和折叠之间切换),那么你可以通过选择此创建子列表:

function expand(d) { 
    d3.select(this) 
     .on("click", null) 
    .append("ul") 
    .selectAll("li") 
     .data(d.links) 
    .enter().append("li") 
     .text(function(d) { return d; }); 
} 

注意expand也将删除点击项目的点击处理程序;点击两次后,您不想再次添加列表。

如果您想在展开和移除之间切换,那么您需要跟踪某个状态:子菜单是打开还是关闭。你可以通过在d(例如d.open)上存储一个布尔值来做到这一点,或者你可以通过查询DOM来查看子菜单是否已经存在:d3.select(this).select("ul").empty()

另一种可以做到这一点的方法是提前创建所有子菜单,然后通过display样式属性切换可见性。如果你有所有可用的数据,这是最简单的选择;我可能只打扰会动态地创建子菜单,如果你正在异步加载链接数据。

现场示例:http://bl.ocks.org/1541816