一、文章引言:近段时间,由于工作的需要,需要以报表和图形的形式对数据进行统计分析,由于手头没有相关的开发组件,于是自己利用GDI+函数进行地层的图形绘制,配合中间层的数据统计及组合,表层嵌入HTML文件中,形成了一整套生成饼状图、柱状图和折线图的应用,现在把设计思路及部分源代码提供出来,和大家相互交流。
二、设计思路:
用户请求 ——》数据采集 ——》逻辑组织——》调用自定义底层函数——》调用.Net GDI+图形函数——》生成JPG文件——》返回指向JPG图形的HTML文件 ——》完成
二、部分代码:
1. 自定义底层图形函数
/// <summary>
/// JpgProxy 的摘要说明。
/// </summary>
public class JpgProxy
{
#region 饼状图
/// <summary>
/// 绘制饼状图
/// </summary>
/// <param name="height">画布高度</param>
/// <param name="width">画布宽度</param>
/// <param name="title">图形标题</param>
/// <param name="partName">图形组成元素名称</param>
/// <param name="partPoint">图形组成元素坐标</param>
/// <param name="partCount">图形组成元素总数</param>
/// <param name="partColor">图形组成元素颜色</param>
/// <param name="imgName">输出图形文件名称</param>
/// <param name="unit">统计单位</param>
/// <param name="bgColor">图形背景颜色</param>
/// <param name="strErr">功能调用返回信息</param>
/// <param name="debug">功能调用测试</param>
/// <returns>功能调用是否成功</returns>
public static bool DrawPie(int height,int width,string title,string[] partName,float[,] partPoint,int[]partCount,Color[] partColor,string imgName,string unit,Color bgColor,out string strErr,bool debug)
{
#region 分离参数
//参数检测
if( partPoint.GetLength(0) != partColor.Length)
{
strErr = "坐标参数与颜色参数不对称,拒绝功能调用";
return false;
}
else if(partPoint.GetLength(0) != 2)
{
strErr = "坐标参数数组定义与约定不符,拒绝功能调用";
}
else if(partPoint.GetLength(0) != partName.Length)
{
strErr = "坐标参数与组成名称参数不对称,拒绝功能调用";
return false;
}
string outPutName = imgName.Split('\\')[imgName.Split('\\').Length - 1].Split('.')[0].ToString();
string outPutParth = "";
for( int i = 0 ; i < imgName.Split('\\').Length - 1; i ++)
{
outPutParth = outPutParth + imgName.Split('\\')[i].ToString() + "\\";
}
#endregion
#region 基本图形
//功能调用
Bitmap bmp = new Bitmap(width,height);
Graphics g = Graphics.FromImage(bmp);
Pen pen = new Pen(Color.Black);
Rectangle outline = new Rectangle(0,0,height - 5,width -5);
g.SmoothingMode = SmoothingMode.AntiAlias;
g.Clear(bgColor);
g.DrawEllipse(pen,outline);
//输出图形区域
for(int i = 0 ; i < partName.Length; i ++)
{
g.FillPie(new SolidBrush(partColor[i]),outline,partPoint[i,0],partPoint[i,1]);
}
//输出到图片
bmp.Save(imgName,ImageFormat.Jpeg);
#endregion
#region 图形标题
if(debug)
{
bmp = new Bitmap(200 , 30);
g = Graphics.FromImage(bmp);
g.Clear(bgColor);
g.DrawString(title,new Font("Arail",14,FontStyle.Regular),SystemBrushes.WindowText,new PointF(0,0));
bmp.Save(outPutParth + outPutName + "_" + "Title" + ".jpg",ImageFormat.Jpeg);
}
#endregion
#region 描述图形
//输出颜色方块
for(int i = 0; i < partName.Length ; i++)
{
bmp = new Bitmap(15 , 15);
g = Graphics.FromImage(bmp);
pen = new Pen(Color.Black);
g.Clear(bgColor);
outline = new Rectangle(0,0,10,10);
g.DrawRectangle(pen,outline);
g.FillRectangle(new SolidBrush(partColor[i]),0,0,10,10);
bmp.Save(outPutParth + outPutName + "_" + "DesColor" + "_" + i.ToString() +".jpg",ImageFormat.Jpeg);
}
#endregion
#region 描述文字
if(debug)
{
for(int i = 0; i < partName.Length ; i++)
{
bmp = new Bitmap(120 , 15);
g = Graphics.FromImage(bmp);
g.Clear(bgColor);
g.DrawString(partName[i].ToString() + ": " + Convert.ToString( partCount[i]) + " " + unit,new Font("Arail",9,FontStyle.Regular),SystemBrushes.WindowText,new PointF(0,0));
bmp.Save(outPutParth + outPutName + "_" + "DesText" + "_" + i.ToString() +".jpg",ImageFormat.Jpeg);
}
}
#endregion
#region 释放资源
g.Dispose();
bmp.Dispose();
strErr = imgName + "绘制成功";
return true;
#endregion
}
#endregion
2. 中间逻辑组织函数
#region 构建饼状图
/// <summary>
/// 构建饼状图
/// </summary>
/// <param name="pie">图形参数</param>
/// <param name="JpgName">图形名称</param>
/// <returns>目标文件地址</returns>
private static string CreatePie(JPGPie pie,string JpgName)
{
//计算总和
int Count = 0;
for(int i = 0 ; i < pie.ElementValue.Length; i ++)
{
Count = Count + pie.ElementValue[i];
}
string strContent = "";
if(Count != 0)
{
#region 组织图形参数
//图形组成元素坐标
float[,]partPoint = new float[pie.ElementCount,2];
for(int i = 0 ; i < partPoint.GetLength(0); i ++)
{
for(int j = 0 ; j < partPoint.GetLength(1); j ++)
{
if( i == 0 && j == 0) //第一个扇形的第一条边
{
partPoint[i,j] = 0.0F;
}
else if( j == 0) //中间扇形的第一条边
{
partPoint[i,j] = partPoint[i-1,0] + partPoint[i -1,1];
}
else if( j == 1 && i == partPoint.GetLength(0) - 1)//最后一个扇型
{
partPoint[i,j] = Convert.ToSingle( pie.ElementValue[i] * 360 / Count + 2 );
}
else if( j == 1)//中间扇形的第二条边
{
partPoint[i,j] = Convert.ToSingle( pie.ElementValue[i] * 360 / Count );
}
}
}
#endregion
string strErr = "";
string strImgName = JPGReportManage.JpgPath("Pie\\"+ JpgName +".jpg");
#region 调用图形函数
JpgProxy.DrawPie(pie.BgHeight,pie.BgWidth,pie.BgTitle,pie.ElementName,partPoint,pie.ElementValue,pie.ElementColor,strImgName,pie.Unit,pie.BgColor,out strErr,false);
#endregion
#region 组织HTML代码
#region 格式控制
//换算值长度
int vir_max_lenth = 0;
//实际数值长度
int val_max_lenth = 0;
//最大元素下标
int flag = 0;
#region 求出最大元素下标
int k = 0;
int max_Value = pie.ElementValue[0];
for(int i = 0 ; i < pie.ElementValue.Length; i ++)
{
if(k < pie.ElementValue.Length -1)
{
k = i + 1;
}
else
{
break;
}
if( max_Value < pie.ElementValue[k] )
{
max_Value = pie.ElementValue[k];
flag = k;
}
}
#endregion
//长度标准
vir_max_lenth = Convert.ToString(pie.ElementValue[flag] * 100 / Count).Length;
val_max_lenth = pie.ElementValue[flag].ToString().Length;
#endregion
string strDynamic = "";
for(int i = 0 ; i < pie.ElementCount; i ++)
{
strDynamic = strDynamic +
"<tr>" +
"<td>" +
"<img src = '../jpg/pie/"+ JpgName +"_DesColor_"+ i.ToString() +".jpg'>" +
"</td>" +
"<td>" +
"<font size = 2 >" +
pie.ElementName[i].ToString() + " : " + Convert.ToString(pie.ElementValue[i] * 100 / Count) + JPGReportManage.HTMLSpaceGenerator(vir_max_lenth - Convert.ToString(pie.ElementValue[i] * 100 / Count).Length) + pie.Unit + "[" + pie.ElementValue[i].ToString() + JPGReportManage.HTMLSpaceGenerator(val_max_lenth - pie.ElementValue[i].ToString().Length) +"]" +
"</font>" +
"</td>" +
"</tr>" ;
}
strContent = "<HTML><Head></Head><Body>" +
"<table align = 'center' width = '100%' height = '100%'>" +
"<tr>" +
"<td>" +
"<table align = 'center'>" +
"<tr>" +
"<td>" +
"<img src = '../jpg/pie/"+ JpgName +".jpg'>" +
"<td>" +
"<td>" +
"<table align = 'center'>" +
strDynamic +
"</table>" +
"<td>" +
"</tr>" +
"</table>" +
"</td>" +
"<tr>" +
"</table>" +
"</Body></HTML>";
#endregion
}
else
{
#region 组织HTML代码
strContent = "<HTML><Head></Head><Body>" +
"<table align = 'center' width = '100%' height = '100%'>" +
"<tr>" +
"<td>" +
"<table align = 'center'>" +
"<tr>" +
"<td>" +
"没有数据可以显示" +
"</td>" +
"</tr>" +
"</table>" +
"</td>" +
"<tr>" +
"</table>" +
"</Body></HTML>";
#endregion
}
#region 生成HTML文件
JPGReportManage.CreateHtmFile(JPGReportManage.HtmlPath(JpgName + ".htm"),strContent);
#endregion
return "../Html/"+ JpgName +".htm";
}
#endregion
3. 特定应用调用
#region 各区办件数量同比柱状图
/// <summary>
/// 各区办件数量同比柱状图
/// </summary>
/// <param name="param"></param>
/// <returns></returns>
private static string Create_Cit_Case_Amount_Pos_Column(PosContrastParam param)
{
#region 逻辑处理
#region 参数处理
LiLongDataReport.JPGColumn column = new JPGColumn();
//图片颜色
column.BgColor = System.Drawing.Color.White;
//图片高度
column.BgHeight = 860;
//图片标题
column.BgTitle = "";
//图片宽度
column.BgWidth = 860;
//柱状颜色
System.Drawing.Color[]color = {System.Drawing.Color.Blue};
column.ElementColor = color;
//柱状总数
column.ElementCount = 1;
//柱状描述
string[]name = new string[PosNameDataBag.NameList.Length];
for(int i = 0 ; i < name.Length ; i ++)
{
name[i] = PosNameDataBag.NameList[i].Substring(0,2);
}
column.ElementName = name;
//统计单位
column.XUnit = "区";
//统计单位
column.YUnit = "件";
//柱状高度
int[]position = new int[PosNameDataBag.NameList.Length];
string Begin = "";
string End = "";
for(int i = 0 ; i < param.StartDate.Split('-').Length; i ++)
{
Begin = Begin + param.StartDate.Split('-')[i];
}
for(int i = 0 ; i < param.EndDate.Split('-').Length; i ++)
{
End = End + param.EndDate.Split('-')[i];
}
#endregion
#region 提交查询
string strErr = "";
string Result = "";
string strSql = "";
for(int i = 0; i < position.Length ; i ++)
{
XMLProxy.SetNodeValue(System.Web.HttpContext.Current.Server.MapPath("..") + "\\" + "state.xml","综合查询","正在处理"+ PosNameDataBag.NameList[i] +"区数据 任务数["+ PosNameDataBag.NameList.Length.ToString() +"] 已处理["+ i.ToString() +"] 未处理["+ Convert.ToString(PosNameDataBag.NameList.Length - i) +"]");
strSql = "SELECT count(*) as col from 办件表 where Cast(受理日期 as datetime) >= '"+ Begin + "' and Cast(受理日期 as datetime) <= '"+ End + "'";
DataBaseProxy.ExceuteSql(ConfigManage.ConnectionStringProxy(PosNameDataBag.NameList[i]),strSql,out Result,out strErr);
position[i] = int.Parse(Result);
}
#endregion
#region 绑定到参数
column.ElementValue = position;
#endregion
#endregion
#region 内核调用
string strReturn = null;
strReturn = JPGReportManage.CreateColumn(column,"Cit_Case_Amount_Pos_Column");
#endregion
return strReturn;
}
#endregion
4. 表层调用函数
#region 构造区级统计类图形
/// <summary>
/// 构造区级统计类图形
/// </summary>
/// <param name="jpgType">图形类型</param>
/// <param name="param">统计参数</param>
/// <returns>目标文件地址</returns>
public static string BuildPosAmountJPG(EJpgReportType jpgType,PosAmountParam param)
{
string strReturn = null;
switch(jpgType)
{
case EJpgReportType.Pos_Case_Amount_Type_Pie:
{
strReturn = JPGReportManage.Create_Pos_Case_Amount_Type_Pie(param);
break;
}
case EJpgReportType.Pos_Case_Amount_Year_Curve:
{
strReturn = JPGReportManage.Create_Pos_Case_Amount_Year_Curve(param);
break;
}
default:
{
strReturn = "";
break;
}
}
return strReturn;
}
#endregion
5. 相关参数列举
/// <summary>
/// 图形报表类型
/// </summary>
public enum EJpgReportType
{
/// <summary>
/// 区级年度办件数量走势折线图
/// </summary>
Pos_Case_Amount_Year_Curve = 0,
/// <summary>
/// 区级办件数量中各办件类型所占比例饼状图
/// </summary>
Pos_Case_Amount_Type_Pie =1,
/// <summary>
/// 各区办件数量同比柱状图
/// </summary>
Cit_Case_Amount_Pos_Column = 2,
/// <summary>
/// 各区办件数量排名饼状图
/// </summary>
Cit_Case_Amount_Pos_Pie = 3,
/// <summary>
/// 市级年度办件数量走势折线图
/// </summary>
Cit_Case_Amount_Year_Curve = 4,
/// <summary>
/// 各区所有办件中各办件类型所占比例饼状图
/// </summary>
Cit_Case_Type_Pie = 5,
/// <summary>
/// 委办局年度办件数量走势折线图
/// </summary>
Adm_Case_Amount_Year_Curve = 6,
/// <summary>
/// 委办局办件数量同比柱状图
/// </summary>
Adm_Case_Amount_Adm_Column = 7,
/// <summary>
/// 委办局各分局办件数量同比柱状图
/// </summary>
Adm_Case_Amount_Sub_Column = 8,
/// <summary>
/// 区级年度办件办结效率评估分析饼状图
/// </summary>
Pos_Case_End_Efficiency_Year_Pie = 9
}
#region 饼状图数据结构
/// <summary>
/// 饼状图数据结构
/// </summary>
public class JPGPie
{
//饼状组成元素个数
private int elementCount;
//饼状组成元素名称
private string[]elementName;
//饼状组成元素颜色
private Color[]elementColor;
//饼状组成元素大小
private int[]elementValue;
//饼装图形背景颜色
private Color bgColor;
//饼状图形高度
private int bgHeight;
//饼状图形宽度
private int bgWidth;
//饼状图形标题
private string bgTitle;
//饼状图统计单位
private string unit;
/// <summary>
/// 饼状图统计单位
/// </summary>
public string Unit
{
get
{
return unit;
}
set
{
unit = value;
}
}
/// <summary>
/// 饼状组成元素个数
/// </summary>
public int ElementCount
{
get
{
return elementCount;
}
set
{
elementCount = value;
}
}
/// <summary>
/// 饼状组成元素名称
/// </summary>
public string[]ElementName
{
get
{
return elementName;
}
set
{
elementName = value;
}
}
/// <summary>
/// 饼状组成元素颜色
/// </summary>
public Color[]ElementColor
{
get
{
return elementColor;
}
set
{
elementColor = value;
}
}
/// <summary>
/// 饼状组成元素大小
/// </summary>
public int[]ElementValue
{
get
{
return elementValue;
}
set
{
elementValue = value;
}
}
/// <summary>
/// 饼装图形背景颜色
/// </summary>
public Color BgColor
{
set
{
bgColor = value;
}
get
{
return bgColor;
}
}
/// <summary>
/// 饼状图形高度
/// </summary>
public int BgHeight
{
get
{
return bgHeight;
}
set
{
bgHeight = value;
}
}
/// <summary>
/// 饼状图形宽度
/// </summary>
public int BgWidth
{
get
{
return bgWidth;
}
set
{
bgWidth = value;
}
}
/// <summary>
/// 饼状图形标题
/// </summary>
public string BgTitle
{
get
{
return bgTitle;
}
set
{
bgTitle = value;
}
}
}
#endregion
6. 效果展示
希望能够有更多的知识与大家分享,共同进步!