@@ -2,6 +2,7 @@ namespace ScottPlot.Plottables;
22
33public class Pie : PieBase
44{
5+ public double Radius { get ; set ; } = 1.0 ;
56 public double ExplodeFraction { get ; set ; } = 0 ;
67 public double DonutFraction { get ; set ; } = 0 ;
78
@@ -12,95 +13,94 @@ public Pie(IList<PieSlice> slices)
1213
1314 public override AxisLimits GetAxisLimits ( )
1415 {
15- double radius = Math . Max ( SliceLabelDistance , 1 + ExplodeFraction ) + Padding ;
16+ double radius = Math . Max ( SliceLabelDistance , Radius + ExplodeFraction ) + Padding ;
1617 return new AxisLimits ( - radius , radius , - radius , radius ) ;
1718 }
1819
20+ protected virtual void RenderDonutSlice (
21+ RenderPack rp , SKPaint paint , LineStyle lineStyle , FillStyle fillStyle ,
22+ float radius , float sliceAngle , float startAngle )
23+ {
24+ PixelRect outerRect = new ( - radius , radius , - radius , radius ) ;
25+
26+ // radius of the inner edge of the pie when donut mode is enabled
27+ float innerRadius = radius * ( float ) DonutFraction ;
28+ PixelRect innerRect = new ( - innerRadius , innerRadius , - innerRadius , innerRadius ) ;
29+
30+ if ( Math . Abs ( sliceAngle ) < 360 )
31+ {
32+ Drawing . FillAnnularSector ( rp . Canvas , paint , fillStyle , outerRect , innerRect , startAngle , sliceAngle ) ;
33+ Drawing . DrawAnnularSector ( rp . Canvas , paint , lineStyle , outerRect , innerRect , startAngle , sliceAngle ) ;
34+ }
35+ else
36+ {
37+ Drawing . FillEllipticalAnnulus ( rp . Canvas , paint , fillStyle , outerRect , innerRect ) ;
38+ Drawing . DrawEllipticalAnnulus ( rp . Canvas , paint , lineStyle , outerRect , innerRect ) ;
39+ }
40+ }
41+
42+ protected virtual void RenderSlice (
43+ RenderPack rp , SKPaint paint , LineStyle lineStyle , FillStyle fillStyle ,
44+ float radius , float sliceAngle , float startAngle )
45+ {
46+ PixelRect outerRect = new ( - radius , radius , - radius , radius ) ;
47+
48+ if ( Math . Abs ( sliceAngle ) < 360 )
49+ {
50+ Drawing . FillSector ( rp . Canvas , paint , fillStyle , outerRect , startAngle , sliceAngle ) ;
51+ Drawing . DrawSector ( rp . Canvas , paint , lineStyle , outerRect , startAngle , sliceAngle ) ;
52+ }
53+ else
54+ {
55+ Drawing . FillOval ( rp . Canvas , paint , fillStyle , outerRect ) ;
56+ Drawing . DrawOval ( rp . Canvas , paint , lineStyle , outerRect ) ;
57+ }
58+ }
59+
1960 public override void Render ( RenderPack rp )
2061 {
21- using SKPath path = new ( ) ;
2262 using SKPaint paint = new ( ) { IsAntialias = true } ;
2363
2464 Pixel origin = Axes . GetPixel ( Coordinates . Origin ) ;
2565
26- float minX = Math . Abs ( Axes . GetPixelX ( 1 ) - origin . X ) ;
27- float minY = Math . Abs ( Axes . GetPixelY ( 1 ) - origin . Y ) ;
66+ float minX = Math . Abs ( Axes . GetPixelX ( Radius ) - origin . X ) ;
67+ float minY = Math . Abs ( Axes . GetPixelY ( Radius ) - origin . Y ) ;
2868
2969 // radius of the outer edge of the pie
3070 float outerRadius = Math . Min ( minX , minY ) ;
31- SKRect outerRect = new ( - outerRadius , - outerRadius , outerRadius , outerRadius ) ;
32-
33- // radius of the inner edge of the pie when donut mode is enabled
34- float innerRadius = outerRadius * ( float ) DonutFraction ;
35- SKRect innerRect = new ( - innerRadius , - innerRadius , innerRadius , innerRadius ) ;
3671
3772 double totalValue = Slices . Sum ( s => s . Value ) ;
3873 Angle totalAngle = Rotation ;
3974 foreach ( PieSlice slice in Slices )
4075 {
4176 using SKAutoCanvasRestore _ = new ( rp . Canvas ) ;
4277
43- var percentage = slice . Value / totalValue ;
44- var sliceAngle = Angle . FromDegrees ( percentage * 360 ) ;
78+ Angle sliceAngle = Angle . FromFraction ( slice . Value / totalValue ) ;
4579 Angle centerAngle = totalAngle + sliceAngle / 2 ;
4680
47- Coordinates explosionOffset = new PolarCoordinates ( ExplodeFraction * outerRadius , centerAngle ) . ToCartesian ( ) ;
81+ PolarCoordinates slicePolar = new ( ExplodeFraction * outerRadius , centerAngle ) ;
82+ Coordinates explosionOffset = slicePolar . ToCartesian ( ) ;
4883 rp . Canvas . Translate (
4984 ( float ) ( origin . X + explosionOffset . X ) ,
5085 ( float ) ( origin . Y + explosionOffset . Y ) ) ;
5186
52- if ( sliceAngle . Degrees == 360 )
87+ if ( DonutFraction > 0 )
5388 {
54- if ( DonutFraction > 0 )
55- {
56- // Clip inner oval
57- // avoid clipping to inner oval line
58- float innerRadius2 = innerRadius - 1 ;
59- path . AddOval ( new SKRect (
60- - innerRadius2 , - innerRadius2 , innerRadius2 , innerRadius2 ) ) ;
61- rp . Canvas . ClipPath ( path , SKClipOperation . Difference ) ;
62- path . Reset ( ) ;
63-
64- // Draw inner oval line
65- path . AddOval ( innerRect ) ;
66- LineStyle . ApplyToPaint ( paint ) ;
67- rp . Canvas . DrawPath ( path , paint ) ;
68- }
69-
70- path . AddOval ( outerRect ) ;
89+ RenderDonutSlice ( rp , paint , LineStyle , slice . Fill , outerRadius , ( float ) sliceAngle . Degrees , ( float ) totalAngle . Degrees ) ;
7190 }
7291 else
7392 {
74- Coordinates ptInnerHome = new PolarCoordinates ( innerRadius , totalAngle ) . ToCartesian ( ) ;
75- Coordinates ptOuterHome = new PolarCoordinates ( outerRadius , totalAngle ) . ToCartesian ( ) ;
76- Coordinates ptInnerRotated = new PolarCoordinates ( innerRadius , totalAngle + sliceAngle ) . ToCartesian ( ) ;
77-
78- path . MoveTo ( new SKPoint ( ( float ) ptInnerHome . X , ( float ) ptInnerHome . Y ) ) ;
79- path . LineTo ( new SKPoint ( ( float ) ptOuterHome . X , ( float ) ptOuterHome . Y ) ) ;
80- path . ArcTo ( outerRect ,
81- ( float ) totalAngle . Degrees ,
82- ( float ) sliceAngle . Degrees ,
83- false ) ;
84- path . LineTo ( new SKPoint ( ( float ) ptInnerRotated . X , ( float ) ptInnerRotated . Y ) ) ;
85- path . ArcTo ( innerRect ,
86- ( float ) ( totalAngle + sliceAngle ) . Degrees ,
87- ( float ) - sliceAngle . Degrees ,
88- false ) ;
89- path . Close ( ) ;
93+ RenderSlice ( rp , paint , LineStyle , slice . Fill , outerRadius , ( float ) sliceAngle . Degrees , ( float ) totalAngle . Degrees ) ;
9094 }
9195
92- PixelRect rect = new ( origin , outerRadius ) ;
93- Drawing . FillPath ( rp . Canvas , paint , path , slice . Fill , rect ) ;
94-
95- Drawing . DrawPath ( rp . Canvas , paint , path , LineStyle ) ;
96-
97- Coordinates polar = new PolarCoordinates ( 1.0 * SliceLabelDistance , centerAngle ) . ToCartesian ( ) ;
98- polar . Y = - polar . Y ;
99- Pixel px = Axes . GetPixel ( polar ) - origin ;
96+ Coordinates textPolar = slicePolar
97+ . WithRadius ( Radius * SliceLabelDistance )
98+ . ToCartesian ( ) ;
99+ textPolar . Y = - textPolar . Y ;
100+ Pixel px = Axes . GetPixel ( textPolar ) - origin ;
100101 slice . LabelStyle . Render ( rp . Canvas , px , paint ) ;
101102
102103 totalAngle += sliceAngle ;
103- path . Reset ( ) ;
104104 }
105105 }
106106}
0 commit comments