score:9

Accepted answer

If you pass an existing DOM element to append or insert, the element (and it's children) will be moved from their current place in the DOM hierarchy to wherever you've just inserted them.

var stuffToBeWrapped = d3.selectAll(".stuff");

stuffToBeWrapped.each(function() {

   d3.select( this.parentNode ).insert("g", function(){return this;} ) 
              //insert a new <g> element immediately before this element
     .attr("class", "wrapper") //set anything you want to on the <g>
     .append( function(){return this;} );
             //move the content element into the group

});

It's a little messy because d3 expects you to always use functions to determine which element to insert or insert before, and that's not necessary when we're doing it all within an each statement. But it should get the job done!

(Or, use the JQuery method if you've already got the library on your page. JQuery doesn't usually have any problem manipulating SVG elements, it just can't create them!)

score:5

Unable to make @AmeliaBR 's answer to work, I solved the problem like so

d3.selectAll(selectElementsToWrap).each(function() {
    var el = this;
    d3.select(el.parentNode)
      .insert("g")
      .attr("class", "wrapped")
      .append(function() { return el; });
});

The approved solution gave me DOMException: Failed to execute 'appendChild' on 'Node': The new child element contains the parent


Related Query

More Query from same tag