*/
roundedRect: function(ctx, x, y, width, height, radius) {
if (radius) {
- var rx = Math.min(radius, width / 2);
- var ry = Math.min(radius, height / 2);
-
- ctx.moveTo(x + rx, y);
- ctx.lineTo(x + width - rx, y);
- ctx.quadraticCurveTo(x + width, y, x + width, y + ry);
- ctx.lineTo(x + width, y + height - ry);
- ctx.quadraticCurveTo(x + width, y + height, x + width - rx, y + height);
- ctx.lineTo(x + rx, y + height);
- ctx.quadraticCurveTo(x, y + height, x, y + height - ry);
- ctx.lineTo(x, y + ry);
- ctx.quadraticCurveTo(x, y, x + rx, y);
+ // NOTE(SB) `epsilon` helps to prevent minor artifacts appearing
+ // on Chrome when `r` is exactly half the height or the width.
+ var epsilon = 0.0000001;
+ var r = Math.min(radius, (height / 2) - epsilon, (width / 2) - epsilon);
+
+ ctx.moveTo(x + r, y);
+ ctx.lineTo(x + width - r, y);
+ ctx.arcTo(x + width, y, x + width, y + r, r);
+ ctx.lineTo(x + width, y + height - r);
+ ctx.arcTo(x + width, y + height, x + width - r, y + height, r);
+ ctx.lineTo(x + r, y + height);
+ ctx.arcTo(x, y + height, x, y + height - r, r);
+ ctx.lineTo(x, y + r);
+ ctx.arcTo(x, y, x + r, y, r);
} else {
ctx.rect(x, y, width, height);
}
var topY = y - offset;
var sideSize = Math.SQRT2 * radius;
ctx.beginPath();
- this.roundedRect(ctx, leftX, topY, sideSize, sideSize, radius / 2);
+
+ // NOTE(SB) the rounded rect implementation changed to use `arcTo`
+ // instead of `quadraticCurveTo` since it generates better results
+ // when rect is almost a circle. 0.425 (instead of 0.5) produces
+ // results visually closer to the previous impl.
+ this.roundedRect(ctx, leftX, topY, sideSize, sideSize, radius * 0.425);
+
ctx.closePath();
ctx.fill();
break;
expect(context.getCalls()).toEqual([
{name: 'moveTo', args: [15, 20]},
{name: 'lineTo', args: [35, 20]},
- {name: 'quadraticCurveTo', args: [40, 20, 40, 25]},
+ {name: 'arcTo', args: [40, 20, 40, 25, 5]},
{name: 'lineTo', args: [40, 55]},
- {name: 'quadraticCurveTo', args: [40, 60, 35, 60]},
+ {name: 'arcTo', args: [40, 60, 35, 60, 5]},
{name: 'lineTo', args: [15, 60]},
- {name: 'quadraticCurveTo', args: [10, 60, 10, 55]},
+ {name: 'arcTo', args: [10, 60, 10, 55, 5]},
{name: 'lineTo', args: [10, 25]},
- {name: 'quadraticCurveTo', args: [10, 20, 15, 20]}
+ {name: 'arcTo', args: [10, 20, 15, 20, 5]}
]);
});
it('should optimize path if radius is 0', function() {