快速开发报表
快速开发报表
潇洒丶疯一回 发表于4个月前
快速开发报表
  • 发表于 4个月前
  • 阅读 6
  • 收藏 0
  • 点赞 0
  • 评论 0

腾讯云 技术升级10大核心产品年终让利>>>   

针对客户的需求来定制化开发(基本上是死写代码)来实现,经常导致项目经常性的延期,因为客户的需求经常会变化,随着用户的使用认知度的提高,对报表的要求越来越高,导致程序员不停的修改代码来实现,效率不高、结束遥遥无期。。。非常的痛苦,
所以我们决定自己来开发一套像目前的润乾、FineReport 这样的报表设计器,来实现快速的报表设计制作。

 定位

    1、基本无需程序员写代码,通过配置的方式实现项目。

     2、在特定领域,提高报表开发效率。

     3、不同的程序员写出同样的代码。

本文将我们当初设计制作的报表设计器的功能分享出来,让有需要的或想开发报表设计的朋友们提供一个参考,尽量少走很动弯路,设计端可以直接使用,但是计算引擎和网页的计算的源码就不能分享出来了(请不要介意,因为涉及到保密)。

 记得当初为了制作报表设计器,在网上查找有没有相关的实例资料,找了很久,也是没有找到合适的,后来发现 SourceGrid 可以实现单元格的合并拆分功能,所以决定修改实现winform端的报表设计。下面我将制作的E_Report 报表控件抽取出来建立一个简易的Winform的可运行的实例提供给大伙下载,希望能给你的开发提供一点帮助和借鉴;当然你可以直接使用也可以,里面的设计功能基本全部能。
 抽取出来的源码包含:E_Report 报表设计自定义控件DLL源码;  EReportDemo 建立的简易Winform 端设计器使用DLL的实例源码;
 抽取出来的源码包含:E_Report 报表设计自定义控件DLL源码;  EReportDemo 建立的简易Winform 端设计器使用DLL的实例源码;
      

 例如单元格属性(其他还有很多的属性,自己下载源码后运行起来就能看到了)

 


                
对表格的斜线、斜线文字有很好的支持;可以设置表头、表位、标题等 实际效果图如下

 


                


二、使用介绍
1、页面初始化的时候,通过 ReportDoc 类 初始报表的行列及单元格属性
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Xml;
using System.Collections;
using E_Report;
 
namespace EReportDemo
{
    /// <summary>
    /// 报表表格对象
    /// </summary>
    public class ReportDoc
    {
        #region 变量参数定义
 
        /// <summary>
        /// 表格对象
        /// </summary>
        private EReport _nowReport;
 
        /// <summary>
        /// 报表配置编码
        /// </summary>
        private string _reportCode = "";
 
        /// <summary>
        /// 表报设计状态
        /// </summary>
        private string _reportState = "";
 
        #endregion
 
        #region 函数构造方法
 
        /// <summary>
        /// 构造函数
        /// </summary>
        public ReportDoc()
        {
            this._nowReport = null;
            this._reportCode = "";
            this._reportState = "";
 
        }
 
 
        /// <summary>
        /// 获取--设置--表格对象
        /// </summary>
        public EReport NowReport
        {
            get { return this._nowReport; }
            set { this._nowReport = value; }
        }
 
        /// <summary>
        /// 报表配置编码
        /// </summary>
        public string ReportCode
        {
            get { return this._reportCode; }
            set { this._reportCode = value; }
        }
 
        /// <summary>
        /// 报表设计状态
        /// 新增、修改 两种状态
        /// </summary>
        public string ReportState
        {
            get { return this._reportState; }
            set { this._reportState = value; }
        }
 
        /// <summary>
        /// 资源释放
        /// </summary>
        ~ReportDoc()
        {
            this._nowReport = null;
            this._reportState = "";
 
        }
 
        #endregion
 
        #region 加载报表表格
 
        /// <summary>
        /// 初始化--报表表格
        /// </summary>
        public void InitReport()
        {
 
            int rCount = 41;  // 41行
            int cCount = 20;  // 20列
 
            _nowReport.Redim(rCount, cCount);
            _nowReport.FixedRows = 1;
            _nowReport.FixedColumns = 1;
 
            InitCells();
 
        }
 
        /// <summary>
        /// 初始化--单元格
        /// </summary>
        public void InitCells()
        {
            // 第一行 第一列
            _nowReport.Rows[0].Height = 23;
            _nowReport.Columns[0].Width = 50;
 
            // 设置00格
            _nowReport[0, 0] = new E_Report.Cells.HeaderColumn("");
 
            //  设置行
            for (int rr = 1; rr < _nowReport.RowsCount; rr++)
            {
                string tmRowT = rr.ToString();
                _nowReport[rr, 0] = new E_Report.Cells.HeaderRow(tmRowT);
            }
 
            //  设置列
            for (int cc = 1; cc < _nowReport.ColumnsCount; cc++)
            {
                _nowReport[0, cc] = new E_Report.Cells.HeaderColumn(_nowReport.GetColumnHeadTileChar(cc));
            }
 
            // 设置单元格
            for (int iRow = 1; iRow < _nowReport.RowsCount; iRow++)
            {
                for (int iCol = 1; iCol < _nowReport.ColumnsCount; iCol++)
                {
                    _nowReport[iRow, iCol] = new E_Report.Cells.Cell("", typeof(string));
                }
            }
 
        }
 
 
        #endregion
 
    }
}

2、工具导航栏 设置单元格相关属性
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using E_Report;

namespace EReportDemo
{
    /// <summary>
    /// 本程序只是Winform端的报表设计功能
    /// 至于其他的功能,本实例没有提供
    /// 报表设计的设计效果:可以查看  www.sdpsoft.com  SDP软件快速开发平台 报表设计篇
    /// </summary>

    public partial class EReportMain : Form
    {
        private ReportDoc report;
        private E_Report.Cells.Controllers.PopupMenu myPopupMenu;

        public EReportMain()
        {
            InitializeComponent();
        }

        private void EReportMain_Load(object sender, EventArgs e)
        {
            Cursor.Current = Cursors.WaitCursor;
            gridMain.Rows.Clear();
            myPopupMenu = new E_Report.Cells.Controllers.PopupMenu(gridMain);

            report = new ReportDoc();
            report.NowReport = gridMain;
            report.InitReport();
            Cursor.Current = Cursors.Default;
        }

        private void gridMain_MouseMove(object sender, MouseEventArgs e)
        {
            this.lbl_X.Text = e.X.ToString();
            this.lbl_Y.Text = e.Y.ToString();
        }

