强制定向图错误,"Cannot Read Property 'Push' of Undefined"
Force Directed Graph Error, "Cannot Read Property 'Push' of Undefined"
我是编码新手,最近开始使用 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>
API 文档有:
Note: the values of the source and target attributes may be initially specified as indexes into the nodes array; these will be replaced by references after the call to start.
links 数组需要通过索引或通过引用节点的对象来引用节点。在您的工作示例中,这是在从 links:
创建节点时完成的
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
。因此,您不仅是从 links 创建节点,而且还改变了 links 本身。初始化后,您的 links 数组将如下所示:
[
{source: { name: 'H' }, target: { name: 'I' }},
{source: { name: 'H' }, target: { name: 'J' }},
{source: { name: 'I' }, target: { name: 'J' }},
{source: { name: 'J' }, target: { name: 'K' }},
];
您现在已经准备好 links 数组,其中包含对节点对象的引用的所有 link 对象的 source
和 target
属性。
如果您已经准备好节点的对象,您可以通过将引用放入自己来初始化 links 数组,或者您可以通过索引引用节点将其留给 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; });
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
在我的例子中,当给出节点索引的链接的源或目标值是一个字符串时,我遇到了这个问题。
我是编码新手,最近开始使用 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>
API 文档有:
Note: the values of the source and target attributes may be initially specified as indexes into the nodes array; these will be replaced by references after the call to start.
links 数组需要通过索引或通过引用节点的对象来引用节点。在您的工作示例中,这是在从 links:
创建节点时完成的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
。因此,您不仅是从 links 创建节点,而且还改变了 links 本身。初始化后,您的 links 数组将如下所示:
[
{source: { name: 'H' }, target: { name: 'I' }},
{source: { name: 'H' }, target: { name: 'J' }},
{source: { name: 'I' }, target: { name: 'J' }},
{source: { name: 'J' }, target: { name: 'K' }},
];
您现在已经准备好 links 数组,其中包含对节点对象的引用的所有 link 对象的 source
和 target
属性。
如果您已经准备好节点的对象,您可以通过将引用放入自己来初始化 links 数组,或者您可以通过索引引用节点将其留给 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; });
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
在我的例子中,当给出节点索引的链接的源或目标值是一个字符串时,我遇到了这个问题。