Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

d3js works after encode decode data

I'm working on a visualization of data with d3js and hierarchical layout. My data looks like this:

       0
     / | \
    /  |  \ 
   1   5   3
    \  |   |
     \ |   |
       4  /
       | /
       2

As I can't make link to multiple parent, I duplicates nodes on display:

       0
     / | \
    /  |  \ 
   1   5   3
   |   |   |
   |   |   |
   4   4   |
   |   |   |
   2   2   2

I've made a fiddle demo to show my problem:

  • When I use correct data in my JSON input, I have the good layout (graphic in border blue).
  • When I use a loop to parse my JSON input, I have strange graph (graphic in border green).

This is the loop I used to parse the input:

for (i in root[2].Arcs){
  var d = root[1].Nodes[root[2].Arcs[i].D];
  var s = root[1].Nodes[root[2].Arcs[i].S];
  if (!d.children){
    d.children = [];
  }
  d.children.push(s);
}

For me : both printed element in console are the same, but not the render of layout. There are maybe some differents in object reference.

A bad solution I found is to decode then encode my var :

    var root = JSON.parse(JSON.stringify(root));

Then the script works good. But I root is a long long array, the parsing takes long time...

Any idea to explain why I need to use that encode/decode to display same things ?

Thank you

like image 278
Matthieu Avatar asked Oct 19 '22 22:10

Matthieu


2 Answers

You can replace your for loop with something like this, don't know about performance though. jsfiddle

traverse(root[1].Nodes[0]);
function traverse(node) {
    for (i in root[2].Arcs) {
        var d = root[1].Nodes[root[2].Arcs[i].D];
        if (node.name === root[2].Arcs[i].D) {
            var s = root[1].Nodes[root[2].Arcs[i].S];
            var sCopy={
                "name": s.name
            }
            traverse(sCopy);
            if (!node.children) {
               node.children = [];
            }
            node.children.push(sCopy);
        }
    }
}
like image 188
ylamaki Avatar answered Oct 30 '22 17:10

ylamaki


You are supposed to encode/decode JSON to prevent shallow copy. To know more what about deepcopy and shallowcopy, here is link. What is the difference between a deep copy and a shallow copy?

As var root = JSON.parse(JSON.stringify(root)); is a wrong way to prevent shallow copy, you can use jquery's clone method or simply javascripts slice method to deepcopy javascript array.

for example.

var d=[1,2,3,4,5,6];//create array
var b=d;//copy array into another array (shallow copy/reference copy)
var e=d.slice();//clone array in another variable (deep copy)
d[0]=9; //change array element
console.log(d)// result : [9,2,3,4,5,6] (changed array)
console.log(b)// result : [9,2,3,4,5,6] (changed array due to reference)
console.log(e)// result : [1,2,3,4,5,6] (unchanged array due to deep copy)

There is another solution is use underscore. If you don't want full javascript code of underscore, then you can pick cloning portion in underscore library.

In underscore, you can clone object array using:

var a = [{f: 1}, {f:5}, {f:10}];
var b = _.map(a, _.clone);       // <----
b[1].f = 55;
console.log(JSON.stringify(a));

It will Print

[{"f":1},{"f":5},{"f":10}]
like image 20
Laxmikant Dange Avatar answered Oct 30 '22 16:10

Laxmikant Dange