简体   繁体   中英

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

I'm trying to modify Mike's Force-Directed Graph example to use rectangles instead of circles as nodes. Also, I want text inside the rectangle.

I have rectangles showing up with text correctly, however they're not attached to the links, and they do not move.

Here's a codepen 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;
        });
});

Update

Thanks to Lars 's comment, and his codepen it works now.

Updates I made to my code:

  1. Add transform illustrated by Lars
  2. Changed links to connect at the center of rectangles
  3. Added rounded corners to rectangles
  4. Gave the text a slight margin indentation
  5. Changed to use window width/height

Here my new codepen: 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 + ")";
        });
});

You're setting the x and y attributes on the g elements to change their positions -- this won't do anything. You need to set the transform attribute instead, like you're doing when adding the g elements. So your tick handler function would contain

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

instead of

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

Complete demo here .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM