D3JS 在编码解码数据后工作

d3js works after encode decode data

本文关键字:工作 数据 解码 编码 D3JS      更新时间:2023-09-26

我正在使用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:

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

然后脚本效果很好。但是我的根是一个很长的数组,解析需要很长时间...

有什么想法可以解释为什么我需要使用该编码/解码来显示相同的东西吗?

谢谢

你可以用这样的东西替换你的 for 循环,但不知道性能。斯菲德尔

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

您应该对 JSON 进行编码/解码以防止浅拷贝。要了解有关深拷贝和浅拷贝的更多信息,这里是链接。深拷贝和浅拷贝有什么区别?

如 var root = JSON.parse(JSON.stringify(root));是防止浅拷贝的错误方法,可以使用jQuery的Clone方法或简单的JavaScript切片方法来深度复制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}]

注意:性能不如原始帖子,请参阅下面的评论。这种方式是可扩展的,所以无论对象(和标志是什么样子),它都应该工作

这是@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/或此处所示 在 JavaScript 中深度克隆对象的最有效方法是什么?(热门答案)

不确定性能,但我希望它不会太糟糕。如果您测试,请告诉我!

也请不要说,根据您的应用程序(断开的链接等),深副本可能会有问题。例如,我最近构建了一个在图形之间共享事件的 react 应用程序 - 并且共享例如缩放事件(调整渲染对象)不会"自动共享"(因为对象是分开的,如果你明白我的意思。

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

用于将子节点推送到数组中的原始代码:

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 分层布局不支持开箱即用的多个父级。为此,您可以尝试使用力图布局。