60

我正在最终学习 D3 的过程中,我偶然发现了一个我无法找到答案的问题。我不确定我的问题是因为我没有习惯性地思考图书馆,还是因为我目前不知道的程序。我还应该提一下,我在 6 月份才开始做与网络相关的事情,所以我对 javascript 还很陌生。

假设我们正在构建一个工具,为用户提供带有相应图像的食物列表。并且让我们添加额外的约束,即每个列表项都需要用唯一 ID 标记,以便可以链接到另一个视图。我解决这个问题的第一个直觉是创建一个<div>'s 列表,每个都有自己的 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; });

现在,在其中添加 a<div>和 a<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上提到子选择,但我对测试该假设的语言不够熟悉。

从概念层面来看,这三个对象(divpimg)更像是一组而不是单独的实体,如果代码也能反映这一点,那就太好了。

4

3 回答 3

85

您不能在一个链接命令中添加多个子元素。您需要将父选择保存在变量中。这应该做你想要的:

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/

您想知道类似por的子元素如何img访问绑定到其父元素的数据。追加新元素时,数据会自动从父级继承。这意味着 p 和 img 元素将与父 div 绑定相同的数据。

append这种数据传播对于该方法来说不是唯一的。它发生在以下selection方法中:appendinsertselect

例如,对于 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);
    });
于 2012-11-02T23:43:43.537 回答
26

同样,没有本质上的不同,但我首选的方法是使用“呼叫”

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; });​
  });

您不需要存储任何变量,如果您想在其他地方使用类似的结构,您可以将调用的函数分解出来。

于 2015-04-20T15:12:05.530 回答
3

这与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>

于 2015-04-10T15:41:53.243 回答