Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 498
Ash Avatar asked Apr 26 '18 11:04

Ash


3 Answers

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>
like image 69
Gerardo Furtado Avatar answered Nov 17 '22 12:11

Gerardo Furtado


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>
like image 4
Asons Avatar answered Nov 17 '22 12:11

Asons


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>
like image 1
Muhammad Usman Avatar answered Nov 17 '22 11:11

Muhammad Usman