4

I'm using D3.js's built-in arc function to generate SVG <path>s for my data.

.attr("d", function(element, index) {

    var arc = d3.arc()
        .innerRadius(iR)
        .outerRadius(iR + 10)
        .startAngle(element[1])
        .endAngle(element[2])
        .cornerRadius(isRounded ? cR : 0);

    return arc();

});

This works perfectly, but I'd like to round one side (both corners) of certain arcs. When a corner radius is supplied with .cornerRadius(), however, it rounds all four corners.

I know there are various ways to selectively round the corners of rectangles, but I'm hoping there's some generic way to do this for arcs.

I also saw this question about rounding only some corners of an arc, but it has no answer (and D3 v4 has come out since it was posted).

Community
  • 1
  • 1
Randoms
  • 2,110
  • 2
  • 20
  • 31

1 Answers1

3

Even with the v4 API, still no straight-forward way to do this. Looking at the source code, the cornerRadius becomes a fixed value for the calculation of the whole arc (all 4 corners). Easiest fix is to just append two arcs for every data point with the 2nd arc just filling in the corners.

Example, say we have this nicely rounded arcs:

      var myArcs = [
        [0, 45],
        [180, 300]
      ];

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

      var arc = d3.arc()
        .innerRadius(80)
        .outerRadius(150)

      var someArcs = vis.selectAll('path')
        .data(myArcs)
        .enter();

      someArcs
        .append("path")
        .attr("transform", "translate(200,200)")
        .attr("d", function(d) {
          arc.startAngle(d[0] * (Math.PI / 180))
            .endAngle(d[1] * (Math.PI / 180))
            .cornerRadius(20);
          return arc();
        })
        .attr("fill", function(d, i) {
          return d3.schemeCategory10[i];
        });
<script data-require="d3@4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v4.min.js"></script>

My fix would look like:

var myArcs = [
      [0, 45],
      [180, 300]
    ];

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

    var arc = d3.arc()
      .innerRadius(80)
      .outerRadius(150)

    var someArcs = vis.selectAll('path')
      .data(myArcs)
      .enter();

    someArcs
      .append("path")
      .attr("transform", "translate(200,200)")
      .attr("d", function(d) {
        arc.startAngle(d[0] * (Math.PI / 180))
          .endAngle(d[1] * (Math.PI / 180))
          .cornerRadius(20);
        return arc();
      })
      .attr("fill", function(d, i) {
        return d3.schemeCategory10[i];
      });

    someArcs
      .append("path")
      .attr("transform", "translate(200,200)")
      .attr("d", function(d) {
        arc.startAngle(d[0] * (Math.PI / 180))
          .endAngle((d[0] + 10) * (Math.PI / 180))
          .cornerRadius(0);
        return arc();
      })
      .attr("fill", function(d, i) {
        return d3.schemeCategory10[i];
      });
  <script data-require="d3@4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v4.min.js"></script>
Mark
  • 106,305
  • 20
  • 172
  • 230