使用组节点强制布局冲突检测

时间:2015-04-24 10:14:46

标签: d3.js

如何对力布局d3使用碰撞检测功能。当我搜索我得到这个代码,但如果考虑布局不包含任何圆。它只包含一些图像和文本组。 那我怎么能重写这个功能呢。

function collide(node) {
var r = node.radius + 16,
    nx1 = node.x - r,
    nx2 = node.x + r,
    ny1 = node.y - r,
    ny2 = node.y + r;
return function(quad, x1, y1, x2, y2) {
    if (quad.point && (quad.point !== node)) {
        var x = node.x - quad.point.x,
            y = node.y - quad.point.y,
            l = Math.sqrt(x * x + y * y),
            r = node.radius + quad.point.radius;
        if (l < r) {
            l = (l - r) / l * .5;
            node.x -= x *= l;
            node.y -= y *= l;
            quad.point.x += x;
            quad.point.y += y;
        }
    }
    return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
};}

1 个答案:

答案 0 :(得分:1)

由于每个节点的高度和宽度相同,唯一需要的更改是在group函数中使用node.radius而不是collide的大小。确保将唯一数据绑定到每个节点。

var width = 960,
    height = 500;

var nodes = d3.range(200).map(function() {
        return {
            radius: Math.random() * 12 + 4
        };
    }),
    root = nodes[0],
    color = d3.scale.category10();

root.radius = 0;
root.fixed = true;

var force = d3.layout.force()
    .gravity(0.05)
    .charge(function(d, i) {
        return i ? 0 : -2000;
    })
    .nodes(nodes)
    .size([width, height]);

force.start();

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

var node = svg.selectAll(".node")
    .data(nodes.slice(1))
    .enter()
    .append("g")
    .attr("class", "node")
    .attr("id",function(d,i){ return d.id = "node"+i; });

node.append("svg:image")  
    .attr("xlink:href", "http://www.clker.com/cliparts/g/l/R/7/h/u/teamstijl-person-icon-blue.svg")
    .attr("width", "30px")
    .attr("height", "30px");   

force.on("tick", function(e) {
    var q = d3.geom.quadtree(nodes),
        i = 0,
        n = nodes.length;

    while (++i < n) q.visit(collide(nodes[i]));

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

svg.on("mousemove", function() {
    var p1 = d3.mouse(this);
    root.px = p1[0];
    root.py = p1[1];
    force.resume();
});

function collide(node) {
    var nodeEl = svg.selectAll("g.node")
        .filter(function(d, i) {
            return node.id == d.id
        }).node();   
    var nodeSize = nodeEl.getBBox().height+16;//You can remove/reduce this static value 16 to decrease the gap between nodes.
    var r = nodeSize / 2 + 16,
        nx1 = node.x - r,
        nx2 = node.x + r,
        ny1 = node.y - r,
        ny2 = node.y + r;
    return function(quad, x1, y1, x2, y2) {
        if (quad.point && (quad.point !== node)) {
            var x = node.x - quad.point.x,
                y = node.y - quad.point.y,
                l = Math.sqrt(x * x + y * y),
                r = nodeSize / 2 + quad.point.radius;
            if (l < r) {
                l = (l - r) / l * .5;
                node.x -= x *= l;
                node.y -= y *= l;
                quad.point.x += x;
                quad.point.y += y;
            }
        }
        return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
    };
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>