using System; using System.Collections; using System.Drawing; using System.Drawing.Drawing2D; namespace Server.Engines.Reports { // Modified from MS sample //********************************************************************* // // PieChart Class // // This class uses GDI+ to render Pie Chart. // //********************************************************************* public class PieChartRenderer : ChartRenderer { private const int _bufferSpace = 125; private Color _backgroundColor; private Color _borderColor; private ArrayList _chartItems; private int _legendFontHeight; private float _legendFontSize; private string _legendFontStyle; private int _legendHeight; private int _legendWidth; private int _perimeter; private float _total; public PieChartRenderer() { _chartItems = new ArrayList(); _perimeter = 250; _backgroundColor = Color.White; _borderColor = Color.FromArgb(63, 63, 63); _legendFontSize = 8; _legendFontStyle = "Verdana"; } public PieChartRenderer(Color bgColor) { _chartItems = new ArrayList(); _perimeter = 250; _backgroundColor = bgColor; _borderColor = Color.FromArgb(63, 63, 63); _legendFontSize = 8; _legendFontStyle = "Verdana"; } public bool ShowPercents{ get; set; } //********************************************************************* // // This method collects all data points and calculate all the necessary dimensions // to draw the chart. It is the first method called before invoking the Draw() method. // //********************************************************************* public void CollectDataPoints(string[] xValues, string[] yValues) { _total = 0.0f; for (int i = 0; i < xValues.Length; i++) { float ftemp = Convert.ToSingle(yValues[i]); _chartItems.Add(new DataItem(xValues[i], xValues.ToString(), ftemp, 0, 0, Color.AliceBlue)); _total += ftemp; } float nextStartPos = 0.0f; int counter = 0; foreach (DataItem item in _chartItems) { item.StartPos = nextStartPos; item.SweepSize = item.Value / _total * 360; nextStartPos = item.StartPos + item.SweepSize; item.ItemColor = GetColor(counter++); } CalculateLegendWidthHeight(); } //********************************************************************* // // This method returns a bitmap to the calling function. This is the method // that actually draws the pie chart and the legend with it. // //********************************************************************* public override Bitmap Draw() { int perimeter = _perimeter; Rectangle pieRect = new Rectangle(0, 0, perimeter, perimeter - 1); Bitmap bmp = new Bitmap(perimeter + _legendWidth, perimeter); Font fnt = null; Pen pen = null; Graphics grp = null; StringFormat sf = null, sfp = null; try { grp = Graphics.FromImage(bmp); grp.CompositingQuality = CompositingQuality.HighQuality; grp.SmoothingMode = SmoothingMode.AntiAlias; sf = new StringFormat(); //Paint Back ground using (SolidBrush brsh = new SolidBrush(_backgroundColor)) { grp.FillRectangle(brsh, -1, -1, perimeter + _legendWidth + 1, perimeter + 1); } //Align text to the right sf.Alignment = StringAlignment.Far; //Draw all wedges and legends for (int i = 0; i < _chartItems.Count; i++) { DataItem item = (DataItem)_chartItems[i]; SolidBrush brs = null; try { brs = new SolidBrush(item.ItemColor); grp.FillPie(brs, pieRect, item.StartPos, item.SweepSize); //grp.DrawPie(new Pen(_borderColor,1.2f),pieRect,item.StartPos,item.SweepSize); if (fnt == null) fnt = new Font(_legendFontStyle, _legendFontSize); if (ShowPercents && item.SweepSize > 10) { if (sfp == null) { sfp = new StringFormat(); sfp.Alignment = StringAlignment.Center; sfp.LineAlignment = StringAlignment.Center; } float perc = item.SweepSize * 100.0f / 360.0f; string percString = $"{perc:F0}%"; float px = pieRect.X + pieRect.Width / 2; float py = pieRect.Y + pieRect.Height / 2; double angle = item.StartPos + item.SweepSize / 2; double rads = angle / 180.0 * Math.PI; px += (float)(Math.Cos(rads) * perimeter / 3); py += (float)(Math.Sin(rads) * perimeter / 3); grp.DrawString(percString, fnt, Brushes.Gray, new RectangleF(px - 30 - 1, py - 20, 60, 40), sfp); grp.DrawString(percString, fnt, Brushes.Gray, new RectangleF(px - 30 + 1, py - 20, 60, 40), sfp); grp.DrawString(percString, fnt, Brushes.Gray, new RectangleF(px - 30, py - 20 - 1, 60, 40), sfp); grp.DrawString(percString, fnt, Brushes.Gray, new RectangleF(px - 30, py - 20 + 1, 60, 40), sfp); grp.DrawString(percString, fnt, Brushes.White, new RectangleF(px - 30, py - 20, 60, 40), sfp); } if (pen == null) pen = new Pen(_borderColor, 0.5f); grp.FillRectangle(brs, perimeter + _bufferSpace, i * _legendFontHeight + 15, 10, 10); grp.DrawRectangle(pen, perimeter + _bufferSpace, i * _legendFontHeight + 15, 10, 10); grp.DrawString(item.Label, fnt, Brushes.Black, perimeter + _bufferSpace + 20, i * _legendFontHeight + 13); grp.DrawString(item.Value.ToString("#,###.##"), fnt, Brushes.Black, perimeter + _bufferSpace + 200, i * _legendFontHeight + 13, sf); } finally { brs?.Dispose(); } } for (int i = 0; i < _chartItems.Count; i++) { DataItem item = (DataItem)_chartItems[i]; SolidBrush brs = null; try { grp.DrawPie(new Pen(_borderColor, 0.5f), pieRect, item.StartPos, item.SweepSize); } finally { brs?.Dispose(); } } //draws the border around Pie using (Pen pen2 = new Pen(_borderColor, 2)) { grp.DrawEllipse(pen2, pieRect); } //draw border around legend using (Pen pen1 = new Pen(_borderColor, 1)) { grp.DrawRectangle(pen1, perimeter + _bufferSpace - 10, 10, 220, _chartItems.Count * _legendFontHeight + 25); } //Draw Total under legend using (Font fntb = new Font(_legendFontStyle, _legendFontSize, FontStyle.Bold)) { grp.DrawString("Total", fntb, Brushes.Black, perimeter + _bufferSpace + 30, (_chartItems.Count + 1) * _legendFontHeight, sf); grp.DrawString(_total.ToString("#,###.##"), fntb, Brushes.Black, perimeter + _bufferSpace + 200, (_chartItems.Count + 1) * _legendFontHeight, sf); } grp.SmoothingMode = SmoothingMode.AntiAlias; } finally { sf?.Dispose(); grp?.Dispose(); sfp?.Dispose(); fnt?.Dispose(); pen?.Dispose(); } return bmp; } //********************************************************************* // // This method calculates the space required to draw the chart legend. // //********************************************************************* private void CalculateLegendWidthHeight() { Font fontLegend = new Font(_legendFontStyle, _legendFontSize); _legendFontHeight = fontLegend.Height + 3; _legendHeight = fontLegend.Height * (_chartItems.Count + 1); if (_legendHeight > _perimeter) _perimeter = _legendHeight; _legendWidth = _perimeter + _bufferSpace; fontLegend.Dispose(); } } }