【Spire.PDF】繪製柱狀圖,兼容性強,可自定義數據

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();

效果

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章