Ash
Ash

Reputation: 722

Add single parent node by selecting multiple elements in D3

I have problem where I have to add a parent node by selection of multiple elements.

I have:

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

Now in the above structure i have to select some elements which have class Node by their ids and add a parent single parent element for them.

It should look something like this, if I select Node 2 & 3 for example:

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

Is there some way I can do this manipulation by using javascript or D3.

Upvotes: 5

Views: 383

Answers (3)

Asons
Asons

Reputation: 87191

With javascript you can do something like this

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>

Upvotes: 4

Gerardo Furtado
Gerardo Furtado

Reputation: 102194

Just for completeness, this is (one of...) the idiomatic D3 for doing that:

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

The nice thing about remove() method is that, like several methods in D3, it returns the selection. Therefore, we can remove the elements but keeping a reference to them, so we can append them later (inside the new group).

Here is the demo. Nothing will show up in the SVG (painted in blue), you have to inspect the SVG using your browser's web inspector to see the groups structure:

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>

Upvotes: 4

Muhammad Usman
Muhammad Usman

Reputation: 10148

If you are easy, you can do it with jQuery. Less lines of code.

$( "#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>

Upvotes: 1

Related Questions