Skip to content

Commit 7d78859

Browse files
committed
Simpler logic for arc padding.
Rather than dynamically increasing the inner radius for thin wedges, preserve the inner radius but relax the requirement for sides parallel with the adjacent arc. As long as the inner radius is reasonably big, the behavior is pleasing and consistent. The recommended minimum inner radius when using padding is outerRadius * padAngle / sin(θ), where θ is the angle of the smallest arc (without padding). For example, if the outerRadius is 200 pixels and the padAngle is 0.02 radians, a reasonable θ is 0.04 radians and a reasonable innerRadius is 100 pixels.
1 parent 8b08481 commit 7d78859

3 files changed

Lines changed: 60 additions & 37 deletions

File tree

d3.js

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7901,31 +7901,30 @@
79017901
var innerRadius = d3_svg_arcInnerRadius, outerRadius = d3_svg_arcOuterRadius, cornerRadius = d3_zero, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle, padAngle = d3_svg_arcPadAngle;
79027902
function arc() {
79037903
var r0 = +innerRadius.apply(this, arguments), r1 = +outerRadius.apply(this, arguments), rc = +cornerRadius.apply(this, arguments), rc0 = 0, rc1 = 0, a0 = startAngle.apply(this, arguments) - halfπ, a1 = endAngle.apply(this, arguments) - halfπ, da = Math.abs(a1 - a0), p1 = (+padAngle.apply(this, arguments) || 0) / 2, p0 = 0, cw = a0 > a1 ? 0 : 1, cr = r0 < r1 ^ cw ? 0 : 1;
7904-
if (rc) {
7905-
rc = Math.min(Math.abs(r1 - r0) / 2 - ε, rc);
7906-
rc0 = Math.min(rc, r0, r0 / (1 / Math.sin(da / 2 - p0) + 1));
7907-
rc1 = Math.min(rc, r1, r1 / (1 / Math.sin(da / 2 - p1) + 1));
7908-
}
79097904
if (p1) {
7910-
r0 = Math.max(r0, r1 * p1 / Math.sin(da / 2));
7911-
rc0 = Math.min(rc, r0 / (1 / Math.sin(da / 2 - p0) + 1));
7912-
p0 = Math.asin((r1 - rc1) / (r0 + rc0) * Math.sin(p1));
7913-
rc0 = Math.min(rc, r0 / (1 / Math.sin(da / 2 - p0) + 1));
7905+
p0 = d3_asin(r1 / r0 * Math.sin(p1));
79147906
if (!cw) p0 *= -1, p1 *= -1;
79157907
}
7916-
return (da >= τε ? r0 ? circleSegment(r1, cw) + circleSegment(r0, 1 - cw) : circleSegment(r1, cw) : "M" + (rc1 ? roundedArcSegment(r1, rc1, a0 + p1, a1 - p1, cr, cw) : arcSegment(r1, a0 + p1, a1 - p1, cw)) + "L" + (r0 ? rc0 ? roundedArcSegment(r0, rc0, a1 - p0, a0 + p0, cr, 1 - cw) : arcSegment(r0, a1 - p0, a0 + p0, 1 - cw) : "0,0")) + "Z";
7908+
return (da >= τε ? r0 ? circleSegment(r1, cw) + circleSegment(r0, 1 - cw) : circleSegment(r1, cw) : "M" + (rc1 ? roundedArcSegment(r1, rc1, a0 + p1, a1 - p1, cr, cw) : arcSegment(r1, a0 + p1, a1 - p1, cw)) + "L" + (rc0 ? roundedArcSegment(r0, rc0, a1 - p0, a0 + p0, cr, 1 - cw) : arcSegment(r0, a1 - p0, a0 + p0, 1 - cw))) + "Z";
7909+
}
7910+
function sweep(x0, y0, x1, y1) {
7911+
return (x0 - x1) * y0 - (y0 - y1) * x0 > 0 ? 0 : 1;
79177912
}
79187913
function circleSegment(r1, cw) {
79197914
return "M0," + r1 + "A" + r1 + "," + r1 + " 0 1," + cw + " 0," + -r1 + "A" + r1 + "," + r1 + " 0 1," + cw + " 0," + r1;
79207915
}
79217916
function arcSegment(r1, a0, a1, cw) {
7922-
return r1 * Math.cos(a0) + "," + r1 * Math.sin(a0) + "A" + r1 + "," + r1 + " 0 " + (Math.abs(a1 - a0) < π ? 0 : 1) + "," + cw + " " + r1 * Math.cos(a1) + "," + r1 * Math.sin(a1);
7917+
var x0 = r1 * Math.cos(a0), y0 = r1 * Math.sin(a0), x1 = r1 * Math.cos(a1), y1 = r1 * Math.sin(a1), df = Math.abs(a1 - a0) <= π ? 0 : 1;
7918+
if (sweep(x0, y0, x1, y1) === cw ^ df) {
7919+
var ha = (a0 + a1) / 2;
7920+
return r1 * Math.cos(ha) + "," + r1 * Math.sin(ha);
7921+
}
7922+
return x0 + "," + y0 + "A" + r1 + "," + r1 + " 0 " + df + "," + cw + " " + x1 + "," + y1;
79237923
}
7924-
function roundedArcSegment(r1, rc, a0, a1, ccw, cw) {
7925-
var c0 = Math.cos(a0), s0 = Math.sin(a0), c1 = Math.cos(a1), s1 = Math.sin(a1), ra = cw ? -rc : rc, rb = ccw ? r1 + ra : r1 - ra, ro = Math.sqrt(rb * rb - rc * rc), xt0 = ro * c0, yt0 = ro * s0, xt1 = ro * c1, yt1 = ro * s1, xt2 = xt0 + ra * s0, yt2 = yt0 - ra * c0, xt3 = xt1 - ra * s1, yt3 = yt1 + ra * c1, ai1 = Math.atan2(yt2, xt2), ai0 = Math.atan2(yt3, xt3);
7926-
if (ai1 < ai0) ai1 += τ;
7927-
var corner = "A" + rc + "," + rc + " 0 0," + ccw + " ";
7928-
return xt0 + "," + yt0 + corner + d3_svg_arcCircleIntersect(r1, xt2, yt2, rc) + "A" + r1 + "," + r1 + " 0 " + (Math.abs(ai1 - ai0) > π ^ cw ? 1 : 0) + "," + cw + " " + d3_svg_arcCircleIntersect(r1, xt3, yt3, rc) + corner + xt1 + "," + yt1;
7924+
function roundedArcSegment(r1, rc, a0, a1, cr, cw) {
7925+
var c0 = Math.cos(a0), s0 = Math.sin(a0), c1 = Math.cos(a1), s1 = Math.sin(a1), ra = cw ? -rc : rc, rb = cr ? r1 + ra : r1 - ra, ro = Math.sqrt(rb * rb - rc * rc), xt0 = ro * c0, yt0 = ro * s0, xt1 = ro * c1, yt1 = ro * s1, xt2 = xt0 + ra * s0, yt2 = yt0 - ra * c0, xt3 = xt1 - ra * s1, yt3 = yt1 + ra * c1, ai1 = Math.atan2(yt2, xt2), ai0 = Math.atan2(yt3, xt3), corner = "A" + rc + "," + rc + " 0 0," + cr + " ";
7926+
if (ai1 < ai0 ^ cw) ai1 += τ;
7927+
return xt0 + "," + yt0 + corner + d3_svg_arcCircleIntersect(r1, xt2, yt2, rc) + "A" + r1 + "," + r1 + " 0 " + (Math.abs(ai1 - ai0) > π ? 1 : 0) + "," + cw + " " + d3_svg_arcCircleIntersect(r1, xt3, yt3, rc) + corner + xt1 + "," + yt1;
79297928
}
79307929
arc.innerRadius = function(v) {
79317930
if (!arguments.length) return innerRadius;

0 commit comments

Comments
 (0)