* @param {CanvasRenderingContext2D} ctx
* @param {ArcElement} element
*/
-function pathArc(ctx, element, offset, spacing, end) {
+function pathArc(ctx, element, offset, spacing, end, circular) {
const {x, y, startAngle: start, pixelMargin, innerRadius: innerR} = element;
const outerRadius = Math.max(element.outerRadius + spacing + offset - pixelMargin, 0);
ctx.beginPath();
- // The first arc segment from point 1 to point 2
- ctx.arc(x, y, outerRadius, outerStartAdjustedAngle, outerEndAdjustedAngle);
+ if (circular) {
+ // The first arc segment from point 1 to point 2
+ ctx.arc(x, y, outerRadius, outerStartAdjustedAngle, outerEndAdjustedAngle);
- // The corner segment from point 2 to point 3
- if (outerEnd > 0) {
- const pCenter = rThetaToXY(outerEndAdjustedRadius, outerEndAdjustedAngle, x, y);
- ctx.arc(pCenter.x, pCenter.y, outerEnd, outerEndAdjustedAngle, endAngle + HALF_PI);
- }
+ // The corner segment from point 2 to point 3
+ if (outerEnd > 0) {
+ const pCenter = rThetaToXY(outerEndAdjustedRadius, outerEndAdjustedAngle, x, y);
+ ctx.arc(pCenter.x, pCenter.y, outerEnd, outerEndAdjustedAngle, endAngle + HALF_PI);
+ }
- // The line from point 3 to point 4
- const p4 = rThetaToXY(innerEndAdjustedRadius, endAngle, x, y);
- ctx.lineTo(p4.x, p4.y);
+ // The line from point 3 to point 4
+ const p4 = rThetaToXY(innerEndAdjustedRadius, endAngle, x, y);
+ ctx.lineTo(p4.x, p4.y);
- // The corner segment from point 4 to point 5
- if (innerEnd > 0) {
- const pCenter = rThetaToXY(innerEndAdjustedRadius, innerEndAdjustedAngle, x, y);
- ctx.arc(pCenter.x, pCenter.y, innerEnd, endAngle + HALF_PI, innerEndAdjustedAngle + Math.PI);
- }
+ // The corner segment from point 4 to point 5
+ if (innerEnd > 0) {
+ const pCenter = rThetaToXY(innerEndAdjustedRadius, innerEndAdjustedAngle, x, y);
+ ctx.arc(pCenter.x, pCenter.y, innerEnd, endAngle + HALF_PI, innerEndAdjustedAngle + Math.PI);
+ }
- // The inner arc from point 5 to point 6
- ctx.arc(x, y, innerRadius, endAngle - (innerEnd / innerRadius), startAngle + (innerStart / innerRadius), true);
+ // The inner arc from point 5 to point 6
+ ctx.arc(x, y, innerRadius, endAngle - (innerEnd / innerRadius), startAngle + (innerStart / innerRadius), true);
- // The corner segment from point 6 to point 7
- if (innerStart > 0) {
- const pCenter = rThetaToXY(innerStartAdjustedRadius, innerStartAdjustedAngle, x, y);
- ctx.arc(pCenter.x, pCenter.y, innerStart, innerStartAdjustedAngle + Math.PI, startAngle - HALF_PI);
- }
+ // The corner segment from point 6 to point 7
+ if (innerStart > 0) {
+ const pCenter = rThetaToXY(innerStartAdjustedRadius, innerStartAdjustedAngle, x, y);
+ ctx.arc(pCenter.x, pCenter.y, innerStart, innerStartAdjustedAngle + Math.PI, startAngle - HALF_PI);
+ }
- // The line from point 7 to point 8
- const p8 = rThetaToXY(outerStartAdjustedRadius, startAngle, x, y);
- ctx.lineTo(p8.x, p8.y);
+ // The line from point 7 to point 8
+ const p8 = rThetaToXY(outerStartAdjustedRadius, startAngle, x, y);
+ ctx.lineTo(p8.x, p8.y);
- // The corner segment from point 8 to point 1
- if (outerStart > 0) {
- const pCenter = rThetaToXY(outerStartAdjustedRadius, outerStartAdjustedAngle, x, y);
- ctx.arc(pCenter.x, pCenter.y, outerStart, startAngle - HALF_PI, outerStartAdjustedAngle);
+ // The corner segment from point 8 to point 1
+ if (outerStart > 0) {
+ const pCenter = rThetaToXY(outerStartAdjustedRadius, outerStartAdjustedAngle, x, y);
+ ctx.arc(pCenter.x, pCenter.y, outerStart, startAngle - HALF_PI, outerStartAdjustedAngle);
+ }
+ } else {
+ ctx.moveTo(x, y);
+
+ const outerStartX = Math.cos(outerStartAdjustedAngle) * outerRadius + x;
+ const outerStartY = Math.sin(outerStartAdjustedAngle) * outerRadius + y;
+ ctx.lineTo(outerStartX, outerStartY);
+
+ const outerEndX = Math.cos(outerEndAdjustedAngle) * outerRadius + x;
+ const outerEndY = Math.sin(outerEndAdjustedAngle) * outerRadius + y;
+ ctx.lineTo(outerEndX, outerEndY);
}
ctx.closePath();
}
-function drawArc(ctx, element, offset, spacing) {
+function drawArc(ctx, element, offset, spacing, circular) {
const {fullCircles, startAngle, circumference} = element;
let endAngle = element.endAngle;
if (fullCircles) {
- pathArc(ctx, element, offset, spacing, startAngle + TAU);
+ pathArc(ctx, element, offset, spacing, startAngle + TAU, circular);
for (let i = 0; i < fullCircles; ++i) {
ctx.fill();
}
}
}
-
- pathArc(ctx, element, offset, spacing, endAngle);
+ pathArc(ctx, element, offset, spacing, endAngle, circular);
ctx.fill();
return endAngle;
}
}
}
-function drawBorder(ctx, element, offset, spacing, endAngle) {
+function drawBorder(ctx, element, offset, spacing, endAngle, circular) {
const {options} = element;
const {borderWidth, borderJoinStyle} = options;
const inner = options.borderAlign === 'inner';
clipArc(ctx, element, endAngle);
}
- pathArc(ctx, element, offset, spacing, endAngle);
+ pathArc(ctx, element, offset, spacing, endAngle, circular);
ctx.stroke();
}
const {options, circumference} = this;
const offset = (options.offset || 0) / 2;
const spacing = (options.spacing || 0) / 2;
+ const circular = options.circular;
this.pixelMargin = (options.borderAlign === 'inner') ? 0.33 : 0;
this.fullCircles = circumference > TAU ? Math.floor(circumference / TAU) : 0;
ctx.fillStyle = options.backgroundColor;
ctx.strokeStyle = options.borderColor;
- const endAngle = drawArc(ctx, this, radiusOffset, spacing);
- drawBorder(ctx, this, radiusOffset, spacing, endAngle);
+ const endAngle = drawArc(ctx, this, radiusOffset, spacing, circular);
+ drawBorder(ctx, this, radiusOffset, spacing, endAngle, circular);
ctx.restore();
}
offset: 0,
spacing: 0,
angle: undefined,
+ circular: true,
};
/**