2011-12-30 103 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