【问题标题】:Appending multiple non-nested elements for each data member with D3.js使用 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')

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

【问题讨论】:

    标签: javascript dom d3.js


    【解决方案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 对元素进行排序。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-09-15
          • 2023-03-31
          • 2021-07-21
          • 2016-10-01
          • 2012-10-07
          • 2015-05-08
          • 2011-10-30
          相关资源
          最近更新 更多