[英]D3, nested appends, and data flow
我正在最終學習D3,我偶然發現了一個我無法找到答案的問題。 我不確定我的問題是因為我沒有習慣性地使用庫,或者是因為我目前沒有意識到的程序。 我還應該提一下,我在6月才開始做與網絡相關的事情,所以我對javascript很新。
假設我們正在構建一個工具,為用戶提供包含相應圖像的食物列表。 並且讓我們添加額外的約束,每個列表項需要用唯一的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; });
現在,添加帶有<p>
的<div>
怎么樣? 我最初的想法是做一些像:
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上提到的子選擇可能有一種方法,但我對該語言不太熟悉以測試該假設。
從概念層面來看,這三個對象( div
, p
和img
)被視為更像是一個組而不是單獨的實體,如果代碼也反映出來也會很好。
您不能在一個鏈式命令中添加多個子元素。 您需要將父選擇保存在變量中。 這應該做你想要的:
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/
您想知道像p
或img
這樣的子元素如何訪問綁定到其父元素的數據。 在追加新元素時,數據會自動從父項繼承。 這意味着p和img元素將具有與父div相同的數據綁定。
此數據傳播對於append
方法不是唯一的。 它使用以下selection
方法: append
, insert
和select
。
例如,對於selection.append:
selection.append(名稱)
將具有指定名稱的新元素追加為當前選擇中每個元素的最后一個子元素。 返回包含附加元素的新選擇。 每個新元素都以與選擇子選擇相同的方式繼承當前元素的數據(如果有)。 必須將名稱指定為常量,但將來我們可能允許附加現有元素或動態生成名稱的函數。
如果不清楚,請隨時詢問細節。
編輯
您可以使用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);
});
同樣,沒有實質性的不同,但我首選的方法是使用'call'
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; });
});
你不需要存儲任何變量,如果你想在其他地方使用類似的結構,你可以將被調用的函數分解出來。
這與nautat的答案沒有根本的不同,但我認為通過保存更新選擇而不是輸入選擇可以使代碼更清晰,並從中獲取輸入選擇以進行需要它的一個操作(添加周圍的div)。
當您在enter()選擇中插入或附加元素時,它會添加到您之后可以使用的更新選擇中。 這意味着您可以加入數據,然后使用回車選擇添加一個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>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.