public class ReportTest
{
///
/// 初始化
///
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;
///
/// 绘制柱状图
///
///
public void DrawHistogram(HistogramModel model)
{
RectangleF loc = model.Location;
List 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());
}
}
}
///
/// 绘制文本,为了统一居中
///
/// 页面
/// 绘制位置
/// 字体
/// 左右对齐方式
/// 列宽度
/// 行高度
/// 内容
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);//绘制的位置
}
///
/// 保存
///
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);
}
}
///
/// 柱状图参数
///
public class HistogramModel
{
///
/// 标题
///
public string Title { get; set; }
///
/// 位置
///
public RectangleF Location { get; set; }
///
/// X轴描述
///
public string XDescription { get; set; }
///
/// Y轴描述
///
public string YDescription { get; set; }
///
/// 数据
///
public List Data { get; set; }
///
/// X轴描述是否倾斜
///
public bool IsXDescriptionSlant { get; set; } = false;
}
///
/// 柱状图数据模型
///
public class HistogramDataModel
{
public int Count { get; set; }
public string Description { get; set; }
}
var test = new ReportTest();
test.Init();
List data = new List()
{
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 data2 = new List()
{
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();
效果