D3 - позиционирование ребер приводит к ошибкам NaN

Основываясь на руководстве Стивена Томаса https://github.com/sathomas/jsDataV.is-source/tree/master/ch7/force, я попытался создать диаграмму раскладки силы d3.

Тем не менее, я застрял на ошибке, которую я не знаю, происхождение и как ее устранить.

С учетом следующего плунжера http://plnkr.co/edit/Bx0qe8DNEsnFgLhkxbfS?p=preview вызывает этот фрагмент

 var positionEdge = function(edge, nodes) {
        edge.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; });
    };

Многие ошибки, например Ошибка: Неверное значение для атрибута y2="NaN"

Я строю свой массив ребер следующим образом, но чтобы полностью воспроизвести проблему, используйте ссылку plunker:

 var edges = [];
        links.forEach(function(srcLink){
            var targetNodeId;
            var targetNodeName;
            var sourceNodeId;
            var sourceNodeName;

            nodes.forEach(function(srcNode){
              if(srcNode.label === srcLink.source){
                  sourceNodeId = srcNode.id;
                  sourceNodeName = srcNode.label;
              } else if(srcNode.label === srcLink.target){
                  targetNodeId = srcNode.id;
                  targetNodeName = srcNode.label;
              }
            })
            edges.push({
                "id": "From_" + sourceNodeName + "_To_" + targetNodeName,
                "target": targetNodeId,
                "source": sourceNodeId
            });
        })

        // remove duplicate edges
        var arr = {};
        for ( var i=0, len=edges.length; i < len; i++ )
            arr[edges[i]['id']] = edges[i];

        edges = new Array();
        for ( var key in arr )
            edges.push(arr[key]);

Что вызывает все ошибки NaN, возникающие при вызове функции positionEdge?

1 ответ

Решение

Кажется, что source а также target поля в ваших краях - это идентификаторы узлов, а не объекты. У вас есть два решения:

  • использовать объекты:

       edges.push({
            "id": "From_" + sourceNodeName + "_To_" + targetNodeName,
            "target": nodes[targetNodeId],
            "source": nodes[sourceNodeId]
        });
    

или же

  • использовать индексы (плохая идея, см. примечание редактирования ниже)

    var positionEdge = function(edge, nodes) {
        edge.attr("x1", function(d) { return nodes[d.source].x; })
            .attr("y1", function(d) { return nodes[d.source].y; })
            .attr("x2", function(d) { return nodes[d.target].x; })
            .attr("y2", function(d) { return nodes[d.target].y; });
    };
    

Стандарт в d3 это использовать первый вариант, но могут быть и другие изменения, чтобы внести в ваш код, если вы пойдете на это. Со вторым вариантом вы будете зависеть от использования узлов [d.source] и узлов [d.target] каждый раз, когда вам нужна конечная точка ребра.


Редактировать: На самом деле, force Компоновка автоматически преобразует основанные на индексе ребра в основанные на объекте. Поэтому, если вы не используете два разных массива для ребер, вам нужно перейти к первому варианту.

Другие вопросы по тегам