        /// <summary>
        /// 工具栏报表单元格事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_GridTools_Click(object sender, EventArgs e)
        {
            string sType = ((Button)sender).Tag.ToString().Trim().ToLower();
            switch (sType)
            {

                case "cellproperty":  // 单元格属性设置
                    myPopupMenu.CellProperty_Click(sender, e);
                    break;
                case "fontset":       // 单元格字体设置
                    myPopupMenu.CellFont_Click(sender, e);
                    break;
                case "fontcolor":     // 文本字体颜色
                    myPopupMenu.CellForColor_Click(sender, e);
                    break;
                case "backcolor":     // 单元格背景色
                    myPopupMenu.CellBackColor_Click(sender, e);
                    break;
                case "cellborder":   // 单元格边框设置
                    myPopupMenu.CellBorder_Click(sender, e);
                    break;
                case "lock":         // 设置表格只读
                    myPopupMenu.LockReport_Click(sender, e);
                    break;
                case "unlock":       // 设置表格编辑
                    myPopupMenu.UnLockReport_Click(sender, e);
                    break;
                case "alignleft":    // 水平居左对齐
                    myPopupMenu.AlignLeft_Click(sender, e);
                    break;
                case "aligncenter":  // 水平居中对齐
                    myPopupMenu.AlignCenter_Click(sender, e);
                    break;
                case "alignright":   // 水平居右对齐
                    myPopupMenu.AlignRight_Click(sender, e);
                    break;
                case "aligntop":     // 垂直居上对齐
                    myPopupMenu.AlignTop_Click(sender, e);
                    break;
                case "alignmiddle":  // 垂直居中对齐
                    myPopupMenu.AlignMiddle_Click(sender, e);
                    break;
                case "alignbottom":  // 垂直居下对齐
                    myPopupMenu.AlignBottom_Click(sender, e);
                    break;
                case "addindent":    // 增加文本缩进
                    myPopupMenu.AddIndent_Click(sender, e);
                    break;
                case "delindent":    // 清除文本缩进
                    myPopupMenu.RemoveIndent_Click(sender, e);
                    break;
                case "insertrow":    // 插入后一行
                    myPopupMenu.InsertRow_Click(sender, e);
                    break;
                case "appendrow":    // 表格追加行
                    myPopupMenu.AddRow_Click(sender, e);
                    break;
                case "delrow":       // 删除选中行
                    myPopupMenu.DeleteRows_Click(sender, e);
                    break;
                case "hiderow":      // 隐藏选中行
                    myPopupMenu.HideSelectRows_Click(sender, e);
                    break;
                case "showrow":      // 显示选中行
                    myPopupMenu.ShowSelectRows_Click(sender, e);
                    break;
                case "showallrow":   // 显示所有行
                    myPopupMenu.ShowAllRows_Click(sender, e);
                    break;
                case "insertcol":    // 插入左侧列
                    myPopupMenu.InsertColumn_Click(sender, e);
                    break;
                case "addcol":       // 插入右侧列
                    myPopupMenu.AddColumn_Click(sender, e);
                    break;
                case "delcol":       // 删除选中列
                    myPopupMenu.DeleteColumns_Click(sender, e);
                    break;
                case "hidecol":      // 隐藏选中列
                    myPopupMenu.HideSelectColumns_Click(sender, e);
                    break;
                case "showcol":      // 显示选中列
                    myPopupMenu.ShowSelectColumns_Click(sender, e);
                    break;
                case "showallcol":   // 显示所有列
                    myPopupMenu.ShowAllColumns_Click(sender, e);
                    break;
                case "mergecell":    // 合并单元格
                    myPopupMenu.MergeCell_Click(sender, e);
                    break;
                case "splitcell":    // 拆分单元格
                    myPopupMenu.SplitCell_Click(sender, e);
                    break;
            }
        }
    }
}

3、报表控件DLL类库部分


                                  

 


 表格内自定义图表控件(曲线、柱状、饼状)源码
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;

namespace E_Report
{
    /// <summary>
    /// 图表属性
    /// </summary>
    /// <summary>
    /// 报表图表类库
    /// </summary>
    public class EChart
    {
        #region 属性方法

        #region 临时变量

        /// <summary>
        /// 临时变量--关联单元格行号
        /// </summary>
        private int _row = 0;

        /// <summary>
        /// 获取--设置--关联单元格行号
        /// </summary>
        public int Row
        {
            get { return _row; }
            set { _row = value; }
        }

        /// <summary>
        /// 临时变量--关联单元格列号
        /// </summary>
        private int _col = 0;

        /// <summary>
        /// 获取--设置--关联单元格列号
        /// </summary>
        public int Col
        {
            get { return _col; }
            set { _col = value; }
        }

        /// <summary>
        /// 数据来源
        /// </summary>
        private string _t_DataFrom = "数据源";

        /// <summary>
        /// 获取--设置--数据来源
        /// </summary>
        public string T_DataFrom
        {
            get { return _t_DataFrom; }
            set { _t_DataFrom = value; }
        }

        /// <summary>
        /// 数据源名称
        /// </summary>
        private string _t_DsName = "";

        /// <summary>
        /// 获取--设置--数据源名称
        /// </summary>
        public string T_DsName
        {
            get { return _t_DsName; }
            set { _t_DsName = value; }
        }

        /// <summary>
        /// 项目名称
        /// </summary>
        private string _t_ItemName = "";

        /// <summary>
        /// 获取--设置--项目名称
        /// </summary>
        public string T_ItemName
        {
            get { return _t_ItemName; }
            set { _t_ItemName = value; }
        }

        /// <summary>
        /// 项目数值
        /// </summary>
        private string _t_ItemValue = "";

        /// <summary>
        /// 获取--设置--项目数值
        /// </summary>
        public string T_ItemValue
        {
            get { return _t_ItemValue; }
            set { _t_ItemValue = value; }
        }

        /// <summary>
        /// X轴刻度
        /// </summary>
        private string _t_XScale = "";

        /// <summary>
        /// 获取--设置--X轴刻度
        /// </summary>
        public string T_XScale
        {
            get { return _t_XScale; }
            set { _t_XScale = value; }
        }


        #endregion

        #region 图表属性

        /// <summary>
        /// 图表名称ID
        /// </summary>
        private string _name = "";

        /// <summary>
        /// 获取--设置--图表名称ID
        /// </summary>
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }

        /// <summary>
        /// 图表类型
        /// </summary>
        private EChartType _chartType = EChartType.Curve;

        /// <summary>
        /// 获取--设置--图表类型
        /// 默认:Line 折曲线
        /// </summary>
        public EChartType ChartType
        {
            get { return _chartType; }
            set { _chartType = value; }
        }

        /// <summary>
        /// 图表宽度
        /// </summary>
        private int _chartWidth = 0;

        /// <summary>
        /// 获取--设置--图表宽度
        /// </summary>
        public int ChartWidth
        {
            get { return _chartWidth; }
            set { _chartWidth = value; }
        }

        /// <summary>
        /// 图表高度
        /// </summary>
        private int _chartHeight = 0;

        /// <summary>
        /// 获取--设置--图表高度
        /// </summary>
        public int ChartHeight
        {
            get { return _chartHeight; }
            set { _chartHeight = value; }
        }

        /// <summary>
        /// 图表背景颜色
        /// </summary>
        private Color _backColor = Color.White;

        /// <summary>
        /// 获取--设置--图表背景颜色
        /// </summary>
        public Color BackColor
        {
            get { return _backColor; }
            set { _backColor = value; }
        }

        /// <summary>
        /// 是否显示图表边框
        /// </summary>
        private bool _showBorder = true;

        /// <summary>
        /// 获取--设置--是否显示图表边框
        /// 默认:true 显示
        /// </summary>
        public bool ShowBorder
        {
            get { return _showBorder; }
            set { _showBorder = value; }
        }

        /// <summary>
        /// 图表边框颜色
        /// </summary>
        private Color _borderColor = Color.LightGray;

        /// <summary>
        /// 获取--设置--图表边框颜色
        /// </summary>
        public Color BorderColor
        {
            get { return _borderColor; }
            set { _borderColor = value; }
        }

        /// <summary>
        /// 是否显示网格线
        /// </summary>
        private bool _showGrid = true;

        /// <summary>
        /// 获取--设置--是否显示网格线
        /// 默认:true 显示
        /// </summary>
        public bool ShowGrid
        {
            get { return _showGrid; }
            set { _showGrid = value; }
        }

        /// <summary>
        /// 线条张力系数
        /// </summary>
        private float _lineTension = 0.3f;

        /// <summary>
        /// 获取--设置--线条张力系数
        /// 默认:0.3
        /// </summary>
        public float LineTension
        {
            get { return _lineTension; }
            set
            {
                if (value < 0.0f && value > 1.0f)
                    _lineTension = 0.5f;
                else
                    _lineTension = value;
            }
        }

        #endregion

        #region 标题属性

        /// <summary>
        /// 是否显示主标题
        /// </summary>
        private bool _showTitle = true;

        /// <summary>
        /// 获取--设置--是否显示主标题
        /// 默认:true 显示
        /// </summary>
        public bool ShowTitle
        {
            get { return _showTitle; }
            set { _showTitle = value; }
        }

        /// <summary>
        /// 主标题文本
        /// </summary>
        private string _title = "";

        /// <summary>
        /// 获取--设置--主标题文本
        /// </summary>
        public string Title
        {
            get { return _title; }
            set { _title = value; }
        }

        /// <summary>
        /// 主标题字体
        /// </summary>
        private Font _titleFont = new Font("黑体", 12);

        /// <summary>
        /// 获取--设置--主标题字体
        /// </summary>
        public Font TitleFont
        {
            get { return _titleFont; }
            set { _titleFont = value; }
        }

        /// <summary>
        /// 主标题颜色
        /// </summary>
        private Color _titleColor = Color.Black;

