3
<!DOCTYPE html>
<html>
<head>
    <meta charset='utf-8'>
    <title>Force Layout Example 1</title>
    <style>

.node {
    fill: #ccc;
    stroke: #fff;
    stroke-width: 2px;
}

.link {
    stroke: #777;
    stroke-width: 2px;
}
.line {
    stroke: #777;
    stroke-width: 2px;
}

    </style>
</head>
<body>
    <script src='http://d3js.org/d3.v3.min.js'></script>
    <script>

var width = 640,
    height = 480;

var nodes = [
    { "x": 200, "y": 200 },
    { "x": 500,  "y":  300 },
  { "x": 500,  "y":  100 },
  //{ "x": 650,  "y":  100 },
];

//var nodes = [
  //  { "x": 200, "y": 200 },
    //            { "x": 500,  "y":  300 },
  //{ "x": 500,  "y":  100 },
//];
//var links = [
  //  { source: 0, target: 1 },
 // { source: 1, target: 2 },
//];

var links = [
    { source: 0, target: 1 },
  { source: 0, target: 2 },
  //{ source: 1, target: 3 },
];

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


var force = d3.layout.force()
    .size([width, height])
    .nodes(nodes)
    .links(links);

force.linkDistance(75);

var link = svg.selectAll('.link')
    .data(links)
    .enter().append('line')
    .attr('class', 'link');

var node = svg.selectAll('.node')
          .data(nodes)
          .enter().append('rect')
          .attr('class', 'node');

var subnode = svg.selectAll('.subnode')
                 .data(nodes)
                 .enter().append('circle')
                 .attr('class', 'subnode');

var subnode2 = svg.selectAll('.subnode2')
              .data(nodes)
              .enter().append('circle')
              .attr('class', 'subnode2');


force.on('end', function() {
   node.attr("x", function(d) { return d.x; })
       .attr("y", function(d) { return d.y; })
       .attr("width", 50)
       .attr("height", 20);
   subnode.attr('r', width/250)
          .attr('cx', function(d) { return (d.x); })
          .attr('cy', function(d) { return d.y + 10; });

  subnode2.attr('r', width/250)
          .attr('cx', function(d) { return d.x+50; })
          .attr('cy', function(d) { return d.y + 10; });

  link.attr('x1', function(d) { return d.source.x; })
      .attr('y1', function(d) { return d.source.y+ 10; })
      .attr('x2', function(d) { return d.target.x+50; })
      .attr('y2', function(d) { return d.target.y+ 10; });

});

force.start();
var line;
function mousedown() {
    var m = d3.mouse(this);
  //alert(m[0]+"---"+m[1]);
    line = svg.append("line")
        .attr('x1', m[0])
        .attr('y1', m[1])
        .attr('x2', m[0])
        .attr('y2', m[1]);

    svg.on("mousemove", mousemove);
}

function mousemove() {

    var m = d3.mouse(this);
    line.attr('x2', m[0])
        .attr('y2', m[1]);
}

function mouseup() {
    svg.on("mousemove", null);
}
    </script>
</body>
</html>

The above solution gives below result:

enter image description here

The problem is I dont understand why the graph is drawn reverse and moreover in above code I have commented out some nodes and links if you uncomment them then there is more chaos the whole nodes are drawn in complete random order i.e. increasing more nodes and links create more chaos.

See the JSBIN : http://jsbin.com/yuyolof/edit?html

Srinivas Gadilli
  • 342
  • 6
  • 25
  • Take a look at this http://jsbin.com/bihosuvobi/edit?html,output I have changed the nodes a bit in order to understand the issue, the nodes are drawn where their respective x and y are defined and follow the tick function that adjusts x and y accordingly. To me it seems that everything is connected as they should (according to your link data) If you need a static graph maybe force is not the most suitable for your case or you should play a bit with node charge link distance and alpha. – mkaran Dec 27 '16 at 13:00
  • I have put some labels on each node and link in order to try clarify how the nodes are connected and created http://jsbin.com/kohiqohahu/1/edit?html,output Hope this helps! – mkaran Dec 27 '16 at 13:21
  • (Changing the link distance: http://jsbin.com/pexifosoqa/1/edit?: html,console,output ) – mkaran Dec 27 '16 at 13:54
  • @mkaran In the chart the links are drawn in between wrong subnodes or so it is visible. I want the right subnode(circle) of the left node(rectangle) to connect to the left subnode(circle) of the left node(rect). See the image https://i.imgsafe.org/34a92f3c64.png where wrong subnodes are connected. – Srinivas Gadilli Dec 28 '16 at 05:19
  • Oh, now I see what you meant. Thanks! – mkaran Dec 28 '16 at 07:38

1 Answers1

1

Take a look at this jsbin http://jsbin.com/himutohimu/1/edit?html,css,output (I've added a bit too much info in this just to have a better look at what's going on)

You have two subnodes that have the same node data. You are positioning them on "end" like this:

   subnode.attr('r', width/250) // black nodes
          .attr('cx', function(d) { return d.x; })
          .attr('cy', function(d) { return d.y + 10; });

   subnode2.attr('r', width/250) // red nodes
          .attr('cx', function(d) { return d.x + 50; })
          .attr('cy', function(d) { return d.y + 10; });

I've colored the nodes differently in order to better see how this works.

In order for your lines to connect to one kind of subnodes you need to either follow the x and y of the black nodes or the x and y of the red nodes:

  // x1 and y1 are the starting point of the line, so in order to follow the 
  // red nodes, we need to move accordingly with +50 for x and +10 for y.
  // the same goes for x2, y2 which are the coordinates for the end of the line
  link.attr('x1', function(d) { return d.source.x + 50; })
      .attr('y1', function(d) { return d.source.y + 10; })
      .attr('x2', function(d) { return d.target.x + 50; })
      .attr('y2', function(d) { return d.target.y + 10; });

 //Or if you need your lines to follow the black nodes/ dots then x1, y1 
 // and x2,y2 need to move accordingly to your subnode's x and y, 
 // so x as it is and y plus 10
 // it is one or the other
 link.attr('x1', function(d) { return d.source.x; })
     .attr('y1', function(d) { return d.source.y + 10; })
     .attr('x2', function(d) { return d.target.x; })
     .attr('y2', function(d) { return d.target.y + 10; });

So, it is a matter of what nodes (dots) you want to connect and then move the line according to their respective x and y.

Hope this helps!

Good luck!

Edit: How this works with more nodes: http://jsbin.com/nodaruwere/1/edit?html,output

mkaran
  • 2,528
  • 20
  • 23
  • I was expecting the mirror image of the image posted in my question. More like red dot of the rectangle in left connected to the black dots of the ones in the right. – Srinivas Gadilli Dec 28 '16 at 08:53
  • My aim is to create something like this : http://imgur.com/Wqgo96C . Is my approach correct – Srinivas Gadilli Dec 28 '16 at 09:04
  • 1
    Like jsplumb? I think d3 might not be the most suitable tool for this. Or at least the force layout. Take a look at this: http://stackoverflow.com/a/35441959/3433323 and maybe this https://bl.ocks.org/cjrd/6863459. You can also try and position the lines' x and y according to which dot is closer to the dot you want to connect, e.g. something like this http://jsbin.com/lomijusaxo/1/edit?html,output – mkaran Dec 28 '16 at 09:32