Is there a good way change the following example (stackblitz), in order to have some space between the paths and have them rounded (eg. using stroke-linecap: round).
Here is the example: https://stackblitz.com/edit/angular-ivy-uqwde8?file=src%2Fapp%2Fapp.component.html,src%2Fapp%2Fapp.component.ts,src%2Fapp%2Fdonut-chart%2Fdonut-chart.component.ts
I am not sure who made this and how exactly this works. But changes to donut-chart.pipe.ts
can get close to what you want.
const degrees = this.percentToDegrees(donutSlice.percent - 3);
const innerRadius = radius - borderSize + 10;
Though you can't get the rounded corners that simply. A SVG path is defined by series of points - you would have to re-calculate those points. SVG stroke could have rounded tips but not an SVG path, nor can SVG path inherit CSS type of properties. Unfortunately seems that the original author did not implement this feature either. So we should do some math to get them rounded.
Basically you could add more Elliptical Arc's to both tips of the svg. Following advice from: https://stackoverflow.com/a/38118843/15439733 and using https://yqnn.github.io/svg-path-editor/ I do the following:
So by adding A 1 1 0 0 0 100 50
to the green path we get something like this.
M 100 50 A 50 50 0 1 0 1.5708 62.4345 L 6.4138 61.191 A 45 45 0 1 1 95 50 A 1 1 0 0 0 100 50
And for the other tip adding A 1 1 0 1 0 5.7971 58.4322
With both tips:
M 100 50 A 50 50 0 1 0 0.8856 59.3691 A 1 1 0 1 0 5.7971 58.4322 A 45 45 0 1 1 95 50 A 1 1 0 1 0 100 50
So now we understand what we need to do, we add Arc before L
and an Arc to the end, where x, y is the locations of the original path.
commands.push(`A 1 1 0 1 0 ${ this.getCoordFromDegrees(degrees, innerRadius, svgSize) }`);
commands.push(`A 1 1 0 0 0 100 50`);
I have marked the changes with // <-------
.
getSliceCommands(donutSlice: DonutSlice, radius: number, svgSize: number, borderSize: number): string {
const degrees = this.percentToDegrees(donutSlice.percent - 3); // <-------
const longPathFlag = degrees > 180 ? 1 : 0;
const innerRadius = radius - borderSize + 10; // <-------
const commands: string[] = [];
commands.push(`M ${ svgSize / 2 + radius } ${ svgSize / 2 }`);
commands.push(`A ${ radius } ${ radius } 0 ${ longPathFlag } 0 ${ this.getCoordFromDegrees(degrees, radius, svgSize) }`);
commands.push(`A 1 1 0 1 0 ${ this.getCoordFromDegrees(degrees, innerRadius, svgSize) }`); // <-------
commands.push(`L ${ this.getCoordFromDegrees(degrees, innerRadius, svgSize) }`);
commands.push(`A ${ innerRadius } ${ innerRadius } 0 ${ longPathFlag } 1 ${ svgSize / 2 + innerRadius } ${ svgSize / 2 }`);
commands.push(`A 1 1 0 0 0 100 50`); // <-------
return commands.join(' ');
}
End result:
Forked: https://stackblitz.com/edit/angular-ivy-foqctq?file=src%2Fapp%2Fdonut-chart%2Fdonut-chart.pipe.ts