如何使用D3布局非树层次结构 [英] How to layout a non-tree hierarchy with D3
问题描述
D3有许多针对严格树的有向图的布局,例如:
D3 has a variety of layouts for directed graphs that are strict trees, such as the following:
A
|\
B C
/ \
D E
我需要绘制一个不是树的节点的层次结构,而是一个有向无环图。这是一个树布局的问题,因为几个分支收敛:
I need to draw a hierarchy of nodes that is not a tree, but is a directed acyclic graph. This is a problem for a tree layout, because several of the branches converge:
A
|\
B C
\|
D
有没有人知道一般层次结构的D3布局?或者,一些聪明的黑客到现有的treelayout?我已经注意到GraphVis处理这种情况很好,但D3生成一个更适合这里的要求的图。
Does anyone know of a D3 layout for general hierarchies? Or alternatively, some clever hack to the existing treelayout? I've noticed GraphVis handles this situation well, but D3 produces a graph that better suits the requirements here.
推荐答案
我已经提供了一个 example in a jsFiddle 。这个例子是相当简单的,需要做一点工作以适应更复杂的例子。
I've provided an example in a jsFiddle. The example is pretty simplistic and would need to be worked a little bit to accommodate more complex examples.
此示例可以重新工作,以便以相对较少的努力处理分层数据。
The example could be re-worked to process hierarchical data as well with relatively little effort.
我在jsFiddle中使用的代码:
Here is the code I have used in the jsFiddle:
// Sample data set
var json = {
nodes: [{
name: 'A'},
{
name: 'B'},
{
name: 'C'},
{
name: 'D'}],
links: [{
source: 'A',
target: 'B'},
{
source: 'A',
target: 'C'},
{
source: 'B',
target: 'D'},
{
source: 'C',
target: 'D'}
]
};
var vis = d3.select('#vis').attr('transform', 'translate(20, 20)');
// Build initial link elements - Build first so they are under the nodes
var links = vis.selectAll('line.link').data(json.links);
links.enter().append('line').attr('class', 'link').attr('stroke', '#000');
// Build initial node elements
var nodes = vis.selectAll('g.node').data(json.nodes);
nodes.enter().append('g').attr('class', 'node').append('circle').attr('r', 10).append('title').text(function(d) {
return d.name;
});
// Store nodes in a hash by name
var nodesByName = {};
nodes.each(function(d) {
nodesByName[d.name] = d;
});
// Convert link references to objects
links.each(function(link) {
link.source = nodesByName[link.source];
link.target = nodesByName[link.target];
if (!link.source.links) {
link.source.links = [];
}
link.source.links.push(link.target);
if (!link.target.links) {
link.target.links = [];
}
link.target.links.push(link.source);
});
// Compute positions based on distance from root
var setPosition = function(node, i, depth) {
if (!depth) {
depth = 0;
}
if (!node.x) {
node.x = (i + 1) * 40;
node.y = (depth + 1) * 40;
if (depth <= 1) {
node.links.each(function(d, i2) {
setPosition(d, i2, depth + 1);
});
}
}
};
nodes.each(setPosition);
// Update inserted elements with computed positions
nodes.attr('transform', function(d) {
return 'translate(' + d.x + ', ' + d.y + ')';
});
links.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;
});
这篇关于如何使用D3布局非树层次结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!