【问题标题】:Space out nodes evenly around root node in D3 force layout在 D3 强制布局中将节点均匀分布在根节点周围
【发布时间】:2015-06-20 18:24:45
【问题描述】:

我刚从 D3 开始,所以如果有人对我可能做得不正确/最佳的事情有任何一般性建议,请告诉我 :)

我正在尝试创建一个力有向图,其中节点在中心根节点周围均匀分布(或足够接近)(以较大的尺寸表示)。

这是我试图实现的布局示例(我知道它不会每次都相同):

我有以下图表:

var width = $("#theVizness").width(),
    height = $("#theVizness").height();

var color = d3.scale.ordinal().range(["#ff0000", "#fff000", "#ff4900"]);

var force = d3.layout.force()
    .charge(-120)
    .linkDistance(30)
    .size([width, height]);

var svg = d3.select("#theVizness").append("svg")
    .attr("width", width)
    .attr("height", height);

var loading = svg.append("text")
    .attr("class", "loading")
    .attr("x", width / 2)
    .attr("y", height / 2)
    .attr("dy", ".35em")
    .style("text-anchor", "middle")
    .text("Loading...");

/*
ForceDirectData.json
{
    "nodes":[
      {"name":"File1.exe","colorGroup":0},
      {"name":"File2.exe","colorGroup":0},
      {"name":"File3.exe","colorGroup":0},
      {"name":"File4.exe","colorGroup":0},
      {"name":"File5.exe","colorGroup":0},
      {"name":"File6.exe","colorGroup":0},
      {"name":"File7.exe","colorGroup":0},
      {"name":"File8.exe","colorGroup":0},
      {"name":"File8.exe","colorGroup":0},
      {"name":"File9.exe","colorGroup":0}
    ],
    "links":[
      {"source":1,"target":0,"value":10},
      {"source":2,"target":0,"value":35},
      {"source":3,"target":0,"value":50},
      {"source":4,"target":0,"value":50},
      {"source":5,"target":0,"value":65},
      {"source":6,"target":0,"value":65},
      {"source":7,"target":0,"value":81},
      {"source":8,"target":0,"value":98},
      {"source":9,"target":0,"value":100}
    ]
}
*/

d3.json("https://dl.dropboxusercontent.com/u/5772230/ForceDirectData.json", function (error, json) {
    var nodes = json.nodes;
    force.nodes(nodes)
        .links(json.links)
        .linkDistance(function (d) {
            return d.value * 1.5;
        })
        .charge(function(d){
            var charge = -500;
            
            if (d.index === 0) charge = 0;
            
            return charge;
        })
        .friction(0.4);
    
    var link = svg.selectAll(".link")
        .data(json.links)
        .enter().append("line")
        .attr("class", "link")              
        .style("stroke-width", 1);
    
        var files = svg.selectAll(".file")
        .data(json.nodes)
        .enter().append("circle")
        .attr("class", "file")
        .attr("r", 10)
        .attr("fill", function (d) {
            return color(d.colorGroup);
        });
    var totalNodes = files[0].length;
    
    files.append("title")
        .text(function (d) { return d.name; });
    
    force.start();
    for (var i = totalNodes * totalNodes; i > 0; --i) force.tick();

    
    nodes[0].x = width / 2;
    nodes[0].y = height / 2;
    
    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; });
    
    files.attr("cx", function (d) { return d.x; })
        .attr("cy", function (d) { return d.y; })
        .attr("class", function(d){
            var classString = "file"
            
            if (d.index === 0) classString += " rootFile";
            
            return classString;
        })
        .attr("r", function(d){
            var radius = 10;
            
            if (d.index === 0) radius = radius * 2;
            
            return radius;
        });
    force.on("tick", function() {
    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; });

    files.attr("cx", function(d) { return d.x; })
        .attr("cy", function(d) { return d.y; });
  });
    
    loading.remove();
    
  }); 

JSFiddle

我已经尝试使用charge() 方法接近这一点。我以为给除根节点之外的每个节点一个更高的费用就可以做到这一点,但事实并非如此。

如何使子节点在根节点周围均匀分布?

【问题讨论】:

  • 自己计算节点的位置。力布局不适合实现这一点。
  • 这真是个好主意!然后我可以完全控制位置中的所有点。
  • 我同意拉斯的观点。还要注意,这并不意味着您会摆脱links,它仍然是一个有用的结构。在更新节点时,您不妨像强制布局一样设置它们的xy。当然这种方式与你现有的渲染代码兼容,但它也与强制布局兼容。因此,如果需要,您可以在自己的布局和强制布局之间切换模式。
  • 嘿@FillipPeyton 你碰巧有一个原始json的副本吗?似乎已从 Dropbox 中删除。
  • @ReidBlomquist 我没有。对不起:(

标签: javascript svg d3.js force-layout


【解决方案1】:

是的,力布局是适合您这种情况的完美工具。

你只需要改变一些布局的初始化,像这样

force.nodes(nodes)
    .links(json.links)
    .charge(function(d){
        var charge = -500;
        if (d.index === 0) charge = 10 * charge;
        return charge;
    });

然后瞧

解释。我不得不删除frictionlinkDistance 的设置,因为它们会严重影响放置。根节点的 charge 大 10 倍,因此所有其他节点都被主要推离根节点。其他节点也相互排斥,最终达到完美对称。

Jsfiddle 是 here


我从您的代码中看到,您试图通过利用依赖于数据的linkDistance 来影响与根节点和其他节点的距离。但是,为此目的使用linkStrength 可能会更好(尽管违反直觉),就像这样

force.nodes(nodes)
    .links(json.links)
    .linkStrength(function (d) {
        return d.value / 100.0;
    })
    .charge(function(d){
        var charge = -500;
        if (d.index === 0) charge = 10 * charge;
        return charge;
    });

但你需要尝试。


为了使根节点居中和固定,可以使用这个

nodes[0].fixed = true;
nodes[0].x = width / 2;
nodes[0].y = height / 2;

但在布局初始化之前,如thisJsfiddle。

【讨论】:

  • 这是一个非常好的解决方案。链接看起来都具有非常相似的长度,所以我正在测试here 与夸张的链接长度。它有效!
  • 我只需要弄清楚如何让这个坏男孩居中,我就可以了。
  • @FillipPeyton 我用居中信息更新了答案。
  • 宾果游戏。公认。我仍然会考虑通过 D3 将其生成为对画布的简单绘制,但这正是我正在寻找的。谢谢!
  • 有人有这个 json 的副本吗?似乎保管箱对它进行了核爆
猜你喜欢
  • 1970-01-01
  • 2021-03-30
  • 1970-01-01
  • 2014-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-01
  • 2014-06-30
相关资源
最近更新 更多