【问题标题】:Add single parent node by selecting multiple elements in D3通过在 D3 中选择多个元素来添加单个父节点
【发布时间】:2018-04-26 11:00:51
【问题描述】:

我有一个问题,我必须通过选择多个元素来添加父节点。

我有:

<g class="group">
     <g class="Node" id="1">...</g>
     <g class="Node" id="2">...</g>
     <g class="Node" id="3">...</g>
     <g class="Node" id="4">...</g>
</g>

现在在上面的结构中,我必须通过它们的 id 选择一些具有 Node 类的元素,并为它们添加一个父单父元素。

如果我选择节点 2 和 3,它应该看起来像这样:

<g class="group">
    <g class="Node" id="1">...</g>
    <g class="Grp">
        <g class="Node" id="2">...</g>
        <g class="Node" id="3">...</g>
    </g>
    <g class="Node" id="4">...</g>
</g>

有什么方法可以让我使用 javascript 或 D3 来进行这种操作。

【问题讨论】:

    标签: javascript html d3.js svg


    【解决方案1】:

    为了完整起见,这是(其中之一)用于执行此操作的惯用 D3:

    var group = d3.select(".group");
    var newGroup = group.insert("g", "#g2").attr("class", "Grp");
    var nodes = group.selectAll("#g2, #g3").remove();
    nodes.each(function() {
      var self = this;
      newGroup.append(function() {
        return self
      });
    });
    

    remove() 方法的好处在于,与 D3 中的几个方法一样,它返回选择。因此,我们可以删除元素但保留对它们的引用,以便稍后(在新组中)附加它们。

    这里是演示。 SVG 中不会显示任何内容(以蓝色绘制),您必须使用浏览器的 Web 检查器检查 SVG 以查看组结构:

    var group = d3.select(".group");
    var newGroup = group.insert("g", "#g2").attr("class", "Grp");
    var nodes = group.selectAll("#g2, #g3").remove();
    nodes.each(function() {
      var self = this;
      newGroup.append(function() {
        return self
      });
    });
    <script src="https://d3js.org/d3.v5.min.js"></script>
    <svg style="background-color:powderblue;">
      <g class="group">
         <g class="Node" id="g1"></g>
         <g class="Node" id="g2"></g>
         <g class="Node" id="g3"></g>
         <g class="Node" id="g4"></g>
    </g>
    </svg>

    【讨论】:

      【解决方案2】:

      使用 javascript 你可以做这样的事情

      var els = document.querySelectorAll('.group, #id2, #id3'); // grab the parent and id2/3
      var grp = document.createElement('g');                     // create wrapper
      grp.className = 'Grp';                                     // give it a class
      els[0].insertBefore(grp, els[1]);                          // insert it before id2
      grp.appendChild(els[1]);                                   // move id2 to wrapper
      grp.appendChild(els[2]);                                   // move id3 to wrapper
      .Grp {
        color: red;
      }
      <g class="group">
        <g class="Node" id="id1">.1.</g>
        <g class="Node" id="id2">.2.</g>
        <g class="Node" id="id3">.3.</g>
        <g class="Node" id="id4">.4.</g>
      </g>

      【讨论】:

      • 谢谢,分组工作正常。但看起来当我使用 createElement 创建 SVG 元素时,它不会被视为 svg 元素并且不会显示。由于 g 是一个 SVG 容器,我不得不使用: document.createElementNS("w3.org/2000/svg", "g")
      • @VishalAsh 这也适用于 SVG 容器,但要查看实际分组,请使用浏览器的“检查”工具。
      • 我应该提到 g 是 SVG 元素。
      • @GerardoFurtado 感谢您提供的信息(以及您的回答加 1)。我不使用 D3,虽然猜测他们确实偶尔使用纯 js,因此发布了这个答案。我仍然认为使用 D3 版本可能更安全,尽管由于上述原因不能多说,而且针对 SVG 可能会在跨浏览器上遇到挑战 :)
      • 对我来说,createElement 创建了一个宽度为零、高度为零的 SVG 元素,并且由于 g 元素内部有 svg rect 而没有显示出来。感谢您的两个答案。
      【解决方案3】:

      如果你很容易,你可以用jQuery来做。更少的代码行。

      $( "#2, #3" ).wrapAll( "<div class='Grp'></div>" );
      
      console.log($(".group").html())
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
      <g class="group">
           <g class="Node" id="1">...</g>
           <g class="Node" id="2">...</g>
           <g class="Node" id="3">...</g>
           <g class="Node" id="4">...</g>
      </g>

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-02-19
        • 1970-01-01
        • 2021-12-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多