25

D3 には、次のような厳密なツリーである有向グラフのさまざまなレイアウトがあります。

A
|\
B C
 / \
D   E

ツリーではなく、有向非巡回グラフであるノードの階層を描画する必要があります。これはツリー レイアウトの問題です。分岐のいくつかが収束するためです。

A
|\
B C
 \|
  D

一般的な階層の D3 レイアウトを知っている人はいますか? あるいは、既存のツリー レイアウトを巧妙にハックしますか? GraphVis はこの状況を適切に処理することに気付きましたが、D3 はここでの要件により適したグラフを生成します。

4

4 に答える 4

17

D3レイアウトに依存せずに、独自のコードを作成できます。

jsFiddleで例を示しました。この例はかなり単純であり、より複雑な例に対応するために少し作業する必要があります。

この例は、比較的少ない労力で階層データを処理するように作り直すことができます。

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;
});
于 2012-07-17T18:25:47.240 に答える
1

ツリーとデータ階層について一般的に言えば、B と C の両方の子リストに「D」が必要です。

ノード リストを作成するときは、「D」が 2 回表示されないように、一意の ID が返されていることを確認してください。

vis.selectAll("g.node").data(nodes, function(d) { return d.id; });

それからあなたが電話するとき

var links = tree.links(nodes)

D が「ターゲット」として 2 回表示され (B と C がそれぞれ「ソース」として)、1 つのノード「D」への 2 つの行が表示されるはずです。

于 2012-07-11T22:18:17.620 に答える