问题
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 top of each other to imitate that, but that seems kind of cheesy. Any way to do it using clipping or any d3.js method?
Right now I have a horizontal bar graph that has rects like:
rects.enter().append("rect")
.attr("x",function(d,i) { return x(0); })
.attr("width",function(d) { return x(d.value) - x(0); })
.attr("height",y.rangeBand())
.attr("y",function(d) { return y(d.name); })
I'm trying to produce rounded corners on the right hand side of the rect, but not sure how to do it.
回答1:
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.
回答2:
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;
}
回答3:
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(); })
回答4:
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;
}
回答5:
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.
来源:https://stackoverflow.com/questions/64355079/round-top-left-corner-on-a-rectangle