chemook78 chemook78 - 4 years ago 121
CSS Question

How to position nodes Force Directed Graph D3 with CSS?

I am making a Force Directed Graph with D3 and got it working with svg circles for the nodes. But when I use divs in combination with CSS left and top properties, the nodes are out of position. I can't figure out what I am doing wrong here. I use the x and y coordinates that force D3 generates as the left and top properties, but maybe that's not the way to go?

Here is my JS:

var url = "";

d3.json(url, function(json){

var data = json;

var margin = {top: 40, right: 40, bottom: 40, left: 40};

var w = 1000 - margin.left - margin.right;
var h = 1000 - - margin.bottom;

var svg ="#chart")
.attr("width", w + margin.left + margin.right)
.attr("height", h + + margin.bottom)
.attr("transform", "translate(" + margin.left + "," + + ")");

var nodes = data.nodes;
var links = data.links;

//Create a force layout object and define its properties
var force = d3.layout.force()



var link = svg.selectAll(".link")
.attr("class", "link");

var node ="#chart").selectAll(".node")

force.on("end", function(){
//set node and link position attributes once force calculations have finished

//position the nodes"left", function(d){

return d.x + "px";

.style("top", function(d){

return d.y + "px";

.attr("class", function(d){

return "flag flag-" + d.code + " node";

.attr("src", "");

link.attr("x1", function(d){

return d.source.x;

.attr("y1", function(d){

return d.source.y;

.attr("x2", function(d){


.attr("y2", function(d){




//let the force start its calculations


My css:

svg {

background-color: white;
box-shadow: 0 0 10px #888888;


.link {

stroke: #2c3e50;
stroke-width: 2px;


.flag {
display: inline-block;
width: 16px;
height: 11px;
background: url('') no-repeat;

.flag.flag-ml {
background-position: -224px -88px;

Graph so far on codepen:

Answer Source

Account for how much the links in the SVG are offset from the window: they're shifted over by margin.left, down by, and also down by the heights of the <h1> and <h2> (plus padding).

For example, in my browser, the flags look positioned correctly with the following code:"left", function(d){

        return d.x + margin.left + 150 + "px";

    .style("top", function(d){

        return d.y + + "px";


Notice that this is because the <div> flag elements have a default left and top attribute of 0, even though their parent is <div#chart>. I've hard-coded 150 but you could also devise a way to calculate it dynamically.

The reason you got it working with <circle> but not <div> is that circles are SVG elements and children of <svg>, so they are already in the correct starting positions. There might be an alternative solution in which you keep the flags within SVGs: adding nodes as <g> or <rect> instead of <div>, attributes of x and y instead of left and top, children of <svg> instead of <div#chart>. However, I haven't explored how to implement assigning the flags to each node because you're not pointing at a distinct URL for each flag file.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download