Search code examples
d3.jsforce-layoutselectall

Children elements didn't inherit parent data with D3 force layout


I have created a d3 force layout,and works very well. My mainly code like so:

var nodes = [{id:1, n:'n_1',np:'0'},{id:2, n:'n_2',np:'0'}];//just for demo
//1. set data
var update = svg.selectAll(".node").data(nodes);
//2. enter
update.enter().append("svg:g").attr("class", "node")
.call(function(p){
  p.append("svg:image").attr("class", "nodeimage");
  p.append("svg:text").attr("class", "nodetext");
});
//3. exit
update.exit().remove();

As is known to us, d3.selectAll(".node").data() is my data. Because the child elements of g will inherit the data from the parent data, d3.selectAll(".nodeimage").data() is also my data.Am I right?

In fact, my data nodes is from backend, and the data is updated. For example, some properties like np have been changed from 0 to 1. We consider the result is nodes = [{id:1, n:'n_1',np:'1'},{id:2, n:'n_2',np:'0'}];

I need to call the function above again. However,d3.selectAll(".node").data() is right, while d3.selectAll(".nodeimage").data() is wrong now.

The following code will not work well.

d3.selectAll('.nodeimage').attr("test", function(d){
    //d.np is a wrong value.
});

Any suggestions for me?

Here is my demo of jsfiddle:http://jsfiddle.net/bpKG4/663/


Solution

  • This is a strange behavior of d3. If I understand correctly (which is not granted), selection.data(...) automatically transfers data to child elements, unless they already have some data binded.

    In your case, it means that you need to copy "by hand" the data to each child:

      //select any child node, then:
        .each(function() {
          d3.select(this).datum(d3.select(this.parentNode).datum());
        }) 
    

    NB: in your fiddle, you only set the xlink:href in the enter() selection: this is wrong, you need to set it within the whole update selection.

    update.selectAll(".nodeimage") 
              .each(function() {
                 d3.select(this).datum(d3.select(this.parentNode).datum());
              }) 
              .attr("xlink:href", function(d){
                var img;
                if(d.np == 1){
                    img = "http://www.gravatar.com/avatar/1eccef322f0beef11e0e47ed7963189b/?default=&s=80"
                }else{
                    img = "http://www.gravatar.com/avatar/a1338368fe0b4f3d301398a79c171987/?default=&s=80";
                }
                return img;
              });
    

    See here: http://jsfiddle.net/cs4xhs7s/1/