svg / d3.js rounded corner on one corner of a rectangle

后端 未结 5 1232
青春惊慌失措
青春惊慌失措 2020-12-01 04:41

I know svg has an in built function to do rounded corners, but I need to do rounded corners on only 2 of the four corners.

I know I can draw multiple rectangles on t

相关标签:
5条回答
  • 2020-12-01 04:42

    Just to expand on the answers given, here is a more comprehensive function to return the path for your rect.

    x: x-coordinate
    y: y-coordinate
    w: width
    h: height
    r: corner radius
    tl: top_left rounded?
    tr: top_right rounded?
    bl: bottom_left rounded?
    br: bottom_right rounded?
    
    function rounded_rect(x, y, w, h, r, tl, tr, bl, br) {
        var retval;
        retval  = "M" + (x + r) + "," + y;
        retval += "h" + (w - 2*r);
        if (tr) { retval += "a" + r + "," + r + " 0 0 1 " + r + "," + r; }
        else { retval += "h" + r; retval += "v" + r; }
        retval += "v" + (h - 2*r);
        if (br) { retval += "a" + r + "," + r + " 0 0 1 " + -r + "," + r; }
        else { retval += "v" + r; retval += "h" + -r; }
        retval += "h" + (2*r - w);
        if (bl) { retval += "a" + r + "," + r + " 0 0 1 " + -r + "," + -r; }
        else { retval += "h" + -r; retval += "v" + -r; }
        retval += "v" + (2*r - h);
        if (tl) { retval += "a" + r + "," + r + " 0 0 1 " + r + "," + -r; }
        else { retval += "v" + -r; retval += "h" + r; }
        retval += "z";
        return retval;
    }
    
    0 讨论(0)
  • 2020-12-01 04:43

    I found myself with this problem recently in order to do a bar chart with top rounded corners in d3. I made a codesandbox demo of the solution I found.

    0 讨论(0)
  • 2020-12-01 04:56

    Expanding on @robert-longson's answer, you can use SVG's elliptical arc commands to make the corners, in conjunction with lineto commands for the straight edges. These are used with path elements. Here's one possible implementation:

    // Returns path data for a rectangle with rounded right corners.
    // The top-left corner is ⟨x,y⟩.
    function rightRoundedRect(x, y, width, height, radius) {
      return "M" + x + "," + y
           + "h" + (width - radius)
           + "a" + radius + "," + radius + " 0 0 1 " + radius + "," + radius
           + "v" + (height - 2 * radius)
           + "a" + radius + "," + radius + " 0 0 1 " + -radius + "," + radius
           + "h" + (radius - width)
           + "z";
    }
    

    You can then call this function to compute the "d" attribute. For example:

    rects.enter().append("path")
        .attr("d", function(d) {
          return rightRoundedRect(x(0), y(d.name), x(d.value) - x(0), y.rangeBand(), 10);
        });
    

    Live example:

    • http://bl.ocks.org/3468167

    Optional: If you like, you could refactor the rightRoundedRect function to make it configurable, rather than taking lots of arguments. This approach would be similar to D3's built-in shape generators. For example, you might use a rect generator like so:

    rects.enter().append("path")
        .attr("d", rightRoundedRect()
          .x(x(0))
          .y(function(d) { return y(d.name); })
          .width(function(d) { return x(d.value) - x(0); })
          .height(y.rangeBand())
          .radius(10));
    

    For more details on that approach, see the configurable function tutorial.

    0 讨论(0)
  • 2020-12-01 05:03

    Anyone who looks for an Eslinted version of stackmate -s answer:

    function roundedRect(x, y, w, h, r, tl, tr, bl, br) {
      let retval;
      retval = `M${x + r},${y}`;
      retval += `h${w - (2 * r)}`;
      if (tr) {
        retval += `a${r},${r} 0 0 1 ${r},${r}`;
      } else {
        retval += `h${r}`; retval += `v${r}`;
      }
      retval += `v${h - (2 * r)}`;
      if (br) {
        retval += `a${r},${r} 0 0 1 ${-r},${r}`;
      } else {
        retval += `v${r}`; retval += `h${-r}`;
      }
      retval += `h${(2 * r) - w}`;
      if (bl) {
        retval += `a${r},${r} 0 0 1 ${-r},${-r}`;
      } else {
        retval += `h${-r}`; retval += `v${-r}`;
      }
      retval += `v${((2 * r) - h)}`;
      if (tl) {
        retval += `a${r},${r} 0 0 1 ${r},${-r}`;
      } else {
        retval += `v${-r}`; retval += `h${r}`;
      }
      retval += 'z';
      return retval;
    }
    
    0 讨论(0)
  • 2020-12-01 05:05

    In case others end up here wanting to round all corners of a rect element, you can add an rx attribute to the rect element (as @mbostock mentions in his fiddle above):

    var rectangle = group.append("rect")
        .attr("width", 60)
        .attr("height", 75)
        .attr("rx", 4)
        .style("fill", function(d) { return "#e6653e"; })
        .style("stroke", function(d) { return d3.rgb("#e6653e").darker(); })
    
    0 讨论(0)
提交回复
热议问题