2012-11-02 101 views
49

我正在學習D3的過程中,偶然發現了一個我一直無法找到答案的問題。我不確定,如果我的問題是因爲我沒有習慣圖書館的慣例,或者是因爲我目前沒有意識到的程序。我還應該提到,我只在6月份開始做與網絡有關的事情,所以我對JavaScript很新。D3,嵌套追加和數據流

假設我們正在構建一個工具,可以爲用戶提供包含相應圖像的食物列表。並且讓我們添加額外的約束條件,即每個列表項需要用唯一ID標記,以便可以鏈接到另一個視圖。我解決這個問題的第一個直覺就是創建一個列表<div>的每個都有自己的ID,其中每個div都有其自己的<p><img>。生成的HTML看起來是這樣的:

<div id="chocolate"> 
    <p>Chocolate Cookie</p> 
    <img src="chocolate.jpg" /> 
</div> 
<div id="sugar"> 
    <p>Sugar Cookie</p> 
    <img src="sugar.jpg" /> 
</div> 

此工具的數據是一個JSON陣列,其中一個單獨的JSON的樣子:

{ "label": "sugar", "text": "Sugar Cookie", "img": "sugar.jpg" } 

有沒有辦法做到生成HTML一舉突破?與添加一個div的基本情況開始,代碼可能看起來像:

d3.select(containerId).selectAll('div')               
    .data(food) 
    .enter().append('div') 
    .attr('id', function(d) { return d.label; }); 

現在,有關將<div>在它<p>什麼?我最初的想法是做類似:

d3.select(containerId).selectAll('div')               
    .data(food) 
    .enter().append('div') 
    .attr('id', function(d) { return d.label; }) 
     .append('p').text('somethingHere'); 

但是,我看到兩個問題:(1)你怎麼從div元素獲取數據,和(2)你怎麼可以追加多個孩子一個聲明鏈中的同一個父項?我無法想出一個辦法來完成第三步,我將在img上追加。

我發現在另一篇文章中提到了嵌套選擇,其指向http://bost.ocks.org/mike/nest/。但是嵌套選擇,因此將附加分解爲三個區塊,對於這種情況適當/習慣?或者實際上是否有一種構造良好的方式來在一個聲明鏈中形成這種結構?看起來好像https://github.com/mbostock/d3/wiki/Selections上提到的子選項可能有一種方法,但我對語言不夠熟悉以檢驗該假設。

從概念級,這三個對象(divp,並img)被處理更像一個基團而不是單獨的實體,並且如果代碼反映以及這將是很好。

回答

69

您不能在一個鏈接命令中添加多個子元素。您需要將父級選擇保存在變量中。這應該做你想要什麼:

var data = [{ "label": "chocolate", "text": "Chocolate Cookie", "img": "chocolate.jpg" }, 
     { "label": "sugar", "text": "Sugar Cookie", "img": "sugar.jpg" }]; 

var diventer = d3.select("body").selectAll("div") 
    .data(data) 
    .enter().append("div") 
    .attr("id", function(d) { return d.label; }); 

diventer.append("p") 
    .text(function(d) { return d.text; }); 

diventer.append("img") 
    .attr("src", function(d) { return d.img; });​ 

見工作小提琴:http://jsfiddle.net/UNjuP/

你想知道像pimg子元素如何獲得訪問綁定到其父的數據。添加新元素時,數據會自動從父級繼承。這意味着p和img元素將與父div具有相同的綁定數據。

該數據傳播對於append方法不是唯一的。它發生在以下selection方法中:append,insertselect

例如,對於selection.append:

selection.append(名稱)

追加具有指定名稱爲 在當前選擇的每個元素的最後一個子一個新元素。返回包含附加元素的新選擇 。每個新元素都會繼承當前元素的數據 (如果有),其方式與選擇 子選項的方式相同。該名稱必須指定爲常量,但在未來我們可能允許附加現有元素或功能 動態生成名稱。

如果有不清楚的地方,請隨時詢問詳情。


EDIT

可以添加多個子元素,而不通過使用selection.each方法存儲在變量中選擇。然後,您可以也直接從父訪問數據:

var data = [{ "label": "chocolate", "text": "Chocolate Cookie", "img": "chocolate.jpg" }, 
     { "label": "sugar", "text": "Sugar Cookie", "img": "sugar.jpg" }]; 

d3.select("body").selectAll("div") 
    .data(data) 
    .enter().append("div") 
    .attr("id", function(d) { return d.label; }) 
    .each(function(d) { 
     d3.select(this).append("p") 
      .text(d.text); 
     d3.select(this).append("img") 
      .attr("src", d.img); 
    }); 
+6

太棒了!我沒有意識到,孩子節點具有相同的數據範圍。感謝您的澄清:) –

+3

Upvoted使用'selection.each'。 – Yawar

+2

如果使用'selection.each'插入分組(或嵌套)節點,請記住在更新步驟中也可以使用'selection.each'(也可以用於退出步驟)。 – npdoty

3

這不是從根本上nautat's answer不同,但我認爲該代碼可以通過保存更新選擇,而不是作出一點清潔劑輸入選擇,並獲取輸入選擇它需要它的一個操作(添加周圍的div)。

當您向輸入()選擇中插入元素或追加元素時,會將其添加到隨後可以使用的更新選擇中。這意味着,你可以加入數據,再加入與輸入選擇一個div,然後當你更新選擇追加,你會內您在輸入選擇添加的div追加

var cookies = [ 
 
    { "label": "sugar", "text": "Sugar Cookie", "img": "sugar.jpg" }, 
 
    { "label": "chocolate", "text": "Chocolate Cookie", "img": "chocolate.jpg" }]; 
 

 
var cookie = d3.select("#cookie-jar").selectAll().data(cookies); 
 
cookie.enter().append("div"); 
 
cookie.append("p").text(function(d){ return d.text }); 
 
cookie.append("img").attr("src",function(d){ return d.img });
#cookie-jar div { border: solid 1px black; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> 
 
<div id="cookie-jar"></div>

19

同樣,沒有實質上的區別,但我的首選方法是使用「呼叫」

var data = [{ "label": "chocolate", "text": "Chocolate Cookie", "img": "chocolate.jpg" }, 
     { "label": "sugar", "text": "Sugar Cookie", "img": "sugar.jpg" }]; 

d3.select("body").selectAll("div") 
    .data(data) 
    .enter().append("div") 
    .attr("id", function(d) { return d.label; }) 
    .call(function(parent){ 
    parent.append('p').text(function(d){ return d.text; }); 
    parent.append('img').attr("src", function(d) { return d.img; });​ 
    }); 

你不需要儲存任何VARI如果你想在其他地方使用類似的結構,你可以將被調用函數分解出來。

+0

愛它!這使得我更容易處理更新深度嵌套對象 – ptim

+0

這個比上面的更適合我的需求,因爲我沒有數據,我只是想在不使用外部變量的情況下重新使用父類,感謝您! –