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