        /// <summary>
        /// 获取--设置--主标题颜色
        /// </summary>
        public Color TitleColor
        {
            get { return _titleColor; }
            set { _titleColor = value; }
        }

        /// <summary>
        /// 主标题对齐方式
        /// </summary>
        private EAlign _titleAlign = EAlign.center;

        /// <summary>
        /// 获取--设置--主标题对齐方式
        /// </summary>
        public EAlign TitleAlign
        {
            get { return _titleAlign; }
            set { _titleAlign = value; }
        }

        /// <summary>
        /// 是否显示副标题
        /// </summary>
        private bool _showSubTilte = true;

        /// <summary>
        /// 获取--设置--是否显示副标题
        /// 默认:true 显示
        /// </summary>
        public bool ShowSubTitle
        {
            get { return _showSubTilte; }
            set { _showSubTilte = value; }
        }

        /// <summary>
        /// 副标题文本
        /// </summary>
        private string _subTitle = "";

        /// <summary>
        /// 获取--设置--副标题文本
        /// </summary>
        public string SubTitle
        {
            get { return _subTitle; }
            set { _subTitle = value; }
        }

        /// <summary>
        /// 副标题字体
        /// </summary>
        private Font _subTitleFont = new Font("黑体", 10);

        /// <summary>
        /// 获取--设置--副标题字体
        /// </summary>
        public Font SubTitleFont
        {
            get { return _subTitleFont; }
            set { _subTitleFont = value; }
        }

        /// <summary>
        /// 副标题颜色
        /// </summary>
        private Color _subTitleColor = Color.Blue;

        /// <summary>
        /// 获取--设置--副标题颜色
        /// </summary>
        public Color SubTitleColor
        {
            get { return _subTitleColor; }
            set { _subTitleColor = value; }
        }

        /// <summary>
        /// 副标题对齐方式
        /// </summary>
        private EAlign _subTitleAlign = EAlign.center;

        /// <summary>
        /// 获取--设置--副标题对齐方式
        /// </summary>
        public EAlign SubTitleAlign
        {
            get { return _subTitleAlign; }
            set { _subTitleAlign = value; }
        }

        /// <summary>
        /// 副标题水平方向偏移量
        /// + - 整数
        /// </summary>
        private int _subTitleOffset = 0;

        /// <summary>
        /// 获取--设置--副标题水平方向偏移量
        /// </summary>
        public int SubTitleOffset
        {
            get { return _subTitleOffset; }
            set { _subTitleOffset = value; }
        }

        #endregion

        #region 图例属性

        /// <summary>
        /// 是否显示图例
        /// </summary>
        private bool _showLegend = true;

        /// <summary>
        /// 是否显示图例
        /// </summary>
        public bool ShowLegend
        {
            get { return _showLegend; }
            set { _showLegend = value; }
        }

        /// <summary>
        /// 图例字体
        /// </summary>
        private Font _legendFont = new Font("宋体", 9);

        /// <summary>
        /// 获取--设置--图例字体
        /// </summary>
        public Font LegendFont
        {
            get { return _legendFont; }
            set { _legendFont = value; }
        }

        /// <summary>
        /// 图例字体颜色
        /// </summary>
        private Color _legendColor = Color.Black;

        /// <summary>
        /// 获取--设置--图例字体颜色
        /// </summary>
        public Color LegendColor
        {
            get { return _legendColor; }
            set { _legendColor = value; }
        }

        /// <summary>
        /// 图例对齐方式
        /// </summary>
        private EAlign _legendAlign = EAlign.center;

        /// <summary>
        /// 获取--设置--图例对齐方式
        /// </summary>
        public EAlign LegendAlign
        {
            get { return _legendAlign; }
            set { _legendAlign = value; }
        }

        #endregion

        #region 坐标属性

        /// <summary>
        /// 获取--X轴分割段数
        /// </summary>
        public int XSplitNum
        {
            get { return _xScaleValues.Count; }
        }

        /// <summary>
        /// Y轴分割段数
        /// </summary>
        private int _ySplitNum = 5;

        /// <summary>
        /// 获取--设置--分割段数
        /// 默认:5
        /// 范围:最小5
        /// </summary>
        public int YSplitNum
        {
            get { return _ySplitNum; }
            set
            {
                if (value < 5)
                    _ySplitNum = 5;
                else
                    _ySplitNum = value;

            }
        }

        /// <summary>
        /// X 轴标
        /// </summary>
        private string _xAxisText = "";

        /// <summary>
        /// 获取--设置--X 轴标
        /// </summary>
        public string XAxisText
        {
            get { return _xAxisText; }
            set { _xAxisText = value; }
        }

        /// <summary>
        /// Y 轴标
        /// </summary>
        private string _yAxisText = "";

        /// <summary>
        /// 获取--设置--Y 轴标
        /// </summary>
        public string YAxisText
        {
            get { return _yAxisText; }
            set { _yAxisText = value; }
        }

        /// <summary>
        /// X轴文本旋转角度
        /// 默认:0
        /// 范围:0~90
        /// </summary>
        private float _xRotateAngle = 0.0f;

        /// <summary>
        /// 获取--设置--X轴文本旋转角度
        /// </summary>
        public float XRotateAngle
        {
            get { return _xRotateAngle; }
            set
            {
                if (value >= 0.0f && value <= 90.0f)
                    _xRotateAngle = value;
                else
                    _xRotateAngle = 0.0f;
            }
        }

        #endregion

        #region 绘图变量

        /// <summary>
        /// 绘图对象
        /// </summary>
        private Graphics g = null;

        /// <summary>
        /// 图表颜色数组
        /// </summary>
        private static Color[] ChartColor = {
                                                 Color.Red, Color.Blue, Color.Orange, Color.Green, Color.Cyan, Color.Purple,
                                                 Color.Coral, Color.Chocolate, Color.Gray, Color.Gold, Color.Lavender, Color.Linen,
                                                 Color.Magenta, Color.Moccasin, Color.Navy, Color.Olive, Color.Peru, Color.Plum,
                                                 Color.Purple, Color.Salmon, Color.Sienna, Color.Silver, Color.Tan, Color.Tomato,
                                                 Color.Violet, Color.Turquoise, Color.Transparent
                                             };

        /// <summary>
        /// 边距10px
        /// </summary>
        private float Margin = 10;

        /// <summary>
        /// 起点 X 坐标
        /// </summary>
        private float Start_X = 0;

        /// <summary>
        /// 起点 Y 坐标
        /// </summary>
        private float Start_Y = 0;

        /// <summary>
        /// 终点 X 坐标
        /// </summary>
        private float End_X = 0;

        /// <summary>
        /// 终点 Y 坐标
        /// </summary>
        private float End_Y = 0;

        /// <summary>
        /// X轴刻度宽度
        /// </summary>
        private float XScaleWidth = 0;

        /// <summary>
        /// Y轴刻度宽度
        /// </summary>
        private float YScaleWidth = 0;

        /// <summary>
        /// Y轴刻度间隔值
        /// 说明:Y轴坐标全部采用整数,表示每个间隔的计算单位值
        /// 包含正负数
        /// </summary>
        private double YScale_SplitValue = 0;

        /// <summary>
        /// Y轴刻度开始值
        /// </summary>
        private double YScale_StartValue = 0;

        /// <summary>
        /// 坐标轴原点坐标
        /// </summary>
        private PointF AxisZeroPt = new PointF(0f, 0f);

        /// <summary>
        /// 图表数据
        /// </summary>
        private string _chartData = "";

        /// <summary>
        /// 获取--设置--图表数据
        /// </summary>
        public string ChartData
        {
            get { return _chartData; }
            set { _chartData = value; }
        }

        /// <summary>
        /// 绘图笔刷
        /// </summary>
        private Brush brush;

        /// <summary>
        /// 绘制画笔
        /// </summary>
        private Pen pen;

        /// <summary>
        /// 绘图矩形
        /// </summary>
        private RectangleF rectF = new RectangleF(0, 0, 0, 0);

        /// <summary>
        /// 字符格式化
        /// </summary>
        private StringFormat stringFormat;

        /// <summary>
        /// 临时变量 最大值
        /// </summary>
        private double myMaxValue = 0;

