【问题标题】:Force Directed Graph Error, "Cannot Read Property 'Push' of Undefined"强制有向图错误,“无法读取未定义的属性‘推送’”
【发布时间】:2016-12-18 20:26:10
【问题描述】:

我是编码新手,最近开始使用 d3 生成力有向图。使用链接派生节点时,我成功生成了一个四节点图。但是,当我明确列出节点时,我收到错误“Uncaught TypeError: Cannot read property 'push' of undefined (d3.v3.min.js)”。我研究了对以下两个类似问题的回答,但无法使用答案解决此问题。我试图尽可能多地删除不相关的功能,谢谢。

JavaScript error "Uncaught TypeError: Cannot call method 'push' of undefined" D3.js

Uncaught TypeError: Cannot call method 'push' of undefined (d3 force layout)

强制有向图失败:

<script type="text/javascript" src="d3.v3.min.js"> </script>

<script>

var width = 900,
    height = 590;

var svg = d3.select("body")
        .append("svg")
        .attr("width", width)
        .attr("height", height)

var links = [
    {source: 'H', target: 'I'},
    {source: 'H', target: 'J'},
    {source: 'I', target: 'J'},
    {source: 'J', target: 'K'},
];

var nodes = [ 
    {name: 'H'},
    {name: 'I'},
    {name: 'J'},
    {name: 'K'},
];

var force = d3.layout.force()
    .size([width, height])
    .nodes(d3.values(nodes))
    .links(links)
    .on('tick', tick)
    .linkDistance(100)
    .gravity(.15)
    .friction(.8)
    .linkStrength(1)
    .charge(-425)
    .chargeDistance(600)
    .start();

var link = svg.selectAll('.link')
    .data(links)
    .enter().append('line')
    .attr('class', 'link');

var node = svg.selectAll('.node')
    .data(force.nodes())
    .enter().append('circle')
    .attr('class', 'node')
    .attr('r', width * 0.01)

function tick(e) {

    node.attr('cx', function(d) { return d.x; })
        .attr('cy', function(d) { return d.y; })
        .call(force.drag);

    link.attr('x1', function(d) { return d.source.x; })
        .attr('y1', function(d) { return d.source.y; })
        .attr('x2', function(d) { return d.target.x; })
        .attr('y2', function(d) { return d.target.y; });

};

    </script>

强制有向图工作:

<script type="text/javascript" src="d3.v3.min.js"> </script>

<script>

var width = 900,
    height = 590;

var svg = d3.select("body")
        .append("svg")
        .attr("width", width)
        .attr("height", height)

var links = [
    {source: 'H', target: 'I'},
    {source: 'H', target: 'J'},
    {source: 'I', target: 'J'},
    {source: 'J', target: 'K'},
];

var nodes = {};
links.forEach(function(link) {
    link.source = nodes[link.source] ||
        (nodes[link.source] = {name: link.source});
    link.target = nodes[link.target] ||
        (nodes[link.target] = {name: link.target});
        });

var force = d3.layout.force()
    .size([width, height])
    .nodes(d3.values(nodes))
    .links(links)
    .on('tick', tick)
    .linkDistance(100)
    .gravity(.15)
    .friction(.8)
    .linkStrength(1)
    .charge(-425)
    .chargeDistance(600)
    .start();

var link = svg.selectAll('.link')
    .data(links)
    .enter().append('line')
    .attr('class', 'link');

var node = svg.selectAll('.node')
    .data(force.nodes())
    .enter().append('circle')
    .attr('class', 'node')
    .attr('r', width * 0.01)

function tick(e) {

    node.attr('cx', function(d) { return d.x; })
        .attr('cy', function(d) { return d.y; })
        .call(force.drag);

    link.attr('x1', function(d) { return d.source.x; })
        .attr('y1', function(d) { return d.source.y; })
        .attr('x2', function(d) { return d.target.x; })
        .attr('y2', function(d) { return d.target.y; });

};

    </script>

