1

New to D3 and the documentation isn't so strong so I'm just going of examples, but it is taking too much time. I found a great jsfiddle (found in this post) using d3 to transition between different embeddings for a network graph. I want to give the graphs straight lines instead of curved lines, and have done so for the tree embedding, but I have no idea how to apply it to the radial cluster option.

This is the code I added to replace 'diagonal()' in the tree representation to give straight lines instead of curved, not sure how to modify it for radialCluster

var line = d3.svg.line()
             .x( d => d.lx )
             .y( d => d.ly );

function lineData(d){
    var points = [
        {lx: d.source.y, ly: d.source.x},
        {lx: d.target.y, ly: d.target.x}
    ];
    return line(points);
}

Any help would be greatly appreciated :)

ps. Why isn't there a way to just transform the location of the nodes (e.g. to form radial cluster) and then use that data simply draw the relations?

Will Cowan
  • 81
  • 8

1 Answers1

1

Sadly, there is no API for it, but from looking at the source code, I was able to write a very short custom link function that just draws a straight line between the nodes.

var width = 500,
  height = 500;
var diameter = 300;
var duration = 2000;

var root; // store data in a variable accessible by all functions

var radialCluster = d3.layout.cluster()
  .size([360, diameter / 2])
  .separation(function(a, b) {
    return (a.parent == b.parent ? 1 : 2) / a.depth;
  });

var radialDiagonal = function(d, i) {
  var projection = function(d) {
    // Because of the transformation, 0 is the centre, and d.y denotes the distance
    // from that centre
    var radius = d.y,
      // Subtract 90 because otherwise 0 degrees is left, instead of at the top
      angle = (d.x - 90) / 180 * Math.PI;
    return [radius * Math.cos(angle), radius * Math.sin(angle)];
  };
  var points = [d.source, d.target].map(projection);

  return "M" + points[0] + "L" + points[1];
}

var line = d3.svg.line()
  .x(d => d.lx)
  .y(d => d.ly);

function lineData(d) {
  var points = [{
      lx: d.source.y,
      ly: d.source.x
    },
    {
      lx: d.target.y,
      ly: d.target.x
    }
  ];
  return line(points);
}


var svg = d3.select("body").append("svg")
  .attr("width", width)
  .attr("height", height)
  .append("g")
  .attr("transform", "translate(" + (width / 2) + "," +
    (height / 2) + ")")
// set appropriate translation (origin in middle of svg)

var root = getData(5),
  nodes = radialCluster.nodes(root),
  links = radialCluster.links(nodes);

var link = svg.selectAll(".link")
  .data(links)
  .enter()
  .append("path")
  .attr("class", "link")
  .style("stroke", "#8da0cb")
  .attr("d", radialDiagonal);

var node = svg.selectAll(".node")
  .data(nodes)
  .enter()
  .append("g")
  .attr("class", "node")
  .attr("transform", function(d) {
    return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")";
  });

node.append("circle")
  .attr("r", 4.5)
  .style("stroke", "#e41a1c");

function getData(x) {
  return ternary_tree_gen(x);
};

function ternary_tree_gen(layers) {
  // Recursive call to generate children
  let node_children = [];
  if (layers > 0) {
    for (var i = 1; i <= 3; i++) {
      node_children.push(ternary_tree_gen(layers - 1));
    }
  }

  // Add children into node
  let node = {
    // name: layer + "_" + (index_start + i),
    name: "",
    children: node_children
  }

  // Return the node and all its children
  return node;
}
label {
  font: 12px sans-serif;
}

.node circle {
  fill: #fff;
  stroke: steelblue;
  stroke-width: 1.5px;
}

.node {
  font: 10px sans-serif;
}

.link {
  fill: none;
  stroke: tan;
  stroke-width: 1.5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.js"></script>
Ruben Helsloot
  • 12,582
  • 6
  • 26
  • 49