3
votes

Does D3 offer the possibility to create a tree where there exist connections between nodes on the same level, but also paths independent from the level over different levels (for example node 3 from level 2 should have a visual link to node 6 on level 4 ).

I mean somenthing like this:

       (1)
   (2)_/ \_(3)
   /_(4)     \
      /_(5)__(6)

I think this is a "normal" graph structure, but I have to visualize it top-down similar to an tree. Maybe http://bl.ocks.org/GerHobbelt/3683278 will be a good point to start, but how can I tell the force-layout to visualize the nodes more clear like a tree?

EDIT: My data looks like this:

{
 "name": "Root",
 "children": [
  {
   "name": "1",
   "children": [
    {
     "name": "2",
     "children": [
      {"name": "20"},
      {"name": "21"},
      {"name": "22"}
     ]
    },
    {
     "name": "3",
     "children": [
      {"name": "31",
         "children": [
          {"name": "300"},
          {"name": "301"},
          {"name": "302",
             "children": [
              {"name": "3020"},
              {"name": "3021"},
              {"name": "3022"}
             ]
          }
         ]
      },
      {"name": "32"},
      {"name": "33"},
      {"name": "34"}
     ]
    },
    {
     "name": "4",
     "children": [
      {"name": "41"},
      {"name": "41"}
     ]
    }
   ]
  }
 ]
}

I have copied this like this tree-example: http://bl.ocks.org/mbostock/4339083

How can I add now individual links? For example between node '2' and '3' ? I have added

var dataset = {
                edges: [
                    {source: 2, target: 3}
                ]
            };

In the copied sample, the link creation is done via

// Update the links…
              var link = vis.selectAll("path.link")
                  .data(tree.links(nodes), function(d) { return d.target.id; });

              // Enter any new links at the parent's previous position.
              link.enter().insert("svg:path", "g")
                  .attr("class", "link")
                  .attr("d", function(d) {
                    var o = {x: source.x0, y: source.y0};
                    return diagonal({source: o, target: o});
                  })
                .transition()
                  .duration(duration)
                  .attr("d", diagonal);

              // Transition links to their new position.
              link.transition()
                  .duration(duration)
                  .attr("d", diagonal);

              // Transition exiting nodes to the parent's new position.
              link.exit().transition()
                  .duration(duration)
                  .attr("d", function(d) {
                    var o = {x: source.x, y: source.y};
                    return diagonal({source: o, target: o});
                  })
                  .remove();

I do not understand, how I can add my new, additional link. Any ideas?

1

1 Answers

1
votes

You can use the normal tree layout for this -- it doesn't limit the types of connections between nodes. The basic idea would be to draw all the "normal" tree links and then add the links between levels separately. For each of those, you would need to determine start and end node positions and draw a line between them.

First, you need to resolve the coordinates for your additional edges.

dataset.edges.forEach(function(e) {
  e.source = nodes[e.source];
  e.target = nodes[e.target];
});

Then, draw the links as you did for the other ones.

vis.selectAll("path.linkExtra").data(dataset.edges)
   .enter().append("path")
   .attr("class", "linkExtra")
   .attr("d", diagonal");