【问题讨论】:

    标签: javascript d3.js force-layout


    【解决方案1】:

    API 文档有它:

    注意:源属性和目标属性的值最初可以指定为 nodes 数组的索引;这些将在调用开始后被引用替换。

    链接数组需要通过索引或节点对象的引用来引用节点。在您的工作示例中,这是在从链接创建节点时完成的:

    link.source =                                   // (3)
        nodes[link.source] ||                       // (1)
        (nodes[link.source] = {name: link.source}); // (2)
    

    这将 (1) 使用来自 link.source 的节点的文字名称,例如 H,并从 nodes 数组中获取节点对象(如果它已经存在)。如果在 nodes 数组中找不到它,则评估 || 运算符的右侧,这将 (2) 创建一个新节点对象并将其放入数组中。在任何一种情况下,整个表达式 (1) || (2) 将评估为节点对象的引用,然后 (3) 将其分配给 link.source。因此,您不仅要从链接创建节点,还要更改链接本身。初始化之后,您的链接数组将如下所示:

    [
      {source: { name: 'H' }, target: { name: 'I' }},
      {source: { name: 'H' }, target: { name: 'J' }},
      {source: { name: 'I' }, target: { name: 'J' }},
      {source: { name: 'J' }, target: { name: 'K' }},
    ];
    

    您现在已准备好链接数组,其中包含对节点对象的引用的所有链接对象的 sourcetarget 属性。


    如果您已经准备好节点的对象,您可以通过放入引用来自己初始化链接数组,或者您可以通过索引引用节点将其留给 D3:

    var links = [
        {source: 0, target: 1},
        {source: 0, target: 2},
        {source: 1, target: 2},
        {source: 2, target: 3},
    ];
    
    var nodes = [ 
        {name: 'H'},
        {name: 'I'},
        {name: 'J'},
        {name: 'K'},
    ];
    

    将其放入您的非工作示例中将使其按预期工作:

    var width = 600,
        height = 400;
    
    var svg = d3.select("body")
            .append("svg")
            .attr("width", width)
            .attr("height", height)
    
    var links = [
        {source: 0, target: 1},
        {source: 0, target: 2},
        {source: 1, target: 2},
        {source: 2, target: 3},
    ];
    
    var nodes = [ 
        {name: 'H'},
        {name: 'I'},
        {name: 'J'},
        {name: 'K'},
    ];
    
    var force = d3.layout.force()
        .size([width, height])
        .nodes(d3.values(nodes))
        .links(links)
        .on('tick', tick)
        .linkDistance(100)
        .gravity(.15)
        .friction(.8)
        .linkStrength(1)
        .charge(-425)
        .chargeDistance(600)
        .start();
    
    var link = svg.selectAll('.link')
        .data(links)
        .enter().append('line')
        .attr('class', 'link');
    
    var node = svg.selectAll('.node')
        .data(force.nodes())
        .enter().append('circle')
        .attr('class', 'node')
        .attr('r', width * 0.01)
    
    function tick(e) {
    
        node.attr('cx', function(d) { return d.x; })
            .attr('cy', function(d) { return d.y; })
            .call(force.drag);
    
        link.attr('x1', function(d) { return d.source.x; })
            .attr('y1', function(d) { return d.source.y; })
            .attr('x2', function(d) { return d.target.x; })
            .attr('y2', function(d) { return d.target.y; });
    
    };
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"&gt;&lt;/script&gt;

    【讨论】:

    • 谢谢,使用从 0 开始的索引很清楚。但是,如果我重新构建链接以将链接指定为 {source: {name: 'H'}, target: {name: 'I'}},因为您指出 d3 执行,为什么脚本会失败?
    • 当使用像这样的对象文字符号构建链接数组时,您正在创建新对象,例如{name: 'H'} 然后分配给,比如说,source。这样,您的链接数组中就有节点对象,以及节点数组中完全不同的节点对象,它们没有以任何方式连接。他们只是碰巧共享通用名称属性。 sourcetarget 属性真正需要的是对节点数组中对象的reference。这样他们就可以连接到 D3 的算法。
    • 这些引用可以由您自己的代码(如在您的工作示例中)或由 D3 分配,如果您将索引值传递给节点对象(如在我的示例中)。
    【解决方案2】:

    就我而言,当我给出节点索引的链接的源或目标值是一个字符串时,我遇到了这个问题。

    【讨论】:

    • 我所有的源和目标都是带有数字 ID 的对象。想知道为什么我仍然得到这个 =(
    猜你喜欢
    • 2017-08-12
    • 1970-01-01
    • 2021-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-06
    相关资源
    最近更新 更多