        /// <summary>
        /// 临时变量 最小值
        /// </summary>
        private double myMinValue = 0;

        /// <summary>
        /// 临时变量 X轴刻度最大高度
        /// 用于绘制坐标轴的时候进行偏移
        /// </summary>
        private float myXScaleMaxHeight = 0;

        /// <summary>
        /// 临时变量 Y轴刻度值字符串的最大宽度
        /// 用于绘制坐标轴的时候进行偏移
        /// </summary>
        private float myYScaleMaxWidth = 0;

        #endregion

        #region 图表数据

        /// <summary>
        /// X轴刻度值数组
        /// </summary>
        private List<string> _xScaleValues = new List<string>();

        /// <summary>
        /// 获取--设置--X轴刻度值数组
        /// </summary>
        public List<string> XScaleValues
        {
            get { return _xScaleValues; }
            set { _xScaleValues = value; }
        }

        /// <summary>
        /// 图表数据
        /// </summary>
        private List<EChartData> _chartDataArray = new List<EChartData>();

        /// <summary>
        /// 获取--设置--图表数据
        /// </summary>
        public List<EChartData> ChartDataArray
        {
            get { return _chartDataArray; }
            set { _chartDataArray = value; }
        }

        #endregion

        #endregion

        #region 构造方法

        /// <summary>
        /// 构造函数
        /// </summary>
        public EChart()
        {

        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="eChart"></param>
        public EChart(EChart eChart)
        {

        }

        #endregion

        #region 生成图表

        /// <summary>
        /// 生成图表
        /// </summary>
        /// <returns>返回:图表图像</returns>
        public Bitmap CreateImage()
        {
            Bitmap ChartImage = new Bitmap(ChartWidth, ChartHeight);
            g = Graphics.FromImage(ChartImage);
            g.SmoothingMode = SmoothingMode.Default;
            g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
            g.Clear(Color.White);

            Start_X = Margin;
            Start_Y = Margin;
            End_X = ChartWidth - Margin;
            End_Y = ChartHeight - Margin;

            DrawChart();

            g.Dispose();

            return ChartImage;
        }

        #endregion

        #region 绘制方法

        /// <summary>
        /// 绘制图表
        /// </summary>
        private void DrawChart()
        {
            DrawChart_InitGraph();
            DrawChart_MainTitle();
            DrawChart_SubTitle();
            DrawChart_Legend();
            DrawChart_YAxisText();
            if (ChartType != EChartType.Pie)
            {
                DrawChart_Axis();
                if (ChartType == EChartType.Curve)
                    DrawChart_Curve();
                else
                    DrawChart_Bar();
            }
            else
            {
                DrawChart_Pie();
            }
        }

        /// <summary>
        /// 绘制图表--绘制背景图
        /// </summary>
        private void DrawChart_InitGraph()
        {
            // 绘制图表外围边框
            if (_showBorder)
                g.DrawRectangle(new Pen(BorderColor, 1), 0, 0, (ChartWidth - 1), (ChartHeight - 1));

            // 填充图表背景颜色
            g.FillRectangle(new SolidBrush(BackColor), 1, 1, ChartWidth - 2, ChartHeight - 2);

        }

        /// <summary>
        /// 绘制图表--绘制主标题
        /// </summary>
        private void DrawChart_MainTitle()
        {
            if (ShowTitle)
            {
                if (Title != null && Title.Trim() != "")
                {
                    brush = new SolidBrush(TitleColor);                     // 矩形填充笔刷
                    SizeF sizeF = g.MeasureString(Title, TitleFont);        // 测试字体大小
                    stringFormat = new StringFormat();                      // 格式化字符串
                    stringFormat.LineAlignment = StringAlignment.Center;    // 垂直对齐方式
                    switch (TitleAlign)                                     // 水平对齐方式
                    {
                        case EAlign.center:
                            stringFormat.Alignment = StringAlignment.Center;
                            break;
                        case EAlign.right:
                            stringFormat.Alignment = StringAlignment.Far;
                            break;
                        default:
                            stringFormat.Alignment = StringAlignment.Near;
                            break;
                    }

                    rectF = new RectangleF(Start_X, Start_Y, (float)(ChartWidth - 4), sizeF.Height);  // 文字的矩形
                    g.DrawString(Title, TitleFont, brush, rectF, stringFormat);                       // 绘制主标题
                    Start_Y += sizeF.Height + 3f;                                                     // 设置Y起点值 + 3px
                }
            }
        }

        /// <summary>
        /// 绘制图表--绘制副标题
        /// </summary>
        private void DrawChart_SubTitle()
        {
            if (ShowSubTitle)
            {
                if (SubTitle != null && SubTitle.Trim() != "")
                {
                    brush = new SolidBrush(SubTitleColor);                  // 矩形填充笔刷
                    SizeF sizeF = g.MeasureString(SubTitle, SubTitleFont);  // 测试字体大小
                    stringFormat = new StringFormat();                      // 格式化字符串
                    stringFormat.LineAlignment = StringAlignment.Center;    // 垂直对齐方式
                    switch (SubTitleAlign)                                  // 水平对齐方式
                    {
                        case EAlign.center:
                            stringFormat.Alignment = StringAlignment.Center;
                            break;
                        case EAlign.right:
                            stringFormat.Alignment = StringAlignment.Far;
                            break;
                        default:
                            stringFormat.Alignment = StringAlignment.Near;
                            break;
                    }

                    rectF = new RectangleF(Start_X + (float)SubTitleOffset, Start_Y, (float)(ChartWidth - 4), sizeF.Height);  // 文字的矩形
                    g.DrawString(SubTitle, SubTitleFont, brush, rectF, stringFormat);                                               // 绘制副标题
                    Start_Y += sizeF.Height + 3f;                                                                             // 设置Y起点值 + 3px
                }
            }

        }

        /// <summary>
        /// 绘制图表--绘制图例
        /// </summary>
        private void DrawChart_Legend()
        {
            // 计算项目颜色
            int tmIndex = 0;
            for (int m = 0; m < ChartDataArray.Count; m++)
            {
                tmIndex = m % ChartColor.Length;
                ChartDataArray[m].ItemColor = ChartColor[tmIndex];
            }

            // 图例的高度最大40px 3排
            if (ShowLegend)
            {
                // 计算文字大小
                int LegendCount = ChartDataArray.Count;
                Font tFont = new Font("宋体", 9);
                for (int t = 0; t < LegendCount; t++)
                {
                    SizeF tmSize = new SizeF();
                    tmSize = g.MeasureString(ChartDataArray[t].Name, tFont);
                    ChartDataArray[t].NameSize = tmSize;
                }

                #region 绘制一排图例

                // 首先判定一行够不够
                float largMax = 0;
                for (int t = 0; t < LegendCount; t++)
                {
                    if (t == 0)
                        largMax += ChartDataArray[t].NameSize.Width;
                    else
                        largMax += (35f + ChartDataArray[t].NameSize.Width);
                }

                if (largMax <= End_X - Start_X) // 图例只需一排
                {
                    End_Y -= 12.0f;
                    float tmX = (End_X - Start_X - largMax) / 2 + Start_X;
                    float tmY = End_Y;
                    for (int n = 0; n < LegendCount; n++)
                    {
                        g.FillRectangle(new SolidBrush(ChartDataArray[n].ItemColor), tmX, tmY + 1, 15, 10);
                        tmX += 20;
                        g.DrawString(ChartDataArray[n].Name, new Font("宋体", 9), new SolidBrush(Color.Black), tmX, tmY);
                        tmX += 15 + ChartDataArray[n].NameSize.Width;
                    }
                }

                #endregion

                #region 绘制多排图例

                // 图例最多绘制三排
                else
                {

                    bool TwoLine = true;                     // 是否两行:true 是; false: 否,为三行

                    // 判定两排还是三排
                    float tmBX = Start_X - 5;
                    int tmBC = (int)Math.Ceiling((double)LegendCount / 2);
                    for (int T = 0; T < tmBC; T++)
                    {
                        float tmBW1 = -1F, tmBW2 = -1F, tmBM = 0F;
                        tmBW1 = ChartDataArray[T * 2].NameSize.Width;
                        if (ChartDataArray.Count > (T * 2 + 1))
                            tmBW2 = ChartDataArray[T * 2 + 1].NameSize.Width;
                        tmBM = tmBW1 > tmBW2 ? tmBW1 : tmBW2;
                        tmBX += 35 + tmBM;
                        if (tmBX > (End_X + 5))
                        {
                            TwoLine = false;
                            break;
                        }
                    }

                    // 绘制两排图例
                    if (TwoLine)
                    {
                        End_Y -= 24.0f;
                        float tmTX = (End_X + 10 - tmBX + Start_X + 5) / 2;       // 开始位置保持两排水平居中
                        float tmTY = End_Y;
                        int tmTM = (int)Math.Ceiling((double)LegendCount / 2);

                        // 绘制两排图例
                        for (int T = 0; T < tmTM; T++)
                        {
                            float tmTW1 = -1F, tmTW2 = -1F, tmTW3 = 0F;
                            tmTW1 = ChartDataArray[T * 2].NameSize.Width;
                            if (ChartDataArray.Count > (T * 2 + 1))
                                tmTW2 = ChartDataArray[T * 2 + 1].NameSize.Width;
                            tmTW3 = tmTW1 > tmTW2 ? tmTW1 : tmTW2;

                            // 绘制第一排图例
                            g.FillRectangle(new SolidBrush(ChartDataArray[T * 2].ItemColor), tmTX, tmTY + 1, 15, 10);
                            g.DrawString(ChartDataArray[T * 2].Name, new Font("宋体", 9), new SolidBrush(Color.Black), (tmTX + 20), tmTY);

                            // 绘制第二排图例
                            if (tmTW2 > 0)
                            {
                                g.FillRectangle(new SolidBrush(ChartDataArray[T * 2 + 1].ItemColor), tmTX, (tmTY + 16 + 1), 15, 10);
                                g.DrawString(ChartDataArray[T * 2 + 1].Name, new Font("宋体", 9), new SolidBrush(Color.Black), (tmTX + 20), (tmTY + 16));
                            }
                            tmTX += 35 + tmTW3;
                        }
                    }

                    // 绘制三排图例
                    else
                    {
                        End_Y -= 40.0f;
                        // 如果三排还不够,那么就不管了,绘制超出范围就超出范围
                        float tmSX = Start_X - 5;
                        float tmSY = End_Y;
                        int tmSC = (int)Math.Ceiling((double)LegendCount / 3);
                        bool CanFlag = true;  // 三排是否足够

                        // 首先计算三排的能排下的居中位置
                        for (int n = 0; n < tmSC; n++)
                        {
                            float tmSW1 = -1F, tmSW2 = -1F, tmSW3 = -1F, tmSW4 = 0F;
                            tmSW1 = ChartDataArray[n * 3].NameSize.Width;
                            if (ChartDataArray.Count > (n * 3 + 1))
                                tmSW2 = ChartDataArray[n * 3 + 1].NameSize.Width;
                            if (ChartDataArray.Count > (n * 3 + 2))
                                tmSW3 = ChartDataArray[n * 3 + 2].NameSize.Width;
                            tmSW4 = tmSW1 > tmSW2 ? tmSW1 : tmSW2;
                            tmSW4 = tmSW4 > tmSW3 ? tmSW4 : tmSW3;
                            tmSX += 35 + tmSW4;
                            if (tmSX > (End_X + 5))
                            {
                                CanFlag = false;
                                break;
                            }
                        }

                        // 再次执行三排绘制
                        if (CanFlag)             // 三排足够,则设置居中开始位置
                            tmSX = (End_X + 10 - tmSX + Start_X + 5) / 2;
                        else
                            tmSX = Start_X - 5;  // 三排排不下的情况就从5px 开始

                        for (int n = 0; n < tmSC; n++)
                        {
                            float tmSW1 = -1F, tmSW2 = -1F, tmSW3 = -1F, tmSW4 = 0F;
                            tmSW1 = ChartDataArray[n * 3].NameSize.Width;
                            if (ChartDataArray.Count > (n * 3 + 1))
                                tmSW2 = ChartDataArray[n * 3 + 1].NameSize.Width;
                            if (ChartDataArray.Count > (n * 3 + 2))
                                tmSW3 = ChartDataArray[n * 3 + 2].NameSize.Width;
                            tmSW4 = tmSW1 > tmSW2 ? tmSW1 : tmSW2;
                            tmSW4 = tmSW4 > tmSW3 ? tmSW4 : tmSW3;

                            // 绘制第一排图例
                            g.FillRectangle(new SolidBrush(ChartDataArray[n * 3].ItemColor), tmSX, (tmSY + 1), 15, 10);
                            g.DrawString(ChartDataArray[n * 3].Name, new Font("宋体", 9), new SolidBrush(Color.Black), (tmSX + 20), tmSY);

                            // 绘制第二排图例
                            if (tmSW2 > 0)
                            {
                                g.FillRectangle(new SolidBrush(ChartDataArray[n * 3 + 1].ItemColor), tmSX, (tmSY + 16 + 1), 15, 10);
                                g.DrawString(ChartDataArray[n * 3 + 1].Name, new Font("宋体", 9), new SolidBrush(Color.Black), (tmSX + 20), (tmSY + 16));
                            }

                            // 绘制第三排图例
                            if (tmSW3 > 0)
                            {
                                g.FillRectangle(new SolidBrush(ChartDataArray[n * 3 + 2].ItemColor), tmSX, (tmSY + 32 + 1), 15, 10);
                                g.DrawString(ChartDataArray[n * 3 + 2].Name, new Font("宋体", 9), new SolidBrush(Color.Black), (tmSX + 20), (tmSY + 32));
                            }

                            tmSX += 35 + tmSW4;
                        }
                    }
                }

                #endregion
            }
        }

        /// <summary>
        /// 绘制图表--绘制X轴标
        /// </summary>
        /// <param name="g"></param>
        private void DrawChart_XAxisText()
        {
            // X轴标就不绘制了,因为空间不够,所以不执行X轴标的绘制
        }

        /// <summary>
        /// 绘制图表--绘制Y轴标
        /// </summary>
        private void DrawChart_YAxisText()
        {
            if (ChartType != EChartType.Pie)
            {
                if (YAxisText != null && YAxisText.Trim() != "")
                {
                    brush = new SolidBrush(Color.Gray);
                    stringFormat = new StringFormat();                                    // 格式化字符串
                    stringFormat.LineAlignment = StringAlignment.Near;                    // 垂直对齐方式
                    stringFormat.Alignment = StringAlignment.Near;                        // 水平对齐方式
                    SizeF sizeF = g.MeasureString(YAxisText, new Font("宋体", 9));        // 测量文字大小
                    rectF = new RectangleF(Start_X, Start_Y, sizeF.Width, sizeF.Height);  // 文字外围矩形
                    g.TranslateTransform((Start_X - Start_Y), (Start_X + Start_Y + sizeF.Width));    // 设置位置移动 X,Y
                    g.RotateTransform(270);                                                          // 旋转270度  以左上角作为旋转原点
                    g.DrawString(YAxisText, new Font("宋体", 9), brush, rectF, stringFormat);
                    g.ResetTransform();

                    Start_X += sizeF.Height + 2;                                          // 加2个像素
                }
            }
        }

        /// <summary>
        /// 绘制图表--绘制坐标轴
        /// </summary>
        private void DrawChart_Axis()
        {
            // 1、图表区下移10PX
            Start_Y += 10;

            // 2、计算坐标轴参数
            Calc_XScaleHeight();
            Calc_YScaleValue();

            // 3、计算原点坐标值
            AxisZeroPt = new PointF(0f, 0f); // 坐标轴原点坐标
            AxisZeroPt.X = Start_X + myYScaleMaxWidth;
            AxisZeroPt.Y = End_Y - myXScaleMaxHeight;

            // 3.1、绘制坐标轴
            Pen pen2 = new Pen(Color.FromKnownColor(KnownColor.ControlDark), 2f);
            g.DrawLine(pen2, (Start_X + myYScaleMaxWidth - 4f), (End_Y - myXScaleMaxHeight), End_X + 2, (End_Y - myXScaleMaxHeight));     // 绘制 X坐标轴
            g.DrawLine(pen2, (Start_X + myYScaleMaxWidth), (End_Y - myXScaleMaxHeight + 4f), (Start_X + myYScaleMaxWidth), Start_Y - 2);  // 绘制 Y坐标轴

            // 3.2、计算分段宽
            XScaleWidth = (End_X - Start_X - myYScaleMaxWidth) / XSplitNum;      // 计算X轴分段宽
            YScaleWidth = (End_Y - Start_Y - myXScaleMaxHeight) / YSplitNum;     // 计算Y轴分段宽

            // 3.3、绘制刻度值
            pen = new Pen(Color.LightGray, 1f);
            pen.DashStyle = DashStyle.Dash;
            for (int k = 0; k < XSplitNum; k++)    // 绘制X轴刻度线 刻度值
            {
                // 绘制X轴刻度线
                g.DrawLine(pen2, (AxisZeroPt.X + XScaleWidth * (k + 1)), AxisZeroPt.Y, (AxisZeroPt.X + XScaleWidth * (k + 1)), AxisZeroPt.Y + 4f);

                // 绘制X轴刻度值
                g.TranslateTransform(AxisZeroPt.X + XScaleWidth * k + 15f * XRotateAngle / 90 + 4f, AxisZeroPt.Y + 4f);  // 平移原点
                g.RotateTransform(XRotateAngle, MatrixOrder.Prepend);                                                    // 旋转图像
                g.DrawString(XScaleValues[k], new Font("宋体", 9f), new SolidBrush(Color.Black), 0, 0);                  // 绘制字符
                g.ResetTransform();
            }

            for (int k = 0; k < YSplitNum; k++)
            {
                // 绘制Y轴刻度线
                g.DrawLine(pen2, AxisZeroPt.X - 4, (AxisZeroPt.Y - YScaleWidth * (k + 1)), AxisZeroPt.X, (AxisZeroPt.Y - YScaleWidth * (k + 1)));

                // 绘制Y轴刻度值
                string tmYvalue = (YScale_StartValue + k * YScale_SplitValue).ToString();
                SizeF tmF = g.MeasureString(tmYvalue, new Font("宋体", 9));
                g.DrawString(tmYvalue, new Font("宋体", 9), new SolidBrush(Color.Black), (AxisZeroPt.X - tmF.Width - 4), (AxisZeroPt.Y - YScaleWidth * k - tmF.Height / 2 + 1));

                if (k == YSplitNum - 1)
                {
                    tmYvalue = (YScale_StartValue + (k + 1) * YScale_SplitValue).ToString();
                    tmF = g.MeasureString(tmYvalue, new Font("宋体", 9));
                    g.DrawString(tmYvalue, new Font("宋体", 9), new SolidBrush(Color.Black), (AxisZeroPt.X - tmF.Width - 4), (AxisZeroPt.Y - YScaleWidth * (k + 1) - tmF.Height / 2 + 1));
                }
            }


            // 3.4、绘制网格线
            if (ShowGrid)
            {
                for (int k = 1; k <= YSplitNum; k++)  // 绘制X轴平行横向辅助线
                    g.DrawLine(pen, AxisZeroPt.X + 1, (AxisZeroPt.Y - YScaleWidth * k), End_X, (AxisZeroPt.Y - YScaleWidth * k));

                for (int k = 1; k <= XSplitNum; k++)  // 绘制Y轴平行纵向辅助线
                    g.DrawLine(pen, (AxisZeroPt.X + XScaleWidth * k), Start_Y, (AxisZeroPt.X + XScaleWidth * k), AxisZeroPt.Y - 1);
            }

            pen2.Dispose();
        }

        /// <summary>
        /// 绘制曲线图
        /// </summary>
        private void DrawChart_Curve()
        {
            g.SmoothingMode = SmoothingMode.HighQuality;
            g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
            g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half;

            int tmLength = 0;
            PointF[] CurvePointF = new PointF[tmLength];
            foreach (EChartData iItem in this.ChartDataArray)
            {
                tmLength = iItem.Values.Count;
                CurvePointF = new PointF[tmLength];
                pen = new Pen(iItem.ItemColor, 2.0f);
                for (int rr = 0; rr < iItem.Values.Count; rr++)
                {
                    double dbValue = iItem.Values[rr];
                    CurvePointF[rr].X = AxisZeroPt.X + XScaleWidth * rr + XScaleWidth / 2;
                    CurvePointF[rr].Y = AxisZeroPt.Y - (float)((dbValue - YScale_StartValue) / YScale_SplitValue) * YScaleWidth;
                }

                // 绘制曲线
                g.DrawCurve(pen, CurvePointF, LineTension);

                // 绘制辅点
                for (int tt = 0; tt < CurvePointF.Length; tt++)
                {
                    // 点标数据值
                    string tmValStr = iItem.Values[tt].ToString();

                    // 绘制数据点
                    g.FillEllipse(new SolidBrush(iItem.ItemColor), CurvePointF[tt].X - 3, CurvePointF[tt].Y - 3, 6, 6);

                    // 绘制数据值
                    SizeF tmValueSize = g.MeasureString(tmValStr, new Font("Arial", 9));
                    g.DrawString(tmValStr, new Font("Arial", 9), new SolidBrush(iItem.ItemColor), (CurvePointF[tt].X - tmValueSize.Width / 2), (CurvePointF[tt].Y - tmValueSize.Height - 2f));
                }
            }
        }

        /// <summary>
        /// 绘制柱状图
        /// </summary>
        private void DrawChart_Bar()
        {
            g.SmoothingMode = SmoothingMode.HighQuality;
            int tmLen = ChartDataArray.Count;                       // 柱形条目总数
            float tmBarWidth = XScaleWidth / (tmLen * 2 + 1);    // 每条柱形宽度 平均分配
            if (tmBarWidth < 2)
            {
                tmBarWidth = 2f;
            }

            for (int kk = 0; kk < this.ChartDataArray.Count; kk++)
            {
                EChartData iItem = this.ChartDataArray[kk];
                pen = new Pen(Color.FromKnownColor(KnownColor.ControlDark), 1.0f);
                for (int rr = 0; rr < iItem.Values.Count; rr++)
                {
                    RectangleF barRect = new RectangleF(0, 0, 0, 0);
                    double dbValue = iItem.Values[rr];
                    barRect.X = AxisZeroPt.X + XScaleWidth * rr + (tmBarWidth * ((kk + 1) * 2 - 1));
                    barRect.Y = AxisZeroPt.Y - (float)((dbValue - YScale_StartValue) / YScale_SplitValue) * YScaleWidth;
                    barRect.Width = tmBarWidth;
                    barRect.Height = AxisZeroPt.Y - barRect.Y;

                    // 绘制柱形
                    g.DrawRectangle(pen, barRect.X, barRect.Y, barRect.Width, barRect.Height);

                    brush = new SolidBrush(iItem.ItemColor);
                    g.FillRectangle(brush, barRect.X + 1, barRect.Y + 1, barRect.Width - 2, barRect.Height - 2);

                    // 绘制数据
                    SizeF tmValueSize = g.MeasureString(dbValue.ToString(), new Font("Arial", 9));
                    g.DrawString(dbValue.ToString(), new Font("Arial", 9), new SolidBrush(iItem.ItemColor), (barRect.X + tmBarWidth / 2 - tmValueSize.Width / 2), (barRect.Y - tmValueSize.Height - 2f));
                }
            }
        }

        /// <summary>
        /// 绘制图表--绘制饼状图
        /// </summary>
        private void DrawChart_Pie()
        {
            // 上下预留20 PX 为了标记饼图的数据值        
            Start_Y += 20;
            End_Y -= 20;

            g.SmoothingMode = SmoothingMode.HighQuality;
            g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
            g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half;

            // 矩形坐标点
            PointF piePoint = new PointF(0, 0);
            float tmPieW = End_X - Start_X;
            float tmPieH = End_Y - Start_Y;
            float tmPieR = tmPieW < tmPieH ? tmPieW / 2 : tmPieH / 2;  // 半径

            piePoint.X = Start_X + tmPieW / 2 - tmPieR;
            piePoint.Y = Start_Y + tmPieH / 2 - tmPieR;

            // 圆心坐标点
            PointF pieZero = new PointF(piePoint.X + tmPieR, piePoint.Y + tmPieR);

            // 绘制外围圆
            pen = new Pen(Color.FromKnownColor(KnownColor.ControlDark), 1.5f);
            g.DrawEllipse(pen, piePoint.X - 5, piePoint.Y - 5, (tmPieR + 5) * 2, (tmPieR + 5) * 2);

            // 计算总数
            double pieCountValue = 0;
            foreach (EChartData iItem in this.ChartDataArray)
            {
                if (iItem.Values.Count >= 1)
                    pieCountValue += iItem.Values[0];
            }

            // 绘制扇形
            if (pieCountValue > 0)
            {
                float curAngle = 0; // 占比角度
                float sumAngle = 0; // 总角度和

                foreach (EChartData iItem in this.ChartDataArray)
                {
                    if (iItem.Values.Count >= 1)
                        curAngle = (float)(iItem.Values[0] / pieCountValue * 360);
                    else
                        curAngle = 0;

                    // 填充笔刷
                    brush = new SolidBrush(iItem.ItemColor);

                    // 绘制弧形
                    g.FillPie(brush, piePoint.X, piePoint.Y, tmPieR * 2, tmPieR * 2, sumAngle, curAngle);

                    // 绘制弧线
                    g.DrawPie(pen, piePoint.X, piePoint.Y, tmPieR * 2, tmPieR * 2, sumAngle, curAngle);

                    // 绘制数据
                    float tmPre = (float)Math.Round((iItem.Values[0] / pieCountValue) * 100, 2);
                    string tmStr = tmPre.ToString() + "%" + " [" + iItem.Values[0].ToString() + "]";

                    // 内圆信息
                    double relCur_X = tmPieR * Math.Cos((360 - sumAngle - curAngle / 2) * Math.PI / 180);
                    double relCur_Y = tmPieR * Math.Sin((360 - sumAngle - curAngle / 2) * Math.PI / 180);
                    double cur_X = relCur_X + pieZero.X;
                    double cur_Y = pieZero.Y - relCur_Y;
                    PointF cur_Point = new PointF((float)cur_X, (float)cur_Y);  // 内圆上弧线中间点的坐标

                    // 外圆信息
                    float largerR = tmPieR + 10;
                    double relLarg_X = largerR * Math.Cos((360 - sumAngle - curAngle / 2) * Math.PI / 180);
                    double relLarg_Y = largerR * Math.Sin((360 - sumAngle - curAngle / 2) * Math.PI / 180);
                    double largerX = relLarg_X + pieZero.X;
                    double largerY = pieZero.Y - relLarg_Y;
                    PointF larger_Point = new PointF((float)largerX, (float)largerY);

                    SizeF calcSize = new SizeF(0, 0);

                    // 绘制链接斜线(内圆到外圆弧度中间点的连接线)
                    g.DrawLine(new Pen(new SolidBrush(iItem.ItemColor), 1.5f), cur_Point, larger_Point);                                               // 斜线

                    // 绘制横向线条
                    //*以下是对四个象限、以及对90度、180度、270度和360度的判断*//
                    float tmCurIf = sumAngle + curAngle / 2;
                    if (tmCurIf <= 90)
                    {
                        g.DrawLine(new Pen(new SolidBrush(iItem.ItemColor), 1.5f), larger_Point.X, larger_Point.Y, larger_Point.X + 15f, larger_Point.Y);  // 横线
                        g.DrawString(tmStr, new Font("Arial", 9), new SolidBrush(iItem.ItemColor), larger_Point.X + 15f, larger_Point.Y - 8f);             // 文字
                    }
                    else if (tmCurIf > 90 && tmCurIf <= 180)
                    {
                        calcSize = g.MeasureString(tmStr, new Font("Arial", 9));
                        g.DrawLine(new Pen(new SolidBrush(iItem.ItemColor), 1.5f), larger_Point.X, larger_Point.Y, larger_Point.X - 15f, larger_Point.Y);       // 横线
                        g.DrawString(tmStr, new Font("Arial", 9), new SolidBrush(iItem.ItemColor), larger_Point.X - 15f - calcSize.Width, larger_Point.Y - 8f); // 文字
                    }
                    else if (tmCurIf > 180 && tmCurIf <= 270)
                    {
                        calcSize = g.MeasureString(tmStr, new Font("Arial", 9));
                        g.DrawLine(new Pen(new SolidBrush(iItem.ItemColor), 1.5f), larger_Point.X, larger_Point.Y, larger_Point.X - 15f, larger_Point.Y);       // 横线
                        g.DrawString(tmStr, new Font("Arial", 9), new SolidBrush(iItem.ItemColor), larger_Point.X - 15f - calcSize.Width, larger_Point.Y - 8f); // 文字
                    }
                    else
                    {
                        g.DrawLine(new Pen(new SolidBrush(iItem.ItemColor), 1.5f), larger_Point.X, larger_Point.Y, larger_Point.X + 15f, larger_Point.Y);  // 横线
                        g.DrawString(tmStr, new Font("Arial", 9), new SolidBrush(iItem.ItemColor), larger_Point.X + 15f, larger_Point.Y - 8f);             // 文字
                    }

                    ////*以下是对四个象限、以及对90度、180度、270度和360度的判断*//
                    //if ((sumAngle + curAngle / 2) < 90)
                    //{
                    //    Half = sumAngle + curAngle / 2;
                    //    double tem_sin = Math.Sin(Pi / 180 * Half);
                    //    double tem_cos = Math.Cos(Pi / 180 * Half);

                    //    //Math.PI

                    //    float Px = (float)(tmPieR * tem_cos);
                    //    float Py = (float)(tmPieR * tem_sin);

                    //    g.DrawString(tmStr, new Font("Arial", 9), new SolidBrush(Color.Black), piePoint.X + tmPieR + Px, piePoint.Y + Py);
                    //    //g.DrawString(arraylist_type[i].ToString(), font1, brush1, new Point(225 + x, 225 + y));
                    //    //g.DrawString((Convert.ToInt32(arraylist_tp[i])).ToString() + "%", font1, brush1, new Point(225 + x, 225 + y + 12));
                    //}

                    //else if (tem_angle + Convert.ToSingle(arraylist_angle[i]) / 2 == 90)
                    //{
                    //    g.DrawString(arraylist_type[i].ToString(), font1, brush1, new Point(225, 225 + 125));
                    //    g.DrawString((Convert.ToInt32(arraylist_tp[i])).ToString() + "%", font1, brush1, new Point(225, 225 + 125 + 12));
                    //}

                    //else if (tem_angle + Convert.ToSingle(arraylist_angle[i]) / 2 > 90 && tem_angle + Convert.ToSingle(arraylist_angle[i]) / 2 < 180)
                    //{
                    //    halfangle = (180 - tem_angle - Convert.ToSingle(arraylist_angle[i]) / 2);
                    //    double tem_sin = Math.Sin(T / 180 * halfangle);
                    //    double tem_cos = Math.Cos(T / 180 * halfangle);

                    //    int y = Convert.ToInt32(125 * tem_sin);
                    //    int x = Convert.ToInt32(125 * tem_cos);
                    //    g.DrawString(arraylist_type[i].ToString(), font1, brush1, new Point(225 - x, 225 + y));
                    //    g.DrawString((Convert.ToInt32(arraylist_tp[i])).ToString() + "%", font1, brush1, new Point(225 - x, 225 + y + 12));
                    //}

                    //else if (tem_angle + Convert.ToSingle(arraylist_angle[i]) / 2 == 180)
                    //{
                    //    g.DrawString(arraylist_type[i].ToString(), font1, brush1, new Point(225 - 125, 225));
                    //    g.DrawString((Convert.ToInt32(arraylist_tp[i])).ToString() + "%", font1, brush1, new Point(225 - 125, 225 + 12));
                    //}

                    //else if (tem_angle + Convert.ToSingle(arraylist_angle[i]) / 2 > 180 && tem_angle + Convert.ToSingle(arraylist_angle[i]) / 2 < 270)
                    //{
                    //    halfangle = (tem_angle - 180 + Convert.ToSingle(arraylist_angle[i]) / 2);
                    //    double tem_sin = Math.Sin(T / 180 * halfangle);
                    //    double tem_cos = Math.Cos(T / 180 * halfangle);

                    //    int y = Convert.ToInt32(125 * tem_sin);
                    //    int x = Convert.ToInt32(125 * tem_cos);
                    //    g.DrawString(arraylist_type[i].ToString(), font1, brush1, new Point(225 - x, 225 - y));
                    //    g.DrawString((Convert.ToInt32(arraylist_tp[i])).ToString() + "%", font1, brush1, new Point(225 - x, 225 - y + 12));
                    //}

                    //else if (tem_angle + Convert.ToSingle(arraylist_angle[i]) / 2 == 270)
                    //{
                    //    g.DrawString(arraylist_type[i].ToString(), font1, brush1, new Point(225, 225 - 125));
                    //    g.DrawString((Convert.ToInt32(arraylist_tp[i])).ToString() + "%", font1, brush1, new Point(225, 225 - 125 + 12));
                    //}

                    //else if (tem_angle + Convert.ToSingle(arraylist_angle[i]) / 2 > 270 && tem_angle + Convert.ToSingle(arraylist_angle[i]) / 2 < 360)
                    //{
                    //    halfangle = (360 - tem_angle - Convert.ToSingle(arraylist_angle[i]) / 2);
                    //    double tem_sin = Math.Sin(T / 180 * halfangle);
                    //    double tem_cos = Math.Cos(T / 180 * halfangle);

                    //    int y = Convert.ToInt32(125 * tem_sin);
                    //    int x = Convert.ToInt32(125 * tem_cos);
                    //    g.DrawString(arraylist_type[i].ToString(), font1, brush1, new Point(225 + x, 225 - y));
                    //    g.DrawString((Convert.ToInt32(arraylist_tp[i])).ToString() + "%", font1, brush1, new Point(225 + x, 225 - y + 12));
                    //}

                    //else if (tem_angle + Convert.ToSingle(arraylist_angle[i]) / 2 == 360)
                    //{
                    //    g.DrawString(arraylist_type[i].ToString(), font1, brush1, new Point(225 + 125, 225));
                    //    g.DrawString((Convert.ToInt32(arraylist_tp[i])).ToString() + "%", font1, brush1, new Point(225 + 125, 225 + 12));
                    //}


                    // 累加角度
                    sumAngle += curAngle;

                }

            }
        }

        #endregion

        #region 辅助方法

        /// <summary>
        /// 计算X轴刻度值最大高度
        /// </summary>
        /// <returns></returns>
        private void Calc_XScaleHeight()
        {
            SizeF tmMaxSizeF = new SizeF(0, 0);
            for (int t = 0; t < XScaleValues.Count; t++)
            {
                SizeF tmSizeF = g.MeasureString(XScaleValues[t], new Font("宋体", 9));
                if (tmSizeF.Width > tmMaxSizeF.Width)
                {
                    tmMaxSizeF.Width = tmSizeF.Width;
                    tmMaxSizeF.Height = tmSizeF.Height;
                }
            }
            myXScaleMaxHeight = (((float)Math.Sqrt(tmMaxSizeF.Height * tmMaxSizeF.Height + tmMaxSizeF.Width * tmMaxSizeF.Width) - tmMaxSizeF.Height) * XRotateAngle / 90 + tmMaxSizeF.Height + 13f);
        }

        /// <summary>
        /// 计算坐标Y轴的刻度值
        /// 适用于:曲线图、柱状图
        /// 不适用:饼状图无需计算
        /// </summary>
        private void Calc_YScaleValue()
        {
            myMaxValue = 0; // 原始最大值
            myMinValue = 0; // 原始最小值

            // 计算所有数据的最大值和最小值
            for (int mm = 0; mm < this.ChartDataArray.Count; mm++)
            {
                for (int nn = 0; nn < this.ChartDataArray[mm].Values.Count; nn++)
                {
                    double iData = this.ChartDataArray[mm].Values[nn];
                    if (mm == 0 && nn == 0)
                    {
                        myMaxValue = iData;
                        myMinValue = iData;
                    }
                    else
                    {
                        myMaxValue = iData > myMaxValue ? iData : myMaxValue;
                        myMinValue = iData > myMinValue ? myMinValue : iData;
                    }
                }
            }

            // 计算Y轴刻度
            double tmMax_New = Math.Ceiling(myMaxValue);  // 目标最大值 向上取整
            double tmMin_New = Math.Floor(myMinValue);    // 目标最小值 向下取整
            if (myMinValue == 0)
            {
                YScale_SplitValue = Math.Ceiling(tmMax_New / (double)YSplitNum);                       // 计算Y轴刻度间隔值
                YScale_StartValue = 0;                                                                 // 计算Y轴刻度开始值
            }
            else
            {
                // 计算间隔值
                double tmJD1 = Math.Ceiling((tmMax_New - tmMin_New) / (double)(YSplitNum));
                double tmJD2 = tmJD1 - Math.Ceiling((tmMax_New - tmMin_New) / (double)(YSplitNum + 1));
                if (tmJD1 == 0) tmJD1 = 1;
                YScale_StartValue = tmJD1 * Math.Floor(tmMin_New / tmJD1);  // 计算Y轴刻度开始值
                bool tmJDFlag = true;
                while (tmJDFlag)
                {
                    if (YScale_StartValue <= tmMin_New && (YScale_StartValue + tmJD1 * YSplitNum) >= tmMax_New)
                    {
                        tmJDFlag = false;
                        YScale_SplitValue = tmJD1;                          // 计算Y轴刻度间隔值
                        break;
                    }
                    else
                    {
                        tmJD1 += tmJD2;
                    }
                }
            }

            // 计算Y轴刻度字符串的最大宽度
            SizeF tmYSizeF = g.MeasureString((YScale_StartValue + YScale_SplitValue * YSplitNum).ToString(), new Font("宋体", 9));
            myYScaleMaxWidth = tmYSizeF.Width + 9f;// 预留4个像素
        }

        #endregion

        #region 枚举方法

        /// <summary>
        /// 枚举图表类型
        /// </summary>
        public enum EChartType
        {
            /// <summary>
            /// 曲线图
            /// </summary>
            Curve,

            /// <summary>
            /// 柱状图
            /// </summary>
            Bar,

            /// <summary>
            /// 饼状图
            /// </summary>
            Pie

        }

        /// <summary>
        /// 枚举对齐方式
        /// </summary>
        public enum EAlign
        {

            /// <summary>
            /// 居左
            /// </summary>
            left,

            /// <summary>
            /// 居中
            /// </summary>
            center,

            /// <summary>
            /// 居右
            /// </summary>
            right
        }

        #endregion

    }

