简体   繁体   中英

D3 - redraw SVG after DOM change

I'm struggling with redrawing/updating my SVG. I included the enter-update-exit method for my data and my DOM structure looks like the following:

<svg>
  <g id="groupOfRectangles">
    <rect>
    <rect>
    <rect>
    <rect>
    ...
  </g>
</svg>  

Now I want to group some specific rectangles together in my DOM structure. For example:

<svg>
  <g id="groupOfRectangles">
    <rect>  
    <g id="Group1">
      <rect>
      <rect>  
    </g>  
    <rect>
    ...
  </g>
</svg>  

Here I have got so far:

var rect = render();  
//until here, everything is displayed correctly
d3.select(rect._groups[0][x]).before('g').attr("id", "Group" + 1);
document.getElementById("Group1").appendChild(rect._groups[0][x]);
document.getElementById("Group1").appendChild(rect._groups[0][x]);  
render();

After doing this the rectangles, which are grouped by "Group1" are hidden in my visualisation, but still grouped right in my DOM tree. So I have tried to recall my render function, but nothing changes.

function render() {
    var group = rectGroup.selectAll("rect").data(nodes);

    group = group.enter()
            .append("rect")
            .attr("width", function(d) { return d.value; })
            .attr("height", rectHeight)
            .attr("x", function(d) { return d.x; })
            .attr("y", function(d) { return d.y; });

    group.select("rect")
            .attr("width", function(d) { return d.value; })
            .attr("height", rectHeight)
            .attr("x", function(d) { return d.x; })
            .attr("y", function(d) { return d.y; });

    group.exit().remove();

    return group;
}  

The reason of doing this, is for the interaction with the rectangles, I want to implement later. That I only have to interact with one group of rectangles, instead of looking for every single rect, which belongs together. So what I'm doing wrong? Is there any more effective method to group specific rectangles?

Or is it possible (perhaps easier?) to group them together before I call the render function?

EDIT-1:
Here is some working code where I'm switching 2 rectangle elements to a new group in the DOM tree. You can see it in the second line of the schedule function.

var width = 500;
var height = 500;

obj1 = {value: 99, x: 0, y:25, height: 20};
obj2 = {value: 200, x: 0, y:50, height: 20};
obj3 = {value: 300, x: 0, y:100, height: 20};
obj4 = {value: 250, x: 0, y:125, height: 20};
obj5 = {value: 370, x: 0, y:75, height: 20};
var myData = [obj1, obj2, obj3, obj4, obj5];

var svg = d3.select("body").append("svg")
        .attr("width", width)
        .attr("height", height);

var rectGroup = svg.append("g").attr("id", "groupOfRectangles");

d3.selection.prototype.before = function(tagName) {
    var elements = [];

    this.each(function() {
        var element = document.createElement(tagName);
        this.parentNode.insertBefore(element, this);
        elements.push(element);
    });

    return d3.selectAll(elements);
};

function render() {
    var group = rectGroup.selectAll("rect").data(myData);

    group = group.enter()
            .append("rect")
            .attr("width", function(d) { return d.value; })
            .attr("height", rectHeight)
            .attr("x", function(d) { return d.x; })
            .attr("y", function(d) { return d.y; });

    group.select("rect")
            .attr("width", function(d) { return d.value; })
            .attr("height", rectHeight)
            .attr("x", function(d) { return d.x; })
            .attr("y", function(d) { return d.y; });

    group.exit().remove();

    return group;
}

function schedule() {
    var rect = render();
    d3.select(rect._groups[0][3]).before('g').attr("id", "Group" + 1);
    document.getElementById("Group1").appendChild(rect._groups[0][3]);
    document.getElementById("Group1").appendChild(rect._groups[0][4]);
}

schedule();

In your before prototype, you need to use createElementNS and specify the SVG namespace:

this.each(function() {
  var element = document.createElementNS("http://www.w3.org/2000/svg", tagName);
  this.parentNode.insertBefore(element, this);
  elements.push(element);
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM