使用 D3.js 为每个数据成员附加多个非嵌套元素

Posted

技术标签:

【中文标题】使用 D3.js 为每个数据成员附加多个非嵌套元素【英文标题】:Appending multiple non-nested elements for each data member with D3.js 【发布时间】:2014-02-24 11:55:11 【问题描述】:

我想使用 d3 创建多个非嵌套元素来创建这样的结构:

    <div id="parent">
        <p> from data[0] </p>
        <p> from data[0] </p>

        <p> from data[1] </p>
        <p> from data[1] </p>

        <p> from data[2] </p>
        <p> from data[2] </p>
    </div>

创建嵌套结构类似于

    d3.select('#parent').selectAll('p').data(data).enter().
           append('p')...append('p')

但即使在追加之后我也想保持原来的选择,所以我可以继续追加到父元素。谢谢!

【问题讨论】:

【参考方案1】:

的惯用方式是嵌套:

var divs = d3.select('#parent').selectAll('p').data(data).enter().append('div');

divs.append('p')
divs.append('p')

创建:

<div id="parent">
  <div>
    <p> from data[0] </p>
    <p> from data[0] </p>
  </div>

  <div>
    <p> from data[1] </p>
    <p> from data[1] </p>
  </div>

  <div>
    <p> from data[2] </p>
    <p> from data[2] </p>
  </div>
</div>

如果这不起作用,请保存您的选择并重复追加:

var enterSelection = d3.select('#parent').selectAll('p').data(data).enter();

enterSelection.append('p')
enterSelection.append('p')

然后对你添加的内容进行排序:

d3.select('#parent').selectAll('p').sort(function(a, b) return a.index - b.index; )

您需要将index 属性添加到描述排序顺序的data 的每个元素。正常的i 仅在特定选择的上下文中定义,当我们重新选择时会丢失。

【讨论】:

谢谢亚当。我没想到只是事后排序 完美运行,无论如何,我的数据将按数据排序。并且仅供任何人以后参考,我们必须在最后一行重新选择 d3.select('#parent') 进行排序,而不是使用 enterSelection,因为我们已经输入了()。谢谢! 您也可以使用 enterSelection.insert("p") 作为第二个元素。这应该消除了作为最后一步进行排序的需要。【参考方案2】:

而不是.append()

您还可以在 .html() 中包装创建新内容的函数

d3.select('#parent')
  .selectAll('div')
    .data(data)
  .enter()
    .append('div')
    .html(function(d) return "<p>" + from data[0] + "<p>" etc..... ;);

【讨论】:

【参考方案3】:

第一项使用append(),第二项使用insert()。这消除了事后排序的任何需要(感谢@scuerda 指出这一点的评论)(JSFiddle):

data = [, , ];
var enterSelection = d3.select('#parent').selectAll('p').data(data).enter()

enterSelection.append('p').text(function(d, i) return 'from data[' + i + ']')
enterSelection.insert('p').text(function(d, i) return 'from data[' + i + ']')

这将为您提供所需的确切结构:

<p>from data[0]</p>

<p>from data[0]</p>

<p>from data[1]</p>

<p>from data[1]</p>

<p>from data[2]</p>

<p>from data[2]</p>

【讨论】:

这实际上是应该被接受的解决方案,因为它正是所要求的,没有任何弯路! 这很好,但你确定不是:&lt;p&gt;from data[0]&lt;/p&gt; &lt;p&gt;from data[1]&lt;/p&gt; &lt;p&gt;from data[2]&lt;/p&gt; &lt;p&gt;from data[0]&lt;/p&gt; &lt;p&gt;from data[1]&lt;/p&gt; &lt;p&gt;from data[2]&lt;/p&gt; 取决于 d3 版本。例如,对于 d3 v7,它不再工作了 仍在为较新版本的 d3 找到解决方案【参考方案4】:

您也可以在单个选择/输入循环中执行此操作,如下所示

d3.select('#parent').selectAll('p').data(data).enter().
append('p').text(function(d) return 'from data[0]')).
select(function()  return this.parentNode; ).
append('p').text(function(d) return 'from data[0]'));

【讨论】:

这太恶心了,正是我要找的东西【参考方案5】:

与上述类似,但成语不同。这更适用于嵌套选择方法,并且无需排序或插入:

var divs = d3.select('#parent');

var ps = divs.selectAll('#parent > div')
    .data(d3.range(3)).enter().append('div');

ps.append('p').html(function(d,i)  return 'from data[' + i + ']'; );
ps.append('p').html(function(d,i)  return 'from data[' + i + ']'; );

更优雅(可能更快):

var divs = d3.select('#parent');

  var ps = divs.selectAll('#parent > div')
    .data(d3.range(3)).enter().append('div');

    ps.append('p').html(function(d,i)  return 'from data[' + i + ']'; )
    .select(function()  return this.parentNode.appendChild(this.cloneNode(true)); );

【讨论】:

【参考方案6】:

1。复制每个元素

创建一个新列表,其中包含所有元素两次 (like this):

doubleData = data.reduce(function (res, current, index, array) 
    return res.concat([current, current]);
, []);

d3.select('#parent').selectAll('p').data(doubleData).enter().append('p')

2。输入两次

有时您想对附加的元素进行进一步的操作。在这种情况下,您可能想知道您是在访问第一个还是第二个添加的元素。为这些元素添加 first-paragraphsecond-paragraph 类。

d3.select('#parent').selectAll('.first-paragraph')
  .data(data)
  .enter()
  .append('p')
  .attr('class', 'first-paragraph');

d3.select('#parent').selectAll('.second-paragraph')
  .data(data)
  .enter()
  .append('p')
  .attr('class', 'second-paragraph');

在这种情况下,您可能需要根据 Adam Pearce's answer 对元素进行排序。

【讨论】:

以上是关于使用 D3.js 为每个数据成员附加多个非嵌套元素的主要内容,如果未能解决你的问题,请参考以下文章

D3.js:使用元素位置而不是鼠标位置定位工具提示?

如何使用 D3.js 将图像添加到 svg 容器

如何在 D3.js 中为网络图的矩形节点添加文本?

如何获得一组生成的 D3.js 元素中每个元素的高度?

相当于 D3.js 中 jQuery 的“非”选择器?

d3.js - 在力有向图组上添加背景矩形