diff --git a/README.md b/README.md
index 1fd83ec..c67f9ca 100644
--- a/README.md
+++ b/README.md
@@ -154,6 +154,20 @@ If the corner radius is greater than zero, the corners of the arc are rounded us
The corner radius may not be larger than ([outerRadius](#arc_outerRadius) - [innerRadius](#arc_innerRadius)) / 2. In addition, for arcs whose angular span is less than π, the corner radius may be reduced as two adjacent rounded corners intersect. This is occurs more often with the inner corners. See the [arc corners animation](http://bl.ocks.org/mbostock/b7671cb38efdfa5da3af) for illustration.
+Individual corners can be rounded by passing in an array of numbers length 1-4 instead of a single number.
+
+- Array length 4: first value applies to top-left corner, second value applies to top-right corner, third value applies to bottom-right corner, and fourth value applies to bottom-left corner
+
+- Array length 3: first value applies to top-left corner, second value applies to top-right and bottom-left corners, and third value applies to bottom-right corner
+
+- Array length 2: first value applies to top-left and bottom-right corners, and the second value applies to top-right and bottom-left corners
+
+- Array length 1 or single number: the value applies to all four corners, which are rounded equally
+
+(This assumes that the arc is being drawn clockwise i.e. end angle > start angle otherwise the order will be flipped, top right corner -> top left corner and bottom right corner -> bottom left corner)
+
+
+
# arc.startAngle([angle]) · [Source](https://github.com/d3/d3-shape/blob/main/src/arc.js)
If *angle* is specified, sets the start angle to the specified function or number and returns this arc generator. If *angle* is not specified, returns the current start angle accessor, which defaults to:
diff --git a/img/selected-corner-radius-rounding.png b/img/selected-corner-radius-rounding.png
new file mode 100644
index 0000000..758aee1
Binary files /dev/null and b/img/selected-corner-radius-rounding.png differ
diff --git a/src/arc.js b/src/arc.js
index 2032882..ad96217 100644
--- a/src/arc.js
+++ b/src/arc.js
@@ -122,11 +122,35 @@ export default function() {
da1 = da,
ap = padAngle.apply(this, arguments) / 2,
rp = (ap > epsilon) && (padRadius ? +padRadius.apply(this, arguments) : sqrt(r0 * r0 + r1 * r1)),
- rc = min(abs(r1 - r0) / 2, +cornerRadius.apply(this, arguments)),
- rc0 = rc,
- rc1 = rc,
+ mwrc = abs(r1 - r0) / 2,
t0,
- t1;
+ t1,
+ rc,
+ rc00,
+ rc01,
+ rc10,
+ rc11,
+ rci = cornerRadius.apply(this, arguments);
+
+ if (Array.isArray(rci)) {
+ for (var i = 0; i < rci.length; i++) rci[i] = min(mwrc, +rci[i]);
+ if (rci.length === 1) rc = [rci[0], rci[0], rci[0], rci[0]];
+ else if (rci.length === 2) rc = [rci[0], rci[1], rci[0], rci[1]];
+ else if (rci.length === 3) rc = [rci[0], rci[1], rci[2], rci[1]];
+ else if (rci.length === 4) rc = rci;
+ rc00 = rc[2];
+ rc01 = rc[3];
+ rc10 = rc[0];
+ rc11 = rc[1];
+ }
+ else {
+ rci = min(mwrc, +rci)
+ rc = [rci, rci, rci, rci];
+ rc00 = rc[2];
+ rc01 = rc[3];
+ rc10 = rc[0];
+ rc11 = rc[1];
+ }
// Apply padding? Note that since r1 ≥ r0, da1 ≥ da0.
if (rp > epsilon) {
@@ -144,7 +168,7 @@ export default function() {
y10 = r0 * sin(a10);
// Apply rounded corners?
- if (rc > epsilon) {
+ if (max(rc[0], rc[1], rc[2], rc[3]) > epsilon) {
var x11 = r1 * cos(a11),
y11 = r1 * sin(a11),
x00 = r0 * cos(a00),
@@ -158,9 +182,13 @@ export default function() {
bx = x11 - oc[0],
by = y11 - oc[1],
kc = 1 / sin(acos((ax * bx + ay * by) / (sqrt(ax * ax + ay * ay) * sqrt(bx * bx + by * by))) / 2),
- lc = sqrt(oc[0] * oc[0] + oc[1] * oc[1]);
- rc0 = min(rc, (r0 - lc) / (kc - 1));
- rc1 = min(rc, (r1 - lc) / (kc + 1));
+ lc = sqrt(oc[0] * oc[0] + oc[1] * oc[1]),
+ mlrc0 = (r0 - lc) / (kc - 1),
+ mlrc1 = (r1 - lc) / (kc + 1);
+ rc00 = min(rc[2], mlrc0);
+ rc01 = min(rc[3], mlrc0);
+ rc10 = min(rc[0], mlrc1);
+ rc11 = min(rc[1], mlrc1);
}
}
@@ -168,20 +196,20 @@ export default function() {
if (!(da1 > epsilon)) context.moveTo(x01, y01);
// Does the sector’s outer ring have rounded corners?
- else if (rc1 > epsilon) {
- t0 = cornerTangents(x00, y00, x01, y01, r1, rc1, cw);
- t1 = cornerTangents(x11, y11, x10, y10, r1, rc1, cw);
+ else if (rc10 > epsilon || rc11 > epsilon) {
+ t0 = cornerTangents(x00, y00, x01, y01, r1, rc10, cw);
+ t1 = cornerTangents(x11, y11, x10, y10, r1, rc11, cw);
context.moveTo(t0.cx + t0.x01, t0.cy + t0.y01);
// Have the corners merged?
- if (rc1 < rc) context.arc(t0.cx, t0.cy, rc1, atan2(t0.y01, t0.x01), atan2(t1.y01, t1.x01), !cw);
+ if (rc10 === rc11 && rc10 === mlrc1) context.arc(t0.cx, t0.cy, rc10, atan2(t0.y01, t0.x01), atan2(t1.y01, t1.x01), !cw);
// Otherwise, draw the two corners and the ring.
else {
- context.arc(t0.cx, t0.cy, rc1, atan2(t0.y01, t0.x01), atan2(t0.y11, t0.x11), !cw);
+ context.arc(t0.cx, t0.cy, rc10, atan2(t0.y01, t0.x01), atan2(t0.y11, t0.x11), !cw);
context.arc(0, 0, r1, atan2(t0.cy + t0.y11, t0.cx + t0.x11), atan2(t1.cy + t1.y11, t1.cx + t1.x11), !cw);
- context.arc(t1.cx, t1.cy, rc1, atan2(t1.y11, t1.x11), atan2(t1.y01, t1.x01), !cw);
+ context.arc(t1.cx, t1.cy, rc11, atan2(t1.y11, t1.x11), atan2(t1.y01, t1.x01), !cw);
}
}
@@ -193,20 +221,20 @@ export default function() {
if (!(r0 > epsilon) || !(da0 > epsilon)) context.lineTo(x10, y10);
// Does the sector’s inner ring (or point) have rounded corners?
- else if (rc0 > epsilon) {
- t0 = cornerTangents(x10, y10, x11, y11, r0, -rc0, cw);
- t1 = cornerTangents(x01, y01, x00, y00, r0, -rc0, cw);
+ else if (rc00 > epsilon || rc01 > epsilon) {
+ t0 = cornerTangents(x10, y10, x11, y11, r0, -rc00, cw);
+ t1 = cornerTangents(x01, y01, x00, y00, r0, -rc01, cw);
context.lineTo(t0.cx + t0.x01, t0.cy + t0.y01);
// Have the corners merged?
- if (rc0 < rc) context.arc(t0.cx, t0.cy, rc0, atan2(t0.y01, t0.x01), atan2(t1.y01, t1.x01), !cw);
+ if (rc00 === rc01 && rc00 === mlrc0) context.arc(t0.cx, t0.cy, rc00, atan2(t0.y01, t0.x01), atan2(t1.y01, t1.x01), !cw);
// Otherwise, draw the two corners and the ring.
else {
- context.arc(t0.cx, t0.cy, rc0, atan2(t0.y01, t0.x01), atan2(t0.y11, t0.x11), !cw);
+ context.arc(t0.cx, t0.cy, rc00, atan2(t0.y01, t0.x01), atan2(t0.y11, t0.x11), !cw);
context.arc(0, 0, r0, atan2(t0.cy + t0.y11, t0.cx + t0.x11), atan2(t1.cy + t1.y11, t1.cx + t1.x11), cw);
- context.arc(t1.cx, t1.cy, rc0, atan2(t1.y11, t1.x11), atan2(t1.y01, t1.x01), !cw);
+ context.arc(t1.cx, t1.cy, rc01, atan2(t1.y11, t1.x11), atan2(t1.y01, t1.x01), !cw);
}
}
@@ -234,7 +262,7 @@ export default function() {
};
arc.cornerRadius = function(_) {
- return arguments.length ? (cornerRadius = typeof _ === "function" ? _ : constant(+_), arc) : cornerRadius;
+ return arguments.length ? (cornerRadius = typeof _ === "function" ? _ : constant(_), arc) : cornerRadius;
};
arc.padRadius = function(_) {