我设置了以下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
被推开。
谢谢
第二,我手动设置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; } }