This is a migrated thread and some comments may be shown as answers.

Customize Donut Series Drawlines To Label

1 Answer 155 Views
ChartView
This is a migrated thread and some comments may be shown as answers.
Genda
Top achievements
Rank 2
Genda asked on 25 Feb 2021, 08:08 AM

Hallo Admin,

here I have a problem when I want to give a line to the label series on the ChartView (DonutSeries),
in this case I want to label the line always up, even though the position of the chart data is below
which I have created is in the image (Chart_No.png)

and I want to make like the image (Chart_Yes.png)

this is the method that i have created.

private void DrawRadChartViewDonutChart(RadChartView p_oRadChart)
        {
            p_oRadChart.View.Margin = new Padding(20); //set pie padding
            p_oRadChart.AreaType = ChartAreaType.Pie; //set to pie chart type
            p_oRadChart.Series.Clear();

            #region Config New Chart Series
            Telerik.WinControls.UI.DonutSeries smartPie = new Telerik.WinControls.UI.DonutSeries();
            smartPie.Name = "Series";
            smartPie.InnerRadiusFactor = 0.45f; //setting inner radious doughnut so it can change as Doughnut Chart
            smartPie.LabelMode = PieLabelModes.Horizontal;
            smartPie.ShowLabels = true; //show label text
            smartPie.DrawLinesToLabels = true; //show label line connector

            smartPie.LinesToLabelsColor = Color.FromArgb(197, 156, 97); //set label line connector color
            smartPie.SyncLinesToLabelsColor = false; //set true if we want to set label line color the same as series color
            smartPie.Size = new Size(200, 200);
            //set angle range starting position
            AngleRange range = smartPie.Range;
            range.StartAngle = 250;
            smartPie.Range = range;

            #endregion

            #region Generate Data
            

            List<DataChart> lData = new List<DataChart>();
            lData.Add(new DataChart("Savings", 30));
            lData.Add(new DataChart("Deposit", 15));
            lData.Add(new DataChart("Credit", 15));
            lData.Add(new DataChart("BancaAssurance", 10));
            lData.Add(new DataChart("MutualFund", 10));
            lData.Add(new DataChart("Jasa Giro", 20));
            #endregion

            //add slice area
            foreach (DataChart d in lData)
            {
                PieDataPoint point = new PieDataPoint(Convert.ToDouble(d.Value), d.Name);
                point.Label = d.Name.ToUpper();
                point.Label = string.Format("{0} | {1}%{2}{3} {4}", d.Name.ToUpper(), d.Value, Environment.NewLine, "IDR", Convert.ToDouble(d.ValueRp).ToString("N0"));
                smartPie.DataPoints.Add(point);
            }
            p_oRadChart.Series.Add(smartPie);

            #region Setting Series Slice Color
            p_oRadChart.Series[0].Children[0].BackColor = Color.FromArgb(193, 152, 105);
            p_oRadChart.Series[0].Children[1].BackColor = Color.FromArgb(207, 175, 140);
            p_oRadChart.Series[0].Children[2].BackColor = Color.FromArgb(221, 198, 173);
            p_oRadChart.Series[0].Children[3].BackColor = Color.FromArgb(235, 221, 206);
            p_oRadChart.Series[0].Children[4].BackColor = Color.FromArgb(193, 152, 105);
            p_oRadChart.Series[0].Children[5].BackColor = Color.FromArgb(207, 175, 140);
            p_oRadChart.Series[0].IsVisible = true;
            #endregion
        }

please help, thank you

1 Answer, 1 is accepted

Sort by
0
Dess | Tech Support Engineer, Principal
Telerik team
answered on 26 Feb 2021, 01:37 PM

Hello, Genda,

The following screenshot illustrates the default labels rendering in RadChartView:

After enabling the smart labels, the labels position is adjusted:

RadChartView offers a built-in mechanism for resolving labels overlapping. Depending on the calculated label's position by the default chart's labels strategy, its line is rendered accordingly:

That is why the line connecting the pie slice and the label may be rendered in a different way.

Note that you can implement your own label's strategy and thus implement custom algorithm for placing the labels. If you implement custom logic for placing the labels above the respective pie slice, the line will be rendered according to your requirements. You can find here a sample approach for implementing your own strategy: https://docs.telerik.com/devtools/winforms/controls/chartview/features/smart-labels#custom-labels-strategy 

