Winforms饼图图例文本的长度会影响标签和图表的大小

问题描述 投票:1回答:1

我设置了以下ChartArea注释设置:

private void chart1_PrePaint(object sender, ChartPaintEventArgs e)
        {
            if (e.ChartElement is ChartArea)
            {
                var ta = new TextAnnotation();
                ta.IsMultiline = true;
                ta.Text = "Results of Calculation\n%";
                ta.Width = e.Position.Width;
                ta.Height = e.Position.Height;
                ta.X = e.Position.X;
                ta.Y = e.Position.Y;
                ta.Font = new Font("Candara", e.Position.Height / 10, FontStyle.Regular);

                chart1.Annotations.Add(ta);
            }
        }

与此有关的一些问题以及与我发布的其他问题有关的Legend

My other Pie Chart Legend/ChartArea question

使用此PrePaint设置,我不确定TextAnnotation的位置是否正确。我正在使用e.Position,但它不是“准确地”出现在饼图区域的甜甜圈中间。我希望它能完美居中。不知道在此使用其他什么属性。

第二个问题是,图例文字长度发生变化时,它会“推动”并使ChartArea本身变小,从而使[[饼图变小]。我想反过来,ChartArea 饼图保持相同大小,但Legend被推开。

这可能吗?

以下是饼图的位置设置:ChartArea settings

谢谢

winforms charts annotations pie-chart legend-properties
1个回答
0
投票
首先,我创建了一个字典来存储居中的TextAnnotations引用(关键是图形名称,如果您有多个的话),然后在PrePaint事件中,获取图形中使用的TextAnnotation的正确引用并更新那一个的坐标。

第二,我手动设置InnerPlotPosition,这似乎解决了TextAnnotation居中的问题。当然,您需要像我对这行所做的那样为InnerPlot指定坐标和大小:

chart1.ChartAreas[0].InnerPlotPosition = new ElementPosition(0, 0, 60.65f, 94.99f);

最后,我手动设置图例的位置和大小,并使用扩展方法WrapAt在图例项文本中的每个_maxLegendTextBeforeWrap处设置一个“换行符”。无法找到使其随图例区域的宽度动态变化的方法,因此必须手动设置。

下面是产生的效果的GIF。不知道这是否适合您作为解决方案(根据我的口味,太多的调整和编码),但是无论如何。也许这可以引发一些有关如何解决的新思路。

为此,我创建了这些全局变量:

/// <summary> /// Saves the currently doughnut centered annotations per graph. /// </summary> private IDictionary<string, TextAnnotation> _annotationsByGraph; /// <summary> /// Number of characters /// </summary> private int _maxLegendTextBeforeWrap = 10; /// <summary> /// Legend area width. /// </summary> private int _legendWidth = 20; /// <summary> /// Legend area height. /// </summary> private int _legendHeight = 90;

这是Load事件的处理程序:

private void ChartTest_Load(object sender, EventArgs e) { // ** Start of test data ** chart1.Series["Series1"].Points.AddXY("A", 33); chart1.Series["Series1"].Points[0].LegendText = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; chart1.Series["Series1"].Points.AddXY("B", 33); chart1.Series["Series1"].Points[1].LegendText = "BBBBBBBBBBBBBBBBBBBB"; chart1.Series["Series1"].Points.AddXY("C", 34); chart1.Series["Series1"].Points[2].LegendText = "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC"; // ** End of test data ** // Creates a new instance of the dictionary storing the references to the annotations. _annotationsByGraph = new Dictionary<string, TextAnnotation>(); // Createa a new instance of an annotation for the chart1 graph. _annotationsByGraph.Add(chart1.Name, new TextAnnotation()); // Manually setting the position of the chart area prevents the imperfect positioning of the // TextAnnotation at the center of the doughnut. chart1.ChartAreas[0].Position.Auto = true; // Manually set the position of the InnerPlotPosition area prevents the imperfect positioning of the // TextAnnotation at the center of the doughnut. chart1.ChartAreas[0].InnerPlotPosition.Auto = false; chart1.ChartAreas[0].InnerPlotPosition = new ElementPosition(0, 0, 60.65f, 94.99f); // Minimum size for the legend font. chart1.Legends[0].AutoFitMinFontSize = 5; // Set the legend style as column. chart1.Legends[0].LegendStyle = LegendStyle.Column; // Splits the legend texts with the space char every _maxLegendTextBeforeWrap characters. chart1.Series["Series1"].Points.ToList().ForEach(p => p.LegendText = p.LegendText.WrapAt(_maxLegendTextBeforeWrap)); }

这是PrePaint事件的处理程序:

private void chart1_PrePaint(object sender, ChartPaintEventArgs e) { if (e.ChartElement is ChartArea) { // Get the reference to the corresponding text annotation for this chart. // We need this, otherwise we are creating and painting a new instance of a TextAnnotation // at every PrePaint, with the resulting blurrying effect caused by the overlapping of the text. var ta = _annotationsByGraph[e.Chart.Name]; // Check if the annotation has already been added to the chart. if (!e.Chart.Annotations.Contains(ta)) e.Chart.Annotations.Add(ta); // Set the properties of the centered TextAnnotation. ta.IsMultiline = true; ta.Text = "Results of Calculation\nx%"; ta.Font = new Font("Candara", e.Position.Height / 10, FontStyle.Regular); ta.Width = e.Position.Width; ta.Height = e.Position.Height; ta.X = e.Position.X; ta.Y = e.Position.Y; // Move the legend manually to the right of the doughnut. e.Chart.Legends[0].Position = new ElementPosition(e.Position.X + e.Position.Width, e.Position.Y, _legendWidth, _legendHeight); } }

这是按钮的作用:

private void BtnChangeLegendItemLength_Click(object sender, EventArgs e) { if (chart1.Series["Series1"].Points[1].LegendText.StartsWith("DD")) chart1.Series["Series1"].Points[1].LegendText = "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB".WrapAt(_maxLegendTextBeforeWrap); else chart1.Series["Series1"].Points[1].LegendText = "DDDDDD".WrapAt(_maxLegendTextBeforeWrap); }

这是扩展方法定义:

internal static class ExtensionMethods { public static string WrapAt(this string legendText, int maxLengthBeforeWrap) { if (legendText.Length <= maxLengthBeforeWrap) return legendText; // Integer division to get how many times we have to insert a space. var times = legendText.Length / maxLengthBeforeWrap; // Counter of added spaces. var spacesAdded = 0; // Iterate for each space char needed. for (var i = 1; i <= times; i++) { // Insert a space char every maxLengthBeforeWrap positions. legendText = legendText.Insert(maxLengthBeforeWrap * i + spacesAdded, new string(' ', 1)); spacesAdded++; } return legendText; } }

enter image description here
© www.soinside.com 2019 - 2024. All rights reserved.