用C#寫了一個繪製柱狀圖的方法,只需傳入參數即可,自動繪製
先看看效果
柱狀的寬度自動調整
可自定義繪製位置,柱狀圖大小,數據
可自定義柱狀圖標題,X軸和Y軸描述信息
當X軸名稱較長時,可以設置旋轉一定的角度
全部代碼
public class ReportTest
{
/// <summary>
/// 初始化
/// </summary>
public void Init()
{
Doc = new PdfDocument();
Doc.PageSettings.Margins.All = 0;//設置邊距爲0
Doc.Pages.Add(); Doc.Pages.RemoveAt(0);//刪除第一頁,因爲有水印
Page = Doc.Pages.Add();
}
PdfDocument Doc;
PdfPageBase Page;
/// <summary>
/// 繪製柱狀圖
/// </summary>
/// <param name="model"></param>
public void DrawHistogram(HistogramModel model)
{
RectangleF loc = model.Location;
List<HistogramDataModel> data = model.Data;
int maxCount = data.Max(d => d.Count);
int ratio = (int)Math.Ceiling((float)maxCount / 5);
var familyName = "宋體";
var Font12 = new PdfTrueTypeFont(new Font(familyName, 12, FontStyle.Regular), true);
var Font10 = new PdfTrueTypeFont(new Font(familyName, 10, FontStyle.Regular), true);
var Font8 = new PdfTrueTypeFont(new Font(familyName, 8, FontStyle.Regular), true);
//背景顏色,淺黃色
var bgColor = new PdfSolidBrush(ColorTranslator.FromHtml("#ECE9D8"));
var fontColorBlack = new PdfSolidBrush(Color.Black);
//柱狀顏色
var fontColorRed = new PdfSolidBrush(Color.Red);
//柱狀備註顏色
var fontColorColumnar = new PdfSolidBrush(ColorTranslator.FromHtml("#FFFFE0"));
//繪製背景
Page.Canvas.DrawRectangle(bgColor, loc);
//深灰色筆
PdfPen lineColorPen = new PdfPen(ColorTranslator.FromHtml("#76746C"));
//黑色筆
PdfPen blackColorPen = new PdfPen(Color.Black);
//橫豎都分爲8個單元格,內邊距爲1個單元格,表格佔6個單元格,一個單元格的寬度和高度可能不同
SizeF cellSize = new SizeF(loc.Width / 8, loc.Height / 8);
//每個數據所佔寬度,包含1/3的間距和2/3的內容
float cellSizeEach = cellSize.Width * 6 / data.Count;
float cellSizeEach1_3 = cellSizeEach / 3;
float cellSizeEach2_3 = cellSizeEach1_3 * 2;
//單元格高度
float cellSizeHeight = cellSize.Height;
//原點
PointF yd = new PointF(loc.X + cellSize.Width, loc.Y + loc.Height - cellSize.Height);
//繪製標題
DrawText(page: Page, location: new PointF(loc.X, loc.Y + 3), font: Font12,
alignment: PdfTextAlignment.Center, colWidth: loc.Width, rowHeight: 17f, contents: model.Title);
//橫線
for (int i = 0; i < 7; i++)
{
float x1 = yd.X;
float y = loc.Y + cellSize.Height + i * cellSize.Height;
Page.Canvas.DrawLine(lineColorPen, x1, y, loc.X + loc.Width - cellSize.Width, y);
}
//繪製X軸描述
DrawText(page: Page, location: new PointF(yd.X - cellSize.Width, loc.Y + 5), font: Font10,
alignment: PdfTextAlignment.Right, colWidth: cellSize.Width, rowHeight: 17f, contents: model.XDescription);
//繪製Y軸描述
DrawText(page: Page, location: new PointF(loc.X + loc.Width - cellSize.Width + 5, loc.Y + loc.Height - cellSize.Height - 10), font: Font10,
alignment: PdfTextAlignment.Left, colWidth: cellSize.Width, rowHeight: 17f, contents: model.YDescription);
string[] contents = new string[7];
for (int i = 0; i < 7; i++)
{
contents[i] = (6 - i) * ratio + "";
}
//繪製數量描述
DrawText(page: Page, location: new PointF(yd.X - cellSize.Width, loc.Y + cellSizeHeight / 2), font: Font8,
alignment: PdfTextAlignment.Right, colWidth: cellSize.Width - 5, rowHeight: cellSizeHeight, contents: contents);
//豎線
for (int i = 0; i < 7; i++)
{
float x = loc.X + cellSize.Width + i * cellSize.Width;
float y2 = yd.Y;
Page.Canvas.DrawLine(lineColorPen, x, loc.Y + cellSize.Height, x, y2);
}
//繪製
for (int index = 0; index < data.Count; index++)
{
float ydSpacingX = yd.X + cellSizeEach1_3 * (index + 1) + cellSizeEach2_3 * index;
float count = data[index].Count;
float height = ratio == 0 ? 0 : cellSize.Height * (count / ratio);
RectangleF rect = new RectangleF(ydSpacingX, yd.Y - height, cellSizeEach2_3, height);
//避免柱狀過寬
if (rect.Width > cellSize.Width)
{
//居中
rect.X += (rect.Width - cellSize.Width) / 2;
//調整大小,最大寬度
rect.Width = cellSize.Width;
}
float rectWidth = rect.Width + 20;
float rectX = rect.X - 10;
//X軸描述是否傾斜
if (model.IsXDescriptionSlant == false)
{
//繪製Y軸描述
DrawText(page: Page, location: new PointF(rectX, rect.Y + rect.Height), font: Font8,
alignment: PdfTextAlignment.Center, colWidth: rectWidth, rowHeight: 17f, contents: data[index].Description);
}
else
{
#region 繪製Y軸描述 DrawString
float rectTran = rect.X + 5;
//保存當前狀態
Page.Canvas.Save();
//設置旋轉原點
Page.Canvas.TranslateTransform(rectTran, rect.Y + rect.Height);
//旋轉20度
Page.Canvas.RotateTransform(20);
//設置位置大小
PointF rectPointF = new PointF(0, 0);
SizeF rectSizeF = new SizeF(50, 20);
RectangleF rectStr = new RectangleF(rectPointF, rectSizeF);
Page.Canvas.DrawString(data[index].Description, Font8, fontColorBlack, rectStr);
//恢復上次狀態
Page.Canvas.Restore();
//備註:通過TranslateTransform設置旋轉原點,然後通過DrawString繪製時,只需設置座標爲0,0即可
#endregion 繪製Y軸描述 DrawString
}
if (count != -1 && height >= 0)
{
//繪製柱狀
Page.Canvas.DrawRectangle(blackColorPen, fontColorRed, rect);
}
if (count >= 0)
{
//繪製數量
DrawText(page: Page, location: new PointF(rectX, rect.Y - 15), font: Font8,
alignment: PdfTextAlignment.Center, colWidth: rectWidth, rowHeight: 17f, contents: data[index].Count.ToString());
}
}
}
/// <summary>
/// 繪製文本,爲了統一居中
/// </summary>
/// <param name="page">頁面</param>
/// <param name="location">繪製位置</param>
/// <param name="font">字體</param>
/// <param name="pdfTextAlignment">左右對齊方式</param>
/// <param name="colWidth">列寬度</param>
/// <param name="rowHeight">行高度</param>
/// <param name="contents">內容</param>
private void DrawText(PdfPageBase page, PointF location, PdfTrueTypeFont font, PdfTextAlignment alignment, float colWidth, float rowHeight, params string[] contents)
{
var Grid = new PdfGrid();
var col = Grid.Columns.Add();
Grid.Style.CellPadding = new PdfPaddings(0, 0, 0, 0);
Grid.Style.CellSpacing = 0;
Grid.Style.Font = font;
col.Width = colWidth;//列寬
for (int i = 0; i < contents.Length; i++)
{
var GridRow = Grid.Rows.Add();
GridRow.Height = rowHeight;
var PdfGridCell = GridRow.Cells[0];
PdfGridCell.StringFormat = new PdfStringFormat(alignment, PdfVerticalAlignment.Middle);//對齊方式
PdfGridCell.Value = contents[i];//繪製的文本
PdfGridCell.Style.Font = font;//字體
PdfGridCell.Style.TextBrush = new PdfSolidBrush(Color.Black);
}
//設置表格無邊框
PdfBorders borders = new PdfBorders { All = new PdfPen(Color.Transparent, 0.1f) };
foreach (PdfGridRow row in Grid.Rows)
{
foreach (PdfGridCell cell in row.Cells)
{
cell.Style.Borders = borders;
}
}
Grid.Draw(page, location);//繪製的位置
}
/// <summary>
/// 保存
/// </summary>
public void Save()
{
//保存
string path = Path.Combine(Environment.CurrentDirectory, "Histograms");
string name = DateTime.Now.ToString("yyyyMMddHHmmss");
if (Directory.Exists(path) == false)
{
Directory.CreateDirectory(path);
}
string fname = Path.Combine(path, name + ".pdf");
Doc.SaveToFile(fname);
Doc.Close();
//打開
Process.Start(fname);
}
}
/// <summary>
/// 柱狀圖參數
/// </summary>
public class HistogramModel
{
/// <summary>
/// 標題
/// </summary>
public string Title { get; set; }
/// <summary>
/// 位置
/// </summary>
public RectangleF Location { get; set; }
/// <summary>
/// X軸描述
/// </summary>
public string XDescription { get; set; }
/// <summary>
/// Y軸描述
/// </summary>
public string YDescription { get; set; }
/// <summary>
/// 數據
/// </summary>
public List<HistogramDataModel> Data { get; set; }
/// <summary>
/// X軸描述是否傾斜
/// </summary>
public bool IsXDescriptionSlant { get; set; } = false;
}
/// <summary>
/// 柱狀圖數據模型
/// </summary>
public class HistogramDataModel
{
public int Count { get; set; }
public string Description { get; set; }
}
使用
var test = new ReportTest();
test.Init();
List<HistogramDataModel> data = new List<HistogramDataModel>()
{
new HistogramDataModel() { Count = 10, Description = "項目1" },
new HistogramDataModel() { Count = 14, Description = "項目2" },
new HistogramDataModel() { Count = 16, Description = "項目3" },
new HistogramDataModel() { Count = 8, Description = "項目4" },
new HistogramDataModel() { Count = 20, Description = "項目5" },
};
RectangleF loc = new RectangleF(new PointF(50, 50), new SizeF(400, 180));
test.DrawHistogram(new HistogramModel()
{
Title = $"xxx統計柱狀圖1",
Location = loc,
XDescription = "數量",
YDescription = "項目",
Data = data,
IsXDescriptionSlant = false
});
List<HistogramDataModel> data2 = new List<HistogramDataModel>()
{
new HistogramDataModel() { Count = 30, Description = "項目名稱1" },
new HistogramDataModel() { Count = 10, Description = "項目名稱2" },
new HistogramDataModel() { Count = 50, Description = "項目名稱3" },
new HistogramDataModel() { Count = 45, Description = "項目名稱4" },
new HistogramDataModel() { Count = 32, Description = "項目名稱5" },
new HistogramDataModel() { Count = 25, Description = "項目名稱6" },
new HistogramDataModel() { Count = 53, Description = "項目名稱7" },
new HistogramDataModel() { Count = 23, Description = "項目名稱8" },
new HistogramDataModel() { Count = 46, Description = "項目名稱9" },
new HistogramDataModel() { Count = 33, Description = "項目名稱10" },
};
RectangleF loc2 = new RectangleF(new PointF(50, 280), new SizeF(480, 200));
test.DrawHistogram(new HistogramModel()
{
Title = $"xxx統計柱狀圖2",
Location = loc2,
XDescription = "數量",
YDescription = "項目",
Data = data2,
IsXDescriptionSlant = true
});
test.Save();
效果