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
Компоновка автоматически преобразует основанные на индексе ребра в основанные на объекте. Поэтому, если вы не используете два разных массива для ребер, вам нужно перейти к первому варианту.