我正在使用d3js和hierarchical layout开展数据可视化工作。我的数据如下:
0
/ | \
/ | \
1 5 3
\ | |
\ | |
4 /
| /
2
由于我无法链接到多个父级,因此我复制了显示的节点:
0
/ | \
/ | \
1 5 3
| | |
| | |
4 4 |
| | |
2 2 2
我已经fiddle demo显示了我的问题:
这是我用来解析输入的循环:
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);
}
对我来说:控制台中的两个打印元素都是相同的,但不是布局的渲染。对象引用中可能存在一些不同之处。
我发现一个糟糕的解决方案是解码然后编码我的var:
var root = JSON.parse(JSON.stringify(root));
然后脚本运行良好。但是我的root是一个很长的数组,解析需要很长时间......
有什么想法解释为什么我需要使用编码/解码来显示相同的东西吗?
谢谢
答案 0 :(得分:1)
您应该编码/解码JSON以防止浅拷贝。要了解更多关于deepcopy和shallowcopy的信息,请点击链接。 What is the difference between a deep copy and a shallow copy?
作为 var root = JSON.parse(JSON.stringify(root)); 防止浅拷贝是一种错误的方法,你可以使用jquery的克隆方法或简单的javascripts切片方法来深度复制javascript数组。
例如,。
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)
另一种解决方案是使用下划线。如果您不想要完整的下划线javascript代码,那么您可以在下划线库中选择克隆部分。
在下划线中,您可以使用以下方法克隆对象数组:
var a = [{f: 1}, {f:5}, {f:10}];
var b = _.map(a, _.clone); // <----
b[1].f = 55;
console.log(JSON.stringify(a));
会打印
[{"f":1},{"f":5},{"f":10}]
答案 1 :(得分:1)
你可以用这样的东西替换你的for循环,但是不要知道性能。 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);
}
}
}
答案 2 :(得分:1)
注意:强> 表现不如原帖,请参阅下面的评论。这种方式是可扩展的,所以无论对象(和标志看起来像什么),它都应该工作
<强>答案强>
这是&#34;深拷贝&#34;根据@transcranial和@LaxmikantDange的建议。
我建议使用jquery(我的首选方法:少写,做更多)并使用其extend
例程:
<<load jquery>>
root = $.extend(true, {}, root[1].Nodes[0]);
graph(root2,svg);
graph(root,svg2);
请确保您true
作为第一个参数,如http://api.jquery.com/jquery.extend/或此处What is the most efficient way to deep clone an object in JavaScript?(最佳答案)
不确定性能,但我希望它不是太糟糕。如果你测试,请告诉我!
请注意,根据您的申请(断开的链接等),深层副本可能会有问题。例如,我最近构建了一个在图表之间共享事件的反应应用程序 - 并且共享例如缩放事件(调整渲染对象)不会自动共享&#34; (因为对象是分开的,如果你知道我的意思。
答案 3 :(得分:0)
当您将其他节点(对象)推送到子节点数组上时,必须克隆这些对象(深度复制)。重新分配&#34; =&#34;仅适用于字符串或数字数组。在将子节点推送到阵列之前深度复制子节点会修复布局和渲染。
将子节点推送到数组中的原始代码:
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 (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)));
}
检查出来:JSFiddle。
此外,包括群集在内的d3层次布局支持多个父项开箱即用。为此,您可以尝试使用强制图布局。