D3js works after encoding decoding data

I am working on data visualization with the d3js and hierarchy. My data is as follows:

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

Since I canโ€™t link to multiple parents, I duplicate the nodes in the display:

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

I did a demo to show my problem:

  • When I use the correct data in my JSON input, I have a nice layout (graphic in blue).
  • When I use a loop to parse my JSON input, I have a weird graph (graphic symbol in the green area).

This is the loop I used to parse 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 print elements in the console are the same, but not a render of the layout. There may be some differences in the object link.

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

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

Then the script works well. But I am root - a long long array, parsing takes a lot of time ...

Any idea to explain why I need to use this encoding / decoding to display the same thing?

thanks

+5
source share
4 answers

You must encode / decode JSON to prevent a shallow copy. To learn more about deep topography and shallow copy, here is the link. What is the difference between a deep copy and a shallow copy?

How var root = JSON.parse (JSON.stringify (root)); is the wrong way to prevent a shallow copy, you can use the jquery clone method or just the javascripts slice method for the javascript deepcopy array.

eg.

 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) 

Another solution is to use underscores. If you do not need the full javascript underscore code, you can select the cloning part in the underscore library.

In underlining, you can clone an array of objects using:

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

He will print

 [{"f":1},{"f":5},{"f":10}] 
+1
source

You can replace the for loop with something like this, but don't know about performance. 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); } } } 
+1
source

Note: Performance is not as good as the original post, see comments below. This method is intended for scaling, so no matter what object (and flags) looks like this, it should work

Answer

Here's another โ€œdeep copyโ€ approach suggested by @transcranial and @LaxmikantDange.

I suggest using jquery (my preferred approach: write less, do more) and use its extend procedure:

 <<load jquery>> root = $.extend(true, {}, root[1].Nodes[0]); graph(root2,svg); graph(root,svg2); 

Make sure you have this true as the first argument, which can be seen here http://api.jquery.com/jquery.extend/ or here What is the most efficient way to deeply clone an object in JavaScript? (top answer)

Not sure about performance, but hope this is not so bad. If you check, please let me know!

Please also do not allow a deep copy to be questionable depending on your application (broken links, etc.). For example, I recently created a response application that shares events between charts - and shares, for example. scaling events (which adjust the rendered object) are not "automatically separated" (because the objects are separate if you know what I mean.

+1
source

When you click additional nodes (objects) on your arrays of child nodes, these objects must be cloned (deeply copied). Redistributing "=" only works for string or numeric arrays. Deep copying of your child nodes, before clicking them on your array, corrects the layout and rendering.

Source code for pushing child nodes into an array:

 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); } 

Modified:

 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(JSON.parse(JSON.stringify(s))); } 

Check this out: JSFiddle .

In addition, d3 hierarchies, including the cluster, do not support having multiple parents out of the box. To do this, you can try to use the power graph layout.

0
source

Source: https://habr.com/ru/post/1207105/


All Articles