在d3.js中配置固定布局的静态图形

19

我有一个工作的代码示例(仅包含 <script type="text/javascript"> 部分),使用 d3.js 制作静态图表,如下:

        /* Create graph data */
        var nodes = [];
        for (var i = 0; i < 13; i++) 
        {
            var datum = {
                "value": i
            };
            nodes.push(datum);
        }

        var links = [{"source": 0, "target": 1},
                     {"source": 1, "target": 2},
                     {"source": 2, "target": 0},
                     {"source": 1, "target": 3},
                     {"source": 3, "target": 2},
                     {"source": 3, "target": 4},
                     {"source": 4, "target": 5},
                     {"source": 5, "target": 6},
                     {"source": 5, "target": 7},
                     {"source": 6, "target": 7},
                     {"source": 6, "target": 8},
                     {"source": 7, "target": 8},
                     {"source": 9, "target": 4},
                     {"source": 9, "target": 11},
                     {"source": 9, "target": 10},
                     {"source": 10, "target": 11},
                     {"source": 11, "target": 12},
                     {"source": 12, "target": 10}];

        /* Create force graph */
        var w = 800;
        var h = 500;

        var size = nodes.length;
        nodes.forEach(function(d, i) { d.x = d.y = w / size * i});

        var svg = d3.select("body").append("svg")
                    .attr("width", w)
                    .attr("weight", h);

        var force = d3.layout.force()
                      .nodes(nodes)
                      .links(links)
                      .linkDistance(200)
                      .size([w, h]);

        setTimeout(function() {

            var n = 400
            force.start();
            for (var i = n * n; i > 0; --i) force.tick();
            force.stop();

            svg.selectAll("line")
               .data(links)
               .enter().append("line")
               .attr("class", "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; });

            svg.append("svg:g")
               .selectAll("circle")
               .data(nodes)
               .enter().append("svg:circle")
               .attr("class", "node")
               .attr("cx", function(d) { return d.x; })
               .attr("cy", function(d) { return d.y; })
               .attr("r", 15);

            svg.append("svg:g")
               .selectAll("text")
               .data(nodes)
               .enter().append("svg:text")
               .attr("class", "label")
               .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
               .attr("text-anchor", "middle")
               .attr("y", ".3em")
               .text(function(d) { return d.value; });

        }, 10);

代码产生的图形布局混乱,如下:

enter image description here

虽然在技术上是正确的图形,但理想的布局应该像这样(忽略不同的视觉图形):

enter image description here

注意,布局应该固定,以便重新加载页面不会改变每个节点的位置;布局还应该是静态的,没有动画效果,并且节点不能拖动。这两个要求在上面的脚本中已经实现。

那么,我应该如何进一步配置这个d3脚本以产生第二幅图中显示的布局?

1个回答

32

首先,增加电荷强度减小连接距离。这样做会更加注重全局结构而不是本地连接。此外,如果你增加足够强的电荷强度,排斥力将会把直接连接的节点彼此推远,从而有效地增加连接距离,同时给出更好的整体结构。(增强电荷力的缺点是图形初始化更加混乱,但对于静态布局来说,这不应该是一个问题。)

其次,您可能需要增加迭代次数添加自定义力以获得更好的结果。力导向布局通常在任意图形上都能工作良好,但不能保证它们会产生最佳(甚至好的)结果。对于任何可以简化假设的图形(例如树状结构),可能有其他力或约束条件可以应用,以促使模拟收敛到更好的解决方案。


3
更大的电荷强度和更小的链接距离可以解决问题。关于添加自定义力,有没有我可以遵循的示例/教程?还能否举一些应用于更好收敛的其他约束条件的例子?非常感谢! - MLister
8
有关自定义力的信息,请参见我的有关力学布局的演讲和相关幻灯片。 - mbostock

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接