d3强制图表节点位置

时间:2016-11-30 18:13:15

标签: javascript d3.js force-layout

我目前正在处理d3力图,我想在父节点周围等间隔地绘制我的子节点,所以例如如果我有一个父节点和4个链接的子节点,我希望每个节点节点以90度间隔定位?这可能吗?

这是我当前的强制码,

app.force
    .nodes(nodes)
    .links(app.edges)
    .on("tick", tick)
    .start();

function tick(e) {
   // console.log(link);
    var k = 6 * e.alpha;

    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; });


    linkText
            .attr("x", function(d) {
                return ((d.source.x + d.target.x)/2);
            })
            .attr("y", function(d) {
                return ((d.source.y + d.target.y)/2);
            });

    node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });

    node
      .attr("cx", function(d) { return d.x })
      .attr("cy", function(d) { return d.y })
  }

app.force = d3.layout.force()
    .charge(-300)
    .linkDistance(85)
    .size([width, height]);

  //Where we will draw our visualisation
  app.svg = d3.select(".visualisation").append("svg")
    .attr('width', width)
    .attr('height', height);

1 个答案:

答案 0 :(得分:0)

d3.layout.force()未考虑此类自定义而创建。当然你可以设置一些参数,但大多数位置是自动计算的,更改它们可能非常困难(除非你创建自己的力函数)。版本4.x在这方面更好,但并不多。

在您的具体情况下,您可以设置一个非常高的(从数学上讲,“非常低”,因为它是负数)费用:

var force = d3.layout.force()
    .charge(-3000)

但即使这样做,角度也不是完全正确的角度,它们会有所不同:如果你点击“运行片段”,你就可以得到一个近乎完美的十字架,但是如果你再次点击它,下一次它就不那么完美了。如果您有多个深度级别的数据,它将无法按预期工作。

这是一个演示:

<script src="https://d3js.org/d3.v2.min.js?2.9.3"></script>
<style>
    .link {
        stroke: #aaa;
    }
    .node text {
        stroke: #333;
        cursor: pointer;
    }
    .node circle {
        stroke: #fff;
        stroke-width: 3px;
        fill: #555;
    }
</style>

<body>
    <script>
        var width = 400,
            height = 300

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

        var force = d3.layout.force()
            .distance(50)
            .charge(-3000)
            .size([width, height]);

        var json = {
            "nodes": [{
                "name": "node1"
            }, {
                "name": "node2"
            }, {
                "name": "node3"
            }, {
                "name": "node4"
            }, {
                "name": "node5"
            }],
            "links": [{
                "source": 0,
                "target": 1
            }, {
                "source": 0,
                "target": 2
            }, {
                "source": 0,
                "target": 3
            }, {
                "source": 0,
                "target": 4
            }]
        };

        force
            .nodes(json.nodes)
            .links(json.links)
            .start();

        var link = svg.selectAll(".link")
            .data(json.links)
            .enter().append("line")
            .attr("class", "link")
            .style("stroke-width", 2);

        var node = svg.selectAll(".node")
            .data(json.nodes)
            .enter().append("g")
            .attr("class", "node")
            .call(force.drag);

        node.append("circle")
            .attr("r", 8);

        node.append("text")
            .attr("dx", 12)
            .attr("dy", ".35em")
            .text(function(d) {
                return d.name
            });

        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;
                });

            node.attr("transform", function(d) {
                return "translate(" + d.x + "," + d.y + ")";
            });
        });
    </script>