Javascript d3js在编码和解码数据后工作

Javascript d3js在编码和解码数据后工作,javascript,json,d3.js,Javascript,Json,D3.js,我正在使用d3js和。我的数据如下所示: 0 / | \ / | \ 1 5 3 \ | | \ | | 4 / | / 2 由于我无法链接到多个父节点,因此我复制了显示的节点: 0 / | \ / | \ 1 5 3 | | | | | | 4 4 | | | |

我正在使用d3js和。我的数据如下所示:

       0
     / | \
    /  |  \ 
   1   5   3
    \  |   |
     \ |   |
       4  /
       | /
       2
由于我无法链接到多个父节点,因此我复制了显示的节点:

       0
     / | \
    /  |  \ 
   1   5   3
   |   |   |
   |   |   |
   4   4   |
   |   |   |
   2   2   2
我已经做了一个实验来说明我的问题:

  • 当我在JSON输入中使用正确的数据时,我有良好的布局(蓝色边框的图形)
  • 当我使用循环解析JSON输入时,我看到了一个奇怪的图形(绿色边框的图形)
这是我用来解析输入的循环:

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 root = JSON.parse(JSON.stringify(root));
那么剧本就很好了。但我根是一个长数组,解析需要很长时间

有没有办法解释为什么我需要使用编码/解码来显示相同的东西


谢谢

您应该对JSON进行编码/解码以防止浅层复制。要了解有关deepcopy和shallowcopy的更多信息,请访问链接。

作为 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));

您可以用这样的东西替换for循环,但不知道性能如何。


将其他节点(即对象)推送到子节点阵列上时,必须克隆(深度复制)这些对象。重新分配“=”仅适用于字符串或数字数组。在将子节点推送到阵列上之前,深入复制它们可以修复布局和渲染

将子节点推入阵列的原始代码:

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)));
}
请查看:

此外,d3分层布局(包括集群)不支持有多个现成的父级。为此,您可以尝试使用力图布局。

注意: 表现不如原来的帖子,见下面的评论。这种方式意味着是可伸缩的,因此无论对象(和标志)是什么样子,它都应该工作

回答

下面是@transcranial和@LaxmikantDange建议的“深度复制”方法的另一个例子

我建议使用jquery(我首选的方法:少写,多做)并使用它的
extend
例程:

<<load jquery>>

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

root=$.extend(true,{},根[1]。节点[0]);
图形(root2,svg);
图(根,svg2);
确保将
true
作为第一个参数,如此处或此处所示(顶部答案)

不确定性能,但我希望不是太差。如果你测试,请让我知道


也请注意,深度副本可能会有问题,这取决于您的应用程序(断开的链接等)。例如,我最近构建了一个react应用程序,它可以在图形之间共享事件,而共享(例如缩放事件(调整渲染对象))不会“自动共享”(因为对象是分开的,如果你知道我的意思的话。

1.root的json数据与root2的不同。2.我不知道你想做什么。你的变量名是没有意义的字母,如S或D,你的代码完全没有注释。不清楚什么代码使用哪种技术。是的,它不是相同的数据:我需要解析root有类似于root2的东西…名称或代码并不重要:我想知道“为什么当我使用两个在所有方面都相同的变量时,结果不一样?”。另外,请检查。它可能更适合您的需要,并完全消除您的问题;)我确信问题不是来自viz的库。我做了一个小的JSFIDLE演示,我有很多使用d3js的后台代码。浅拷贝就是我在绿色边框图中所做的:好吧,它不起作用。但我不相信你的建议:我试着使用切片,这是同一个错误。如果你的数组是对象数组,那么数组元素ents(对象)是浅层复制的。您也需要克隆该对象。关于性能(文件:90ko、780nodes和906links):我的小循环+json.stringify()+json.parse()在大约26毫秒内执行。您的解决方案:~872.548毫秒。这太糟糕了,怀疑速度太慢。要回答您的问题,为什么即使数据看起来相同,root也不能工作。问题是,在您的三个实例中,同一个对象被添加了多次,但需要作为不同的实例添加。例如,1和5都有一个子对象我知道分层布局不支持多个父级,这就是为什么我复制了一些路径(这对我来说不是问题)。还有其他方法,但这可能是最简单的。请参阅和。当一些人谈到深度复制时,我使用进行了一些测试。例如:780个节点和906个链接,使用
$.extend(true,{},oldObject);
,使用
JSON.parse(JSON.stringify(oldObject))克隆大约需要200毫秒
和~1800ms,使用定制的@ylamaki解决方案function@Matthieu:谢谢,有趣的输入!我喜欢
$.extend
的方式,因为它是“可伸缩的”,所以当我更改对象等时,它应该仍然可以工作。但是如果性能是一个问题,我同意特定的功能更快。(在我的答案顶部添加注释)
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)));
}
<<load jquery>>

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