Skip to content

Commit 74961d1

Browse files
authored
Add selfJoin option for doughnut graphs (#12054)
Co-authored-by: Pierre Gueguen <gueguenpierre.pro@gmail.com>
1 parent 9b1306a commit 74961d1

File tree

6 files changed

+97
-2
lines changed

6 files changed

+97
-2
lines changed

src/elements/element.arc.ts

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,42 @@
11
import Element from '../core/core.element.js';
22
import {_angleBetween, getAngleFromPoint, TAU, HALF_PI, valueOrDefault} from '../helpers/index.js';
3-
import {PI, _isBetween, _limitValue} from '../helpers/helpers.math.js';
3+
import {PI, _angleDiff, _normalizeAngle, _isBetween, _limitValue} from '../helpers/helpers.math.js';
44
import {_readValueToProps} from '../helpers/helpers.options.js';
55
import type {ArcOptions, Point} from '../types/index.js';
66

7+
function clipSelf(ctx: CanvasRenderingContext2D, element: ArcElement, endAngle: number) {
8+
const {startAngle, x, y, outerRadius, innerRadius, options} = element;
9+
const {borderWidth, borderJoinStyle} = options;
10+
const outerAngleClip = Math.min(borderWidth / outerRadius, _normalizeAngle(startAngle - endAngle));
11+
ctx.beginPath();
12+
ctx.arc(x, y, outerRadius - borderWidth / 2, startAngle + outerAngleClip / 2, endAngle - outerAngleClip / 2);
13+
14+
if (innerRadius > 0) {
15+
const innerAngleClip = Math.min(borderWidth / innerRadius, _normalizeAngle(startAngle - endAngle));
16+
ctx.arc(x, y, innerRadius + borderWidth / 2, endAngle - innerAngleClip / 2, startAngle + innerAngleClip / 2, true);
17+
} else {
18+
const clipWidth = Math.min(borderWidth / 2, outerRadius * _normalizeAngle(startAngle - endAngle));
19+
20+
if (borderJoinStyle === 'round') {
21+
ctx.arc(x, y, clipWidth, endAngle - PI / 2, startAngle + PI / 2, true);
22+
} else if (borderJoinStyle === 'bevel') {
23+
const r = 2 * clipWidth * clipWidth;
24+
const endX = -r * Math.cos(endAngle + PI / 2) + x;
25+
const endY = -r * Math.sin(endAngle + PI / 2) + y;
26+
const startX = r * Math.cos(startAngle + PI / 2) + x;
27+
const startY = r * Math.sin(startAngle + PI / 2) + y;
28+
ctx.lineTo(endX, endY);
29+
ctx.lineTo(startX, startY);
30+
}
31+
}
32+
ctx.closePath();
33+
34+
ctx.moveTo(0, 0);
35+
ctx.rect(0, 0, ctx.canvas.width, ctx.canvas.height);
36+
37+
ctx.clip('evenodd');
38+
}
39+
740

841
function clipArc(ctx: CanvasRenderingContext2D, element: ArcElement, endAngle: number) {
942
const {startAngle, pixelMargin, x, y, outerRadius, innerRadius} = element;
@@ -213,7 +246,7 @@ function drawBorder(
213246
circular: boolean,
214247
) {
215248
const {fullCircles, startAngle, circumference, options} = element;
216-
const {borderWidth, borderJoinStyle, borderDash, borderDashOffset} = options;
249+
const {borderWidth, borderJoinStyle, borderDash, borderDashOffset, borderRadius} = options;
217250
const inner = options.borderAlign === 'inner';
218251

219252
if (!borderWidth) {
@@ -246,6 +279,10 @@ function drawBorder(
246279
clipArc(ctx, element, endAngle);
247280
}
248281

282+
if (options.selfJoin && endAngle - startAngle >= PI && borderRadius === 0 && borderJoinStyle !== 'miter') {
283+
clipSelf(ctx, element, endAngle);
284+
}
285+
249286
if (!fullCircles) {
250287
pathArc(ctx, element, offset, spacing, endAngle, circular);
251288
ctx.stroke();
@@ -276,6 +313,7 @@ export default class ArcElement extends Element<ArcProps, ArcOptions> {
276313
spacing: 0,
277314
angle: undefined,
278315
circular: true,
316+
selfJoin: false,
279317
};
280318

281319
static defaultRoutes = {

src/types/index.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1847,6 +1847,12 @@ export interface ArcBorderRadius {
18471847
}
18481848

18491849
export interface ArcOptions extends CommonElementOptions {
1850+
/**
1851+
* If true, Arc can take up 100% of a circular graph without any visual split or cut. This option doesn't support borderRadius and borderJoinStyle miter
1852+
* @default true
1853+
*/
1854+
selfJoin: boolean;
1855+
18501856
/**
18511857
* Arc stroke alignment.
18521858
*/
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
module.exports = {
2+
config: {
3+
type: 'doughnut',
4+
data: {
5+
labels: ['Red'],
6+
datasets: [
7+
{
8+
// option in dataset
9+
data: [100],
10+
borderWidth: 15,
11+
backgroundColor: '#FF0000',
12+
borderColor: '#000000',
13+
borderAlign: 'center',
14+
selfJoin: true
15+
}
16+
]
17+
}
18+
},
19+
options: {
20+
canvas: {
21+
height: 256,
22+
width: 512
23+
}
24+
}
25+
};
Loading
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
module.exports = {
2+
config: {
3+
type: 'pie',
4+
data: {
5+
labels: ['Red'],
6+
datasets: [
7+
{
8+
// option in dataset
9+
data: [100],
10+
borderWidth: 15,
11+
backgroundColor: '#FF0000',
12+
borderColor: '#000000',
13+
borderAlign: 'center',
14+
borderJoinStyle: 'round',
15+
selfJoin: true
16+
}
17+
]
18+
}
19+
},
20+
options: {
21+
canvas: {
22+
height: 256,
23+
width: 512
24+
}
25+
}
26+
};
Loading

0 commit comments

Comments
 (0)