D3.js 使用力导向布局和节点矩形的网络图

D3.js network graph using force-directed layout and rectangles for nodes

我正在尝试修改 Mike 的 Force-Directed Graph 示例以使用矩形而不是圆形作为节点。另外,我想要矩形内的文本。

我有正确显示文本的矩形,但是它们没有附加到 link 上,并且它们不会移动。

这是一个代码笔link:http://codepen.io/anon/pen/gpgWaz

var width = 960,
    height = 500;

var color = d3.scale.category20();

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

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

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

var link = svg.selectAll(".link")
    .data(graph.links)
    .enter().append("line")
    .attr("class", "link")
    .style("stroke-width", function(d) {
        return Math.sqrt(d.value);
    });

var node = svg.selectAll(".node")
    .data(graph.nodes)
    .enter()
    .append("g")
    .attr("transform", function(d) {
        return "translate(" + d.x + "," + d.y + ")";
    })
    .call(force.drag);

node.append("rect")
    .attr("class", "node")
    .attr("width", 100)
    .attr("height", 35)
    .style("fill", function(d) {
        return color(d.group);
    })
    .style("stroke", "black")
    .style("stroke-width", "1px");

node.append("text")
    .text(function(d) {
        return d.name;
    })
    .style("font-size", "12px")
    .attr("dy", "1em");

node.append("title")
    .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("x", function(d) {
            return d.x;
        })
        .attr("y", function(d) {
            return d.y;
        });
});

更新

多亏了 Lars's comment, and his codepen 现在可以使用了。

我对代码所做的更新:

  1. 添加 Lars 说明的变换
  2. 更改 links 以在矩形的中心连接
  3. 为矩形添加了圆角
  4. 给文本留一点边距缩进
  5. 更改为使用 window width/height

这是我的新代码笔:http://codepen.io/anon/pen/bdgREd

var width = window.innerWidth,
    height = window.innerHeight,
    nodeWidth = 100,
    nodeHeight = 35;

var color = d3.scale.category20();

var force = d3.layout.force()
    .charge(-1500)
    .linkDistance(100)
    .friction(0.5)
    .size([width, height]);

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

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

var link = svg.selectAll(".link")
    .data(graph.links)
    .enter().append("line")
    .attr("class", "link")
    .style("stroke-width", function(d) {
        return Math.sqrt(d.value);
    });

var node = svg.selectAll(".node")
    .data(graph.nodes)
    .enter()
    .append("g")
    .attr("transform", function(d) {
        return "translate(" + d.x + "," + d.y + ")";
    })
    .call(force.drag);

node.append("rect")
    .attr("class", "node")
    .attr("width", nodeWidth)
    .attr("height", nodeHeight)
    .attr("rx", 5)
    .attr("ry", 5)
    .style("fill", function(d) {
        return color(d.group);
    })
    .style("stroke", "black")
    .style("stroke-width", "1px");

node.append("text")
    .attr("x", 5)
    .attr("y", 2)
    .text(function(d) {
        return d.name;
    })
    .style("font-size", "12px")
    .attr("dy", "1em");

node.append("title")
    .text(function(d) {
        return d.name;
    });

force.on("tick", function() {
    link.attr("x1", function(d) {
            return d.source.x + (nodeWidth / 2);
        })
        .attr("y1", function(d) {
            return d.source.y + (nodeHeight / 2);
        })
        .attr("x2", function(d) {
            return d.target.x + (nodeWidth / 2);
        })
        .attr("y2", function(d) {
            return d.target.y + (nodeHeight / 2);
        });

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

您在 g 元素上设置 xy 属性以更改它们的位置——这不会执行任何操作。您需要改为设置 transform 属性,就像您在添加 g 元素时所做的那样。所以你的 tick 处理函数将包含

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

而不是

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

完成演示 here