【问题标题】:Cannot read property 'weight' of undefined and Cannot read property 'x' of undefined d3.js无法读取未定义的属性“权重”和无法读取未定义的 d3.js 的属性“x”
【发布时间】:2018-04-06 05:38:07
【问题描述】:

我在这里创建了一个小提琴来复制这个问题:fiddle link

在此之前,我们在项目中使用了一个不错的平面 json 文件。我必须使用的新文件更加嵌套。

我的 d3 函数如下所示:

/* chart data */
// return data for relationships between database tables
returnTableRelationshipData = function(){

    var url = 'https://api.myjson.com/bins/7ovnb.json';
    d3.json(url, function(data){

        //find the node index
        function find(f){
          var i = -1
            data.p.nodes.forEach(function(node, index){
                node.x = 200 + Math.random()*200;
                node.y = 150 + Math.random()*200;
                if(node.properties.nodeID.val == f)
                    i = index;
            });
            return i;
        }

        //set the source and target index
        data.p.relationships.forEach(function(d){
            d.start = find(d.start);
            d.end = find(d.end);
        });

        // used to store the number of links between two nodes. 
        var mLinkNum = {};

        // sort links first
        sortLinks();                                

        // set up linkIndex and linkNumer, because it may possible multiple links share the same source and target node
        setLinkIndexAndNum();

        // check that we don't have empty or null values
        checkDataNotEmpty();

        var w = 1000;
        var h = 400;

        var force = d3.layout.force()
            .nodes(data.p.nodes)
            .links(data.p.relationships)
            .alpha(.1)
            .gravity(1)
            .charge(-10000)
            .size([w, h])
            .start();

        var svg = d3.select('.node-wrapper').append('svg')
            .attr('width', w)
            .attr('height', h);

        var path = svg.append('svg:g')
            .selectAll('path')
            .data(force.links())
            .enter().append('line')
            .attr('class', 'link')
            .attr('x1', function(d) {
                return d.start.x;
            })
            .attr('y1', function(d) {
                return d.start.y;
            })
            .attr('x2', function(d) {
                return d.end.x;
            })
            .attr('y2', function(d) {
                return d.end.y;
            });

        var node_drag = d3.behavior.drag()
            .on('dragstart', dragstart)
            .on('drag', dragmove)
            .on('dragend', dragend);

        var circle = svg.append('svg:g')
            .selectAll('circle')
            .data(force.nodes())
            .enter().append('svg:circle')
            .attr('r', 6)
            .call(node_drag);

        var text = svg.append('svg:g')                                
            .selectAll('g')
            .data(force.nodes())
            .enter().append('svg:g');

        text.append('svg:text')
            .text(function(d){ 
                return d.description;
            });

        force.on('tick', tick);

        function tick() {
            path.attr('x1', function(d) {
                return d.start.x;
            })
            .attr('y1', function(d) {
                return d.start.y;
            })
            .attr('x2', function(d) {
                return d.end.x;
            })
            .attr('y2', function(d) {
                return d.end.y;
            });

            circle.attr('transform', function(d){
                return 'translate(' + d.x + ',' + d.y + ')';
            });

            text.attr('transform', function(d){
                return 'translate(' + d.x + ',' + d.y + ')';
            });
        }

        function dragstart(d, i) {
            force.stop(); // stops the force auto positioning before you start dragging
        }

        function dragmove(d, i) {
            d.px += d3.event.dx;
            d.py += d3.event.dy;
            d.x += d3.event.dx;
            d.y += d3.event.dy;
            tick();
        }

        function dragend(d, i) {
            d.fixed = true; // of course set the node to fixed so the force doesn't include the node in its auto positioning stuff
            tick();
        }

        // sort the links by source, then target
        function sortLinks(){
            if(data.p.relationships != null){                         
                data.p.relationships.sort(function(a,b){
                    if(a.start > b.start){
                        return 1;
                    }else if(a.start < b.start){
                        return -1;
                    }else{
                        if(a.end > b.end){
                            return 1;
                        }if(a.end < b.end){
                            return -1;
                        }else{
                            return 0;
                        }
                    }
                });
            }
        }

        //any links with duplicate source and target get an incremented 'linknum'
        function setLinkIndexAndNum(){                              
            for(var i = 0; i < data.p.relationships.length; i++){
                if(i != 0 &&
                    data.p.relationships[i].start == data.p.relationships[i-1].start &&
                    data.p.relationships[i].end == data.p.relationships[i-1].end){
                    data.p.relationships[i].linkindex = data.p.relationships[i-1].linkindex + 1;
                }else{
                    data.p.relationships[i].linkindex = 1;
                }// save the total number of links between two nodes
                if(mLinkNum[data.p.relationships[i].end + ',' + data.p.relationships[i].start] !== undefined){
                    mLinkNum[data.p.relationships[i].end + ',' + data.p.relationships[i].start] = data.p.relationships[i].linkindex;
                }else{
                    mLinkNum[data.p.relationships[i].start + ',' + data.p.relationships[i].end] = data.p.relationships[i].linkindex;
                }
            }
        }

        function checkDataNotEmpty(){
            data.p.relationships.forEach(function(link, index, list) {
                if (typeof link.start === 'undefined') {
                    console.log('undefined link', data.p.nodes[link.start]);
                }
                if (typeof link.end === 'undefined') {
                    console.log('undefined source', data.p.nodes[link.end]);
                }
            });
        }

    });
}();

根据answer,如果我注释掉这些行:

var force = d3.layout.force()
            //.nodes(data.p.nodes)
            //.links(data.p.relationships)
            .alpha(.1)
            .gravity(1)
            ...

然后将一个 svg 对象附加到 html 中。

链接的答案实际上并没有为此提供解决方案。

节点和链接似乎都被正确地迭代了。

我唯一的预感是我必须以某种方式将"start""end" 映射到sourcetarget,或者我需要以某种方式转换data.p.nodesdata.p.relationships。或者索引可能无法正常工作。

我能够与后端开发人员一起更改一些 json 属性和类型(字符串、整数等)。

正在从这里调用 json 文件:http://myjson.com/7ovnb

【问题讨论】:

  • 好的,我的节点正在工作,只是看不到路径连接。它们正在渲染,但没有通过 x1、x2、y1 等参数 jsfiddle.net/lharby/km4co7tz/4

标签: javascript json d3.js svg


【解决方案1】:
  1. 为链接定义一个笔触以使它们可见:

    .node-wrapper line {
      stroke: #0D9E1E;
    }
    
  2. tick() 函数中将所有出现的.start.source.end 重命名为.target

  3. 在您的find() 函数中,您必须与node.id 属性进行比较:

    function find(f){
      var i; // do not return an existing value as default
        data.p.nodes.forEach(function(node, index){
            node.x = 200 + Math.random()*200;
            node.y = 150 + Math.random()*200;
            if(node.id == f)
                i = index;
        });
        return i;
    }
    

    如果是现有节点索引,则索引 0,因此最好不要将其设置为默认值。

【讨论】:

  • 谢谢,我会在早上尝试实现它,让你知道我的进展情况。
  • 是的,做到了。非常感谢@ccprog
猜你喜欢
  • 1970-01-01
  • 2016-03-10
  • 2016-03-25
  • 2016-06-30
  • 1970-01-01
  • 2022-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多