    /// <summary>
    /// 图表数据单个项目
    /// </summary>
    public class EChartData
    {
        private string _name;
        private List<double> _values;
        private Color _itemColor;
        private SizeF _nameSize;

        public EChartData()
        {
            _name = "";
            _values = new List<double>();
            _itemColor = Color.White;
            _nameSize = new SizeF(0, 0);
        }

        /// <summary>
        /// 项目名称
        /// </summary>
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }

        /// <summary>
        /// 项目值数组
        /// </summary>
        public List<double> Values
        {
            get { return _values; }
            set { _values = value; }
        }

        /// <summary>
        /// 文字大小
        /// 用户绘制图例时候使用
        /// </summary>
        public SizeF NameSize
        {
            get { return _nameSize; }
            set { _nameSize = value; }
        }

        /// <summary>
        /// 项目颜色
        /// </summary>
        public Color ItemColor
        {
            get { return _itemColor; }
            set { _itemColor = value; }
        }

    }
}

 表报设计DLL控件的源码实在太多,这里就不再一一贴出来了,下载完整的源码自己调试运行查看。
   此报表设计器结合上次的WEB打印控件,就组成了完整的报表设计。
   报表设计器实例完整源码下载地址:http//:www.sdpsoft.com/==》下载中心==》报表设计器简易源码----自定义报表控件(源码)以及在Winform中的使用源码  
   或直接下载地址:winform报表设计工具源码

共有 人打赏支持
粉丝 0
博文 5
码字总数 11081
×
潇洒丶疯一回
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: