4
votes

I'm working on a proof of concept for an application that I think D3 might be a good fit for. Since I'm new to D3 I thought I would start off simple and build my way up to the application requirements. However, I seem to be hitting a snag on what I believe should be a very easy task with this library. I want to place two small circles on an SVG and then draw an arc or curve between them. Based on the documentation, I believe arcTo would be the best fit for this since I know the start and end points. For the life of me I cannot get it to draw the arc. The circles are drawn perfectly every time though.

var joints = [{x : 100, y : 200, r : 5},
    {x : 150, y : 150, r : 5}];
              
var svg = d3.select("svg");

svg.selectAll("circle")
  .data(joints)
  .enter().append("circle")
  .attr("cx", function(d) { return d.x; })
  .attr("cy", function(d) { return d.y; })
  .attr("r", function(d) { return d.r; });

svg.selectAll("path").append("path").arcTo(100,200,150,150,50)
  .attr("class", "link");
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="960" height="800" />

I'm either going about this the wrong way or I don't fully understand how to append a path to an SVG. Can someone point me in the right direction? I haven't been able to find many examples of arcTo. Thank you!

1

1 Answers

6
votes

You misunderstood what d3.path() is. According to the API:

The d3-path module lets you take [a HTML Canvas] code and additionally render to SVG.

And for d3.path():

d3.path(): Constructs a new path serializer that implements CanvasPathMethods.

As you can see, the d3-path module has only a bunch of methods that allow you to take a HTML canvas code and use it to draw SVG elements.

That being said, you cannot use arcTo straight away in the SVG, as you are doing right now. It should be:

var path = d3.path();
    path.moveTo(100, 200);
    path.arcTo(100,200,150,150,50)

... and then:

svg.append("path")
    .attr("d", path.toString())

However, as an additional problem, arcTo is more complicated than that: the first two values are not the x and y of the starting point, but the coordinates of the first tangent.

Here is a demo, using different values for arcTo, which I think is what you want:

var joints = [{
  x: 100,
  y: 200,
  r: 5
}, {
  x: 150,
  y: 150,
  r: 5
}];

var svg = d3.select("svg");

svg.selectAll("circle")
  .data(joints)
  .enter().append("circle")
  .attr("cx", function(d) {
    return d.x;
  })
  .attr("cy", function(d) {
    return d.y;
  })
  .attr("r", function(d) {
    return d.r;
  });

var path = d3.path();
path.moveTo(100, 200);
path.arcTo(100, 150, 150, 150, 50);

svg.append("path")
  .attr("d", path.toString())
  .attr("stroke", "firebrick")
  .attr("stroke-width", 2)
  .attr("fill", "none");
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="400" height="250" />

An easy alternative is simply dropping the d3.path() and doing all this using just SVG code. There are plenty of examples showing how to draw an SVG arc from point A to point B with a given radius.