42

I am trying to implement a bar chart like diagram. I have the following html element

<rect x="35" y="-135" width="10" height="51" style="stroke: rgb(255, 255, 255); opacity: 0.8; fill: rgb(255, 122, 0);"></rect>

I want to give the top corner of the rectangle a rounded shape. How is it possible?
I am not able to apply border-radius property.

web-tiki
  • 99,765
  • 32
  • 217
  • 249
Dhanya
  • 549
  • 1
  • 6
  • 14

6 Answers6

27

You may use clipPath too. It's kind of a hack but it may be easier to implement.

Assuming the follow:

  • your rect is width="10" and height="51"
  • the top corner will be rx="5" and ry="5"

<svg>
    <defs>
        <clipPath id="round-corner">
            <rect x="0" y="0" width="10" height="56" rx="5" ry="5"/>
         </clipPath>
     </defs>

     <!-- if you want to use x="35" y="-135" put clip-path on a `g` element --> 
     <rect width="10" 
           height="51" 
           clip-path="url(#round-corner)"
           style="stroke: rgb(255, 255, 255); opacity: 0.8; fill: rgb(255, 122, 0);"></rect>
</svg>

Some Notes:
So the clipPath > rect > width is exactly the same as your rect.

Instead for clipPath > rect > height, you have to consider the corner radius on top and thus the height should be rect.height + desired-corner-radius (in this case 51px + 5px).

In that way you won't touch the bottom part of your rect with the clipPath.

borracciaBlu
  • 4,017
  • 3
  • 33
  • 41
  • 1
    Small hint: I used this code for multiple rectangles `` with different lenghts. The rounding didn't work always properly. Ofc it turned out that `id="round-corner"` is a global identifier. So I had to adapt it to something like `id={"round-corner" + uniqueIdentifier}` to make the solution work for multiple rectangles. Maybe this helps somebody. – Semjon Mössinger May 17 '23 at 14:53
20

Wrote an article explaining this https://medium.com/@dphilip/one-side-rounded-rectangle-using-svg-fb31cf318d90

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
  <path
    d="M10,40
       h50
       q5,0 5,5
       v10
       q0,5 -5,5
       h-50
       z
    "
    fill="#4EDFA5"
  >
<svg>
14

As commented by Robert Longson you need to convert your rect element to a path element to control the rounded corners.

In the following example, I used a cubic bezier curve with the Q command to make the top left rounded corner (Q1 1 5 1 in the d attribute):

svg{
  height:90vh;
  width:auto;
  }
<svg viewbox="0 0 10 50">
  <path d="M1 49 V5 Q1 1 5 1 H9 V49z"
        fill="rgba(255, 122, 0, 0.8)" />
</svg>
Community
  • 1
  • 1
web-tiki
  • 99,765
  • 32
  • 217
  • 249
  • 3
    It is incorrect to use a bezier curve. A bezier curve can only ever approximate a circle. You need to use the `arc` command: http://devdocs.io/svg/attribute/d#arcto – adius Jan 10 '18 at 13:37
  • 1
    @adius bezier curve can definetly make circles. Both commands are apropriate for this situation. – web-tiki Jan 09 '19 at 09:53
  • 3
    @adius I get your point from a mathematical point of view but I don't think you can see a diffrence in the output of a circle made with bezier curves and using the arc command. On a side note the, the OP isn't trying to make a circle, but rather connecting two lines with a curve, therefore a bezier curve command is apriopriate in this situation. – web-tiki Jan 09 '19 at 14:49
  • 2
    Ok, you're right, the OP only asked for rounded corners, so it's not incorrect per se to use a bezier curve, as it yields to "rounded" corners. But you should be more precise with your language, cause "bezier curves can make circles" is just plain wrong. – adius Jan 10 '19 at 15:31
  • 2
    From a practical standpoint for website display (raster rendering), bezier curves can draw pixel perfect circles due to the fact that it is rasterized at a finite resolution. The theoretical mathematics does not matter for this conversation, as it has no application to the real life scenario in this case. Choose your dogmatic battles where it actually matters. – user2867288 Mar 01 '22 at 22:15
10

Use the <path> element with the arc command (http://devdocs.io/svg/attribute/d#arcto).

Syntax: a rx,ry x-axis-rotation large-arc-flag sweep-flag dx,dy

<svg width="200" height="200" viewBox="0 0 10 10">
  <path d="M0,8 v-3 a5,5 0 0 1 5,-5 h3 v8 z" />
</svg>
adius
  • 13,685
  • 7
  • 45
  • 46
2

The clip-path approach can be simplified by using the inset basic shape function i.e. inset(top, right, bottom, left) which takes px or percent and insets from the shapes border.

The example below has set the offset of left to be equal to border radius hence the left has a straight edge.

The support for css-clip-path is pretty good. It doesn't work in opera mini and IE.

rect {
  clip-path: inset(0px 0px 0px 25px);
}
<svg>
  <rect width=200 height=100 rx=25 />
</svg>
owennewo
  • 301
  • 2
  • 3
0

This worked for me :)

function createRectanglePath(props) {
  const {
    width,
    height,
    topLeftRadius,
    topRightRadius,
    bottomRightRadius,
    bottomLeftRadius,
  } = props;

  return [
    // Move to the start point, considering top left radius
    `M ${topLeftRadius} 0`,
    // Draw a horizontal line to the top right corner, considering top right radius
    `H ${width - topRightRadius}`,
    // Draw an arc for top right corner if radius is greater than 0
    topRightRadius > 0
      ? `A ${topRightRadius} ${topRightRadius} 0 0 1 ${width} ${topRightRadius}`
      : null,
    // Draw a vertical line to the bottom right corner, considering bottom right radius
    `V ${height - bottomRightRadius}`,
    // Draw an arc for bottom right corner if radius is greater than 0
    bottomRightRadius > 0
      ? `A ${bottomRightRadius} ${bottomRightRadius} 0 0 1 ${
          width - bottomRightRadius
        } ${height}`
      : null,
    // Draw a horizontal line to the bottom left corner, considering bottom left radius
    `H ${bottomLeftRadius}`,
    // Draw an arc for bottom left corner if radius is greater than 0
    bottomLeftRadius > 0
      ? `A ${bottomLeftRadius} ${bottomLeftRadius} 0 0 1 0 ${
          height - bottomLeftRadius
        }`
      : null,
    // Draw a vertical line to the top left corner, considering top left radius
    `V ${topLeftRadius}`,
    // Draw an arc for top left corner if radius is greater than 0
    topLeftRadius > 0
      ? `A ${topLeftRadius} ${topLeftRadius} 0 0 1 ${topLeftRadius} 0`
      : null,
    // Close the path
    'Z',
  ]
    .filter((v) => v != null)
    .join(' ');
}


const node = {
  width: 512,
  height: 512,
  bottomLeftRadius: 10,
  bottomRightRadius: 50,
  topLeftRadius: 100,
  topRightRadius: 200
};

const svgPath = createRectanglePath(node);

document.getElementById('yourSVGPath').setAttribute('d', svgPath);
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
  <path id="yourSVGPath" fill="#4EDFA5">
</svg>
BennoDev
  • 1,067
  • 1
  • 6
  • 17