An alternative approach is to plug into the line's rendering and control how the line is drawn. You can find below a sample approach how the line is drawn with the default logic that RadChartView offers: 

        public RadForm1()
        {
            InitializeComponent();
            this.radChartView1.LabelFormatting+=radChartView1_LabelFormatting;

            this.radChartView1.CreateRenderer+=radChartView1_CreateRenderer;
            this.radChartView1.AreaType = ChartAreaType.Pie;
            DonutSeries series = new DonutSeries();
            for (int i = 0; i < 3; i++)
            { 
            series.DataPoints.Add(new PieDataPoint(50, "Germany "+i));
            series.DataPoints.Add(new PieDataPoint(70, "United States "+i));
            series.DataPoints.Add(new PieDataPoint(40, "France "+i));
            series.DataPoints.Add(new PieDataPoint(25, "United Kingdom "+i)); 
            }
            series.ShowLabels = true;
            series.DrawLinesToLabels = true;
            this.radChartView1.Series.Add(series);

            this.radChartView1.ShowSmartLabels = true; 
        }

        private void radChartView1_CreateRenderer(object sender, ChartViewCreateRendererEventArgs e)
        {
            if (e.Area is PieArea)
            {
                e.Renderer = new CustomPieRenderer(e.Area as PieArea);
            }
        }

        public class CustomPieRenderer : PieRenderer
        {
            public CustomPieRenderer(PieArea area) : base(area)
            {
            }

            protected override void Initialize()
            {
                base.Initialize();
                this.DrawParts.Clear();

                for (int i = 0; i < this.Area.Series.Count; i++)
                {
                    if (this.Area.Series[i] is DonutSeries)
                    {
                        this.DrawParts.Add(new DonutSeriesDrawPart((DonutSeries)this.Area.Series[i], this));
                    }
                    else if (this.Area.Series[i] is PieSeries)
                    {
                        this.DrawParts.Add(new PieSeriesDrawPart((PieSeries)this.Area.Series[i], this));
                    }

                    this.DrawParts.Add(new CustomLabelElementDrawPart((PieSeries)this.Area.Series[i], this));
                }
            }
        }

        public class CustomLabelElementDrawPart : PieLabelElementDrawPart
        {
            public CustomLabelElementDrawPart(PieSeries element, IChartRenderer renderer)
                : base(element, renderer)
            {
            }

            protected override void DrawConnectingLine(Telerik.WinControls.Paint.RadGdiGraphics graphics, LabelElement label, DataPointElement point, bool isSmartLabel)
            { 
                graphics.ChangeSmoothingMode(System.Drawing.Drawing2D.SmoothingMode.AntiAlias);

                PointF center = new PointF((float)this.Element.View.Viewport.Center.X, (float)this.Element.View.Viewport.Center.Y);
                PointF lineStart = this.GetLineStart(label, point, isSmartLabel);
                PointF lineEnd = this.GetLineEnd(label, point, isSmartLabel);

                float radiusLineA = lineStart.Y - center.Y;
                float radiusLineB = center.X - lineStart.X;
                float radiusLineC = radiusLineA * center.X + radiusLineB * center.Y;

                float labelLineA = 0f;
                float labelLineB = 1;
                float labelLineC = lineEnd.Y;

                float delta = radiusLineA * labelLineB - labelLineA * radiusLineB;

                Color lineColor = ((ChartSeries)point.Parent).LinesToLabelsColor;

                if (((ChartSeries)point.Parent).SyncLinesToLabelsColor)
                {
                    lineColor = point.BackColor;
                }

                if (delta != 0f)
                {
                    PointF intersection = new PointF();
                    intersection.X = (labelLineB * radiusLineC - radiusLineB * labelLineC) / delta;
                    intersection.Y = (radiusLineA * labelLineC - labelLineA * radiusLineC) / delta;


                    if ((intersection.X <= lineStart.X && intersection.X >= lineEnd.X) || (intersection.X >= lineStart.X && intersection.X <= lineEnd.X))
                    {
                        if (intersection.Y <= center.Y)
                        {
                            if (intersection.Y <= lineStart.Y)
                            {
                                graphics.DrawLine(lineColor, lineStart.X, lineStart.Y, intersection.X, intersection.Y);
                                graphics.DrawLine(lineColor, lineEnd.X, lineEnd.Y, intersection.X, intersection.Y);

                                return;
                            }
                        }
                        else
                        {
                            if (intersection.Y >= lineStart.Y)
                            {
                                graphics.DrawLine(lineColor, lineStart.X, lineStart.Y, intersection.X, intersection.Y);
                                graphics.DrawLine(lineColor, lineEnd.X, lineEnd.Y, intersection.X, intersection.Y);

                                return;
                            }
                        }
                    }
                }

                graphics.DrawLine(lineColor, lineStart.X, lineStart.Y, lineEnd.X, lineEnd.Y);

                graphics.RestoreSmoothingMode();
            }

        }

You can draw a direct line connecting the pie slice and the label. However, do not forget that the label's position and the pie slice's location are important for the way the connecting line is rendered.

I hope this information helps. If you need any further assistance please don't hesitate to contact me. 

Regards,
Dess | Tech Support Engineer, Sr.
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

Genda
Top achievements
Rank 2
commented on 18 May 2021, 06:25 AM

thankyouu for answer.. this is very nice
Tags
ChartView
Asked by
Genda
Top achievements
Rank 2
Answers by
Dess | Tech Support Engineer, Principal
Telerik team
Share this question
or