• 统计报表


    统计图表

         
     


    作者:郭斌 时间:2003年10月
    作者手机:13571878390
    作者项目:Syn-Data
    负责人名称: 韦敏宗
    负责人Email: hansmail@sina.com

    Syn-Data基于Internet数据协同会议系统是利用最新流媒体通信技术实现的一个具有实时多点语音、视频、数据通讯综合应用能力的系统。它不仅实现基于Internet的具有多人音频、多人视频、共享电子白板、共享文档等交流手段的实时数据协同、实时讨论的功能,而且实现单机的课件录制,全程录制回放等功能,具有对带宽要求低,高质量音频视频,与Web无缝集成,强的抗网络拥塞丢包能力和支持防火墙和应用代理等能力。它使用户可以利用普通的PC机、标准的视频采集设备、耳机和麦克风,实现基于Internet的实时数据协同、实时讨论。Syn-Data致力于有效地节约时间和经费,提高了用户的工作效率,使任何人不受时间、地点的限制,可充分享受网络时代给大家带来的实时交互式多媒体通信服务。使用Syn-Data,终端用户可以实现共享演示文档、应用程序、网页及桌面等,同时提供音、视频的无缝嵌入。

    BlastTeam:该文为Blast Tean技术原创文章之一。因为是一系列文章,故文章描述是以章节来描述的。BlastTeam最终将把所有的技术原创文章汇编成册。
    概述
    在Web程序开发中,图形和图表是很好的数据表现形式。往往是表格中的大量数据让用户产生无法处理,无从获取所需要的信息。而以图表方式提供数据的话就可以达到简单清爽,简单易懂并且一目了然的效果。利用图表,管理人员可以方便的掌握销售与生产数据,从而做出相应的判断。
    在ASP.NET Web程序中,生成图表有以下的选择:
    ● ASP.NET内建的图形库(GDI+,位于System.Drawing 命名空间)
    使用简单的图形,GDI+能够创建饼图、柱状图、线性图。但是这种方法过于底层,不适于创建复杂的图形。
    ● 各种ASP.NET图表控件
    网上有一些ASP.NET的图表控件,但许多控件非常昂贵,而且与最常用的图表应用Excel差别很大。
    ● Office Web Components
    Microsoft Office Web Components 包含在 Microsoft Office 2000 中。它们是用于向 Web 页添加电子表格、图表和数据处理功能的 ActiveX 控件的集合。可以直接在浏览器中处理数据,并以图表的形式显示数据。由于其基于Office的强大功能,以及与Office相同的用户界面,无疑是ASP.NET中图表生成的明智选择。
    本章主要包括以下几个方面内容:
    ● 基于GDI+的图表生成。
    ● 基于Office Web Components的图表生成。
    ● 基于Office Web Components的报表生成。
    经过本章的学习,将掌握ASP.NET中统计图表的实现,利用图表将网站的数据完美呈现给用户。
    方案设计
    本节分别介绍GDI+与Office Web Components的具体使用,为后面的章节打下基础。
    使用GDI+
    GDI+ 是 GDI(Windows XP之前版本提供的图形设备接口)的后续版本。GDI+ 是一种应用程序编程接口 (API),负责在屏幕和打印机上显示信息。
    在ASP.NET中,利用GDI+可以创建简单的柱状图和饼图。
    ASP.NET页面GDI+图像使用
    在完整的生成柱状图和饼图之前,先从简单的ASP.NET页面图像使用开始。
    在System.Draw命名空间中包含了创建、编辑图像的所有类。创建图像时,主要使用Bitmap类和Graphics类。为了便于理解,可以把Bitmap类想象成画板,Graphics类想象成画笔。Bitmap类主要用于创建画板以及在完成后图像的保存。Graphics类主要用来绘制图像、图形和线条。
    首先使用下面的代码创建画板。(本小节所有代码需要添加System.Drawing命名空间与System.Drawing.Image命名空间)
    Bitmap myPalette = new Bitmap(600, 400); //创建600*400的画板
    有了画板,还需要创建Graphics类的实例来创建画笔,指定画板。代码如下
    Graphics myGraphics = Graphics.FromImage(myPalette);
    有了画笔和画板,只要使用Graphics类中的各种方法在画板上绘制图像、图形和线条就可以了。
    Graphics类中的方法分为两类:绘制方法与填充方法。例如,DrawRectangle方法与FillRectangle方法。绘制方法仅仅绘制出图形的轮廓,而填充方法绘制出图形的轮廓同时填充图形的内部。
    下面的代码绘制了简单的图形:
    int width=150,height=50;
    // 创建黑色背景椭圆
    myGraphics.FillEllipse(new SolidBrush(Color.Black), 300, 150, width, height);
    // 创建蓝色背景椭圆
    myGraphics.FillEllipse(new SolidBrush(Color.LightBlue), 300, 150, width - 10, height - 10);
    // 创建输出文本
    string textOut = "ASP.NET";
    //指定字体
    Font fontOut = new Font("Times New Roman", 16, FontStyle.Bold|FontStyle.Italic);
    //指定文本居中
    StringFormat stringFormat = new StringFormat();
    stringFormat.Alignment = StringAlignment.Center;
    stringFormat.LineAlignment = StringAlignment.Center;
    // 绘制文本
    myGraphics.DrawString(textOut,fontOut,new SolidBrush(Color.Black),new Rectangle(0,0,width,height),stringFormat);
    图已经画好了,只剩下将图保存下来。要将保存的图在网页中显示,可以在下面两种方式中任选其一:
    ● 将图像保存在服务器的文件系统中,使用HTML的<img>标记来显示。
    ● 直接将图像的二进制流输出到Response对象的输出流。
    两种方式各有千秋。第一种方式适合于创建不需要变动的图片(例如网站广告图片),能够创建一次,满足今后的所有要求。但会在服务器端保留下临时文件。第二种方式适用于动态的创建图片供页面显示,不能满足今后的需要,却也不会留下临时文件。
    下面分别写出这两种方式的代码:
    ● 保存文件方式代码:
    保存文件方式首先需要在Aspx文件中添加<Img>标记
    <!-- 指定显示文件为tmpFile.jpg -->
    <img src = “tmpFile.jpg”>
    然后在代码中保存文件即可:
    //将文件保存为当前页面所在目录下的tmpFile.jpg
    myPalette.Save(Server.MapPath("")+@"\tmpFile.jpg",ImageFormat.Jpeg);
    ● 直接输出方式代码:
    //直接将图片以二进制流的方式输出到Response对象的输出流。
    myPalette.Save(Response.OutputStream, ImageFormat.Jpeg);
    将代码加入页面的PageLoad事件中即可得到如图18-1效果。
          
           图18-1 GDI+图像使用效果
    创建柱状图
    在知道了如何使用GDI+创建简单图像并显示到页面后,创建复杂一些的柱状图就非常自然了。
    使用简单的FillRectangle,DrawRectangle,DrawString方法,即可实现基本的柱状图。代码如下:
    //初始化Bitmap类实例与Graphics类实例准备画图
    const int width = 600, height = 400;
    Bitmap myPalette = new Bitmap(width,height);
    Graphics myGraphics = Graphics.FromImage(myPalette);
    // 绘制白色背景
    myGraphics.FillRectangle(new SolidBrush(Color.White), 0, 0, width, height);
    // 设定显示数据
    string [] DataName = {"Jan","Feb","Mar","Apr","May","Jun"};
    int [] Data = {100,20,50,60,240,20};
    //设定显示颜色
    Color [] myColors = {
    Color.Blue,
    Color.Red,
    Color.Yellow,
    Color.Purple,
    Color.Orange,
    Color.Brown
    };
    //绘制柱图
    for(int i = 0;i<DataName.Length;i++)
    {
    //填充柱图
    myGraphics.FillRectangle(new SolidBrush(myColors[i]),(i*40)+30,300 - Data[i],20,Data[i]+5);
    //绘制柱图边界
    myGraphics.DrawRectangle(new Pen(Color.Black),(i*40)+30,300 - Data[i],20,Data[i]+5);
    //绘制柱图上方数据
    myGraphics.DrawString(Data[i].ToString(), new Font("宋体", 9), Brushes.Black, new PointF((i*40)+30,300-Data[i]-20));
    //绘制柱图下标
    myGraphics.DrawString(DataName[i], new Font("宋体", 9), Brushes.Black, new PointF((i*40)+30,320));
    }
    //输出图像
    myPalette.Save(Response.OutputStream, ImageFormat.Jpeg);
    // 清除所用绘图对象
    myGraphics.Dispose();
    myPalette.Dispose();
    将上述代码写入页面CodeBehind文件的PageLoad事件中即可看到如图18-2效果:
           
              图18-2 GDI+柱状图效果
    使用Office Web Components
    Office Web Components是用于向 Web 页添加电子表格、图表和数据处理功能的 ActiveX控件的集合。
    利用Office Web Components可以方便的来绘制简单的柱状图与饼图。不必像在GDI+中需要考虑画图的细节。
    使用Office Web Components要求
    使用Office Web Components需要系统中装有Office2000以上版本。在工程的引用中添加Office Web Components即可。
    具体步骤如下:
    在解决方案资源管理器的引用文件夹上单击鼠标右键选择添加引用,在出现的添加引用对话框中选择COM标签,选择Microsoft Office Web Components,双击选中,点击确定即可。图18-3、18-4显示了该过程。
           
                图18-3 添加引用           图18-4 添加Office Web Components引用

    使用Office Web Components绘制柱状图
    使用Office Web Components绘制图表不同于直接使用GDI+,主要的工作从绘图的细节转移到对于图表的设置。步骤如下:
    ● Step1 创建ChartSpace对象来放置图表
    ChartSpace是用来放置图表的类,图表完成后用它来输出。
    OWC.ChartSpace objCSpace = new OWC.ChartSpaceClass ();
    ● Step2 使用ChartSpace对象的Add方法创建图表
    ChartSpace的Add方法创建图表,参数表示所创建图表的索引。
    OWC.WCChart objChart = objCSpace.Charts.Add (0);
    ● Step3 指定图表的类型
    通过设定Chart类对象的Type属性来指定图表的类型。
    objChart.Type = OWC.ChartChartTypeEnum.chChartTypeColumnClustered;
    本例创建柱状图,选择了chChartTypeColunmClustered类型。
    其他的类型包括:chChartTypeArea 面积图、chChartTypeBarClustered 条形图、chChartTypePie 饼图、chChartType RadarLine 雷达线图、chChartTypeSmoothLine 平滑曲线图、chChartTypeDoughnut 环形图等等。
    图18-5至18-10显示了部分图表的简单实例。
           
             图18-5 曲线图          图18-6 条形图          图18-7 面积图
           
             图18-8 环形图           图18-9 饼图          图18-10 雷达图
    ● Step4 设定图示说明
    图示说明主要包括图例(用颜色表示数据类型)、图题(图表的标题)、XY轴的数据说明(一般用来说明各轴上的数据单位)。设定代码如下:
    //指定图表是否需要图例
    objChart.HasLegend = true;

    //给定标题
    objChart.HasTitle = true;
    objChart.Title.Caption= "上半年月收入图";

    //给定x,y轴的图示说明
    objChart.Axes[0].HasTitle = true;
    objChart.Axes[0].Title.Caption = "万元";
    objChart.Axes[1].HasTitle = true;
    objChart.Axes[1].Title.Caption = "月份";
    ● Step5 添加数据
    添加数据主要设定Chart类对象的SeriesCollection属性。首先使用SeriesCollection的Add方法创建一组数据。然后使用SetData方法具体添加数据。代码如下:
    (注意:数据的格式是以'\t'间隔的字符串)
    //添加一组图表数据
    objChart.SeriesCollection.Add(0);
    //给定该组数据的名字
    objChart.SeriesCollection[0].SetData (OWC.ChartDimensionsEnum.chDimSeriesNames,
    + (int)OWC.ChartSpecialDataSourcesEnum.chDataLiteral,”上半年收入”);
    //给定数据分类
    objChart.SeriesCollection[0].SetData (OWC.ChartDimensionsEnum.chDimCategories,
    + (int)OWC.ChartSpecialDataSourcesEnum.chDataLiteral,
    "Jan"+'\t'+"Feb"+'\t'+"Mar"+'\t'+"Apr"+'\t'+"May"+'\t'+"Jun"+'\t' );
    //给定数据值
    objChart.SeriesCollection[0].SetData (OWC.ChartDimensionsEnum.chDimValues,
    (int)OWC.ChartSpecialDataSourcesEnum.chDataLiteral,
    "100"+'\t'+"20"+'\t'+"50"+'\t'+"60"+'\t'+"240"+'\t'+"20"+'\t');
    ● Step6 显示数据
    显示数据是使用Chart类对象的ExportPicture方法将生成的图表创建为图片,然后显示的。代码如下:
    //输出成GIF文件,参数为文件名、格式、图片大小
    objCSpace.ExportPicture(Server.MapPath("")+@"\tmpFile.gif", "GIF", 400, 300);
    //从生成的图片创建Bitmap对象,输出到Response输出流
    Bitmap myPalette = new Bitmap(Server.MapPath("")+@"\tmpFile.gif",true);
    myPalette.Save(Response.OutputStream,System.Drawing.Imaging.ImageFormat.Gif);
    经过了以上的步骤,将代码输入页面的PageLoad事件代码段中,运行程序就可以得到如图18-11效果。
            
            图18-11 Office Web Components柱状图示例
    使用Office Web Components绘制饼图
    绘制饼图与绘制柱状图的区别不是很大,需要注意的是饼图没有XY轴,所以不能设置XY轴的图示说明。在绘制柱状图的代码上去掉关于XY轴图示说明的代码即可。
    完整代码如下:
    //初始化图表数据
    string [] DataName = {"Jan","Feb","Mar","Apr","May","Jun"};
    int [] Data = {100,20,50,60,240,20};
    //声明存储数据分类和数据值的字符串
    string strDataName = "";
    string strData = "";
    //循环按格式生成存储数据分类与数据值的字符串
    for(int i=0;i< Data.Length;i++)
    {
    strCategory += DataName[i]+'\t';
    strValue += Data[i].ToString()+'\t';
    }
    //创建ChartSpace对象来放置图表
    OWC.ChartSpace objCSpace = new OWC.ChartSpaceClass ();

    //在ChartSpace对象中添加图表,Add方法返回chart对象
    OWC.WCChart objChart = objCSpace.Charts.Add (0);

    //指定图表的类型为饼图
    objChart.Type = OWC.ChartChartTypeEnum.chChartTypePie;
    //指定图表是否需要图例
    objChart.HasLegend = true;
    //给定标题
    objChart.HasTitle = true;
    objChart.Title.Caption= "上半年月收入图";

    //添加一个series
    objChart.SeriesCollection.Add(0);

    //给定数据分类
    objChart.SeriesCollection[0].SetData (OWC.ChartDimensionsEnum.chDimCategories,
    + (int)OWC.ChartSpecialDataSourcesEnum.chDataLiteral,strDataName);

    //给定数据值
    objChart.SeriesCollection[0].SetData (OWC.ChartDimensionsEnum.chDimValues,
    (int)OWC.ChartSpecialDataSourcesEnum.chDataLiteral,strData);
    //输出成GIF文件.
    objCSpace.ExportPicture(Server.MapPath("")+@"\tmpFile.gif", "GIF", 400, 300);
    Bitmap myPalette = new Bitmap(Server.MapPath("")+@"\tmpFile.gif",true);
    myPalette.Save(Response.OutputStream,System.Drawing.Imaging.ImageFormat.Gif);
    将上述代码写入页面文件的PageLoad事件处理代码中,运行得到如图18-12效果。
             
            图18-12 Office Web Components饼图示例
    公司盈利状况统计
    前面介绍了Office Web Components的情况,本节将通过公司盈利状况统计来介绍Office Web Components柱状图在具体实例中的使用。
    数据库设计
    为了实现公司盈利状况统计。首先,需要设计相关的数据库表。在实际情况中,公司的盈利就是收入的总和与支出的总和之差。而每笔收入与支出都是在一次交易中完成的。基于以上考虑,同时为了实现简单。设计数据库表单如下:
    表名 T_Deal 别名 交易表
    表项      说明   类型     是否可空
    DealTime   交易时间  DateTime     否
    DealIncome  交易金额  int       否
    DealContent  交易内容  Varchar(50)   否
    DealObject  交易对象  Varchar(20)   是
    Comment    备注    Varchar(50)   是
    注意:为了简单起见,用交易金额统一表示收入与支出。用正数的交易金额表示收入,负数的交易金额表示支出。这样计算盈利时只需将交易金额求和即可。
    按照上表的格式在SqlServer中创建表。添加样例数据供程序使用。
    然后创建下面的存储过程来实现公司盈利状况的统计。
    CREATE PROCEDURE sp_SelectIncome
    @year int
    AS

    Select sum(DealCount),Datepart(mm,DealTime) From T_Deal
    where DATEPART(yy,DealTime)=@year
    Group By Datepart(mm,DealTime)
    GO
    该存储过程选择交易时间的年份与输入参数@year相等的数据,并将选择得到的数据按交易时间的月份分组。返回每组交易金额的总和以及该组的交易月份。
    界面设计
    新建Web工程WebChart。将WebForm1.aspx改名为OWCChart.aspx。同时,将其代码文件中的类名改为OWCChart。
    界面如图18-13所示:
          
              图18-13 公司盈利统计界面
    该界面主要包括两部分:一个PlaceHolder控件用来放置生成的图表构成显示图表部分。一个用来选择统计年份的DropDownList控件,一个用来确定生成图表的Button控件,一个用来显示错误信息的Label控件构成了图表的生成部分。
    同样为了界面整洁使用Table将所用控件放在表格中。按照图18-13安排好界面后就可以为控件设置属性了,主要包括以下几个方面的设置:
    ● PlaceHolder控件的设置
    PlaceHolder控件在本程序中用于放置生成的图表,只需设置其Id属性为ChartPlaceHolder即可。
    ● DropDownList控件的设置
    DropDownList控件在本程序中用于选择统计年份,设置其Id属性为ddlYear。并为其添加ListItem 2000,2001,2002,2003。
    <asp:ListItem Value="2000">2000</asp:ListItem>
    <asp:ListItem Value="2001">2001</asp:ListItem>
    <asp:ListItem Value="2002">2002</asp:ListItem>
    <asp:ListItem Value="2003">2003</asp:ListItem>
    ● Button控件的设置
    Button控件设置Id属性为btnSumbit,Text属性为“确定”即可。
    ● Label控件的设置
    Label控件设置Id属性为Info即可。
    代码实现
    在完成了上面的界面设计后,就要进入后台代码的编写了。下面就将分模块介绍各部分功能的代码实现。
    数据读入
    为了显示公司盈利状况统计,首先需要将统计的结果从数据库中读入。读入数据的代码包括以下两部分。
    ● 创建数据库联接
    为了方便程序的配置,将数据库联接字段保存在Web.Config文件中。如此一来,在需要修改数据库联接字段时只需要修改Web.Config文件即可,不需要修改程序代码,重新编译。
    在Web.Config文件中的<configuration>字段中加入如下代码:
    <appSettings>
    <add key="ConnectStr"
    value="server=localhost;uid=yourid;pwd=yourpas;database=Info;"/>
    </appSettings>
    其中localhost要改为自己的数据库服务器名,uid,pwd分别为数据库用户id和密码,database为数据库名。
    设置好联接字段后就可在代码中对其进行引用了。
    主要使用AppSettingReader对象的GetValue方法获取”ConnectStr”字段信息,该方法需要两个参数,第一个指定要引用的字段,第二个参数指定需要的类型。返回一个Object类型的变量。需要使用Convert的ToString方法将其转换为字符串类型
    引用代码如下:
    //全局数据库联接
    System.Data.SqlClient.SqlConnection MyConnection;
    private void Page_Load(object sender, System.EventArgs e)
    {
    // 在此处放置用户代码以初始化页面
    if(Page.IsPostBack==false) // 页面首次加载时
    {

    //创建Web.Config文件应用程序设置字段读取对象
    System.Configuration.AppSettingsReader ConnectionString = new System.Configuration.AppSettingsReader();
    //创建数据库联接
    MyConnection = new System.Data.SqlClient.SqlConnection();
    //设置数据库联接的连接字段
    MyConnection.ConnectionString = Convert.ToString(ConnectionString.GetValue("ConnectStr",System.Type.GetType("System.String")));
    }
    }
    ● 利用数据库联接读取数据
    有了前面创建的数据库联接就可以从数据库中读取数据了。
    读取数据代码如下:
    //读取数据函数,参数为需要统计的年份,返回DataSet
    DataSet ReadData(string Year)
    {
    //创建DataSet
    DataSet dsIncome = new DataSet();
    //设置存储过程名
    string SpName = "sp_SelectIncome";
    //创建Sql命令
    SqlCommand IncomeCmd = new SqlCommand(SpName,MyConnection);
    //设定数据库命令类型为存储过程
    IncomeCmd.CommandType = CommandType.StoredProcedure;
    //打开数据库联接
    MyConnection.Open();
    //创建并设定存储过程参数
    SqlParameter IncomeYear = new SqlParameter("@year",SqlDbType.Int,4);
    IncomeYear.Value=Convert.ToInt16(Year);
    //为Sql命令添加参数
    IncomeCmd.Parameters.Add(IncomeYear);
    //创建Sql数据桥接器
    SqlDataAdapter adapter = new SqlDataAdapter(SpName,MyConnection);
    //指定桥接器Sql命令
    adapter.SelectCommand = IncomeCmd;
    //填充DataSet
    adapter.Fill(dsIncome,"Income");
    //关闭数据库联接
    MyConnection.Close();
    }
    数据显示
    使用ReadData方法读出数据,接下来就是显示数据了。显示数据同样需要两个步骤。
    ● 处理数据库读出的数据
    由于从数据库读出的数据不能完全满足显示的要求,有可能某个月份没有交易,那么返回的DataSet中就不会包含该月的数据。但显示时需要所有月份的数据。所以直接显示数据之前先要对数据进行加工。代码如下:
    //创建存储数据的数组,MyMonthIncome存放每月数据,MyMonthName存放月份缩写
    int[] MyMonthIncome = new int[12];
    string[] MyMonthName = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};

    //声明存放显示用字符串的变量,strMonthName存放月份信息,strMonthIncome存放数据
    string strMonthName = "";
    string strMonthIncome = "";
    //对存在数据的月份将数据保存在MyMonthName
    for(int i=0;i< dsIncome.Tables["Income"].Rows.Count;i++)
    {
    MyMonthIncome[Convert.ToInt16(dsIncome.Tables["Income"].Rows[i][1])-1] = Convert.ToInt16(dsIncome.Tables["Income"].Rows[i][0]);
    }
    //用已有的数据来生成图表显示所需的字符串
    for(int i=0;i< 12;i++)
    {
    strMonthName += MyMonthName[i]+'\t';
    strMonthIncome += MyMonthIncome[i].ToString()+'\t';
    }
    ● 使用Office Web Components显示数据
    经过上一步骤,图表显示所需的字符串已经放入了strMonthName和strMonthIncome中,下面使用18.2节中关于Office Web Components的知识就可以大功告成了。需要注意的是在生成图片后使用了PlaceHolder的.Controls属性的Add方法将动态生成的<img>标签放入页面。为了方便后面的使用,将显示数据的代码写为函数。代码如下:
    private void MakeLineChart(string Year)
    {
    //使用ReadData函数读出数据
    DataSet dsIncome = ReadData(Year);
    //以下插入处理数据库读出的数据部分的代码,不再重复
    //….上一步骤中处理数据库读出数据代码

    //创建ChartSpace对象来放置图表
    OWC.ChartSpace mySpace = new OWC.ChartSpaceClass ();
    //在ChartSpace对象中添加图表,Add方法返回chart对象
    OWC.WCChart myChart = mySpace.Charts.Add (0);

    //指定图表的类型为线性图
    myChart.Type = OWC.ChartChartTypeEnum.chChartTypeLine;
    //指定图表是否需要图例
    myChart.HasLegend = true;
    //给定标题
    myChart.HasTitle = true;
    myChart.Title.Caption= ddlYear.SelectedItem.Text + "月收入图";
    //给定x,y轴的图示说明
    myChart.Axes[0].HasTitle = true;
    myChart.Axes[0].Title.Caption = "万元";
    myChart.Axes[1].HasTitle = true;
    myChart.Axes[1].Title.Caption = "月份";
    //添加一个series
    myChart.SeriesCollection.Add(0);
    //给定series的名字
    myChart.SeriesCollection[0].SetData (OWC.ChartDimensionsEnum.chDimSeriesNames,
    + (int)OWC.ChartSpecialDataSourcesEnum.chDataLiteral, strSeriesName);
    //给定分类
    myChart.SeriesCollection[0].SetData (OWC.ChartDimensionsEnum.chDimCategories,
    + (int)OWC.ChartSpecialDataSourcesEnum.chDataLiteral, strCategory);
    //给定值
    myChart.SeriesCollection[0].SetData (OWC.ChartDimensionsEnum.chDimValues,
    (int)OWC.ChartSpecialDataSourcesEnum.chDataLiteral, strValue);
    //输出成GIF文件.
    string strAbsolutePath = (Server.MapPath(".")) + @"\images\tempFile.gif";
    mySpace.ExportPicture(strAbsolutePath, "GIF", 700, 350);
    //创建GIF文件的相对路径.
    string strRelativePath = "./images/tempFile.gif”
    //生成显示图片的<img>标签
    string strImageTag = "<IMG SRC='" + strRelativePath + "'/>";
    //把图片添加到placeholder.
    ChartPlaceHolder.Controls.Add(new LiteralControl(strImageTag));
    18.3.3.3 按钮点击事件
    有了前面的MakeLineChart函数,在aspx页面的设计模式下双击btnSumbit创建按钮点击事件。修改代码如下:
    private void btnSubmit_Click(object sender, System.EventArgs e)
    {
    MakeLineChart(ddlYear.SelectedItem.Text);
    }
    至此,公司盈利状况统计功能完全实现,运行结果如图18-16:
            
             图18-16 公司盈利状况统计效果
    公司收入分块图
    上一节介绍了Office Web Components的柱状图的使用,实现了对公司盈利状况统计。本节将通过公司收入分块图的实现来介绍Office Web Components中饼装图的使用。
    数据库设计
    为了实现公司收入分块图,为T_Deal表增添交易类别字段。扩充后的T_Deal表如下:
    表名 T_Deal 别名 交易表
    表项      说明   类型     是否可空
    DealTime   交易时间  DateTime     否
    DealIncome  交易金额  int       否
    DealContent  交易内容  Varchar(50)   否
    DealObject  交易对象  Varchar(20)   是
    DealCategory 交易类别  Varchar(20)   否
    Comment     备注   Varchar(50)   是
    按照新表的格式重新在SqlServer中创建表。添加样例数据供程序使用。并且创建如下存储过程实现公司收入分块统计。
    CREATE PROCEDURE sp_SelectCategory
    @year int
    AS

    Select sum(DealCount),DealCategory From T_Deal
    where DATEPART(yy,DealTime)=@year
    Group By DealCategory
    GO
    该存储过程选择交易时间的年份与输入参数@year相等的数据,并将选择得到的数据按交易类别分组。返回每组交易金额的总和以及该组的交易类别。
    界面设计
    为了简便同时利用已有成果,在现有的基础上修改无疑是最好的选择。因此,本节的程序直接在上一节的程序上修改。在原有界面上添加一个DropDownList来选择不同的图表内容。新的界面如图18-17:
          
             图18-17 公司收入分布界面
    新增的DropDownList属性设置为Id=ddlChartType,并为其添加Item
    <asp:ListItem Value="Income">公司盈利状况</asp:ListItem>
    <asp:ListItem Value="Category">公司收入分块图</asp:ListItem>
    代码实现
    在完成了上面的界面设计后,就要进入后台代码的编写了。由于是在上一节的基础上,所以只需增加新功能。
    数据读入
    由于已经有了创建数据库联接部分,下面只需要读出数据即可。数据读入部分代码与上一节的代码相似,不同之处只是所调用的存储过程不同,为了简化代码,修改ReadData函数,为其增加参数SpName 指定调用的存储过程。将原有程序中声明SpName的语句删除即可。
    //读取数据函数,参数Yesr为需要统计的年份SpName为调用存储过程名,返回DataSet
    DataSet ReadData(string Year,string SpName)
    {
    //创建DataSet
    DataSet dsIncome = new DataSet();
    //设置存储过程名,通过新增参数完成,将此句去除
    //string SpName = "sp_SelectIncome";
    //以下部分不做修改,不再重复

    }
    注意:修改ReadData函数后,在上一节MakeLineChart函数中调用ReadData的代码需要为其增加参数。
    private void MakeLineChart(string Year)
    {
    //使用ReadData函数读出数据
    DataSet dsIncome = ReadData(Year,“sp_SelectIncome”);
    //以下部分不做修改

    }
    数据显示
    使用ReadData方法读出数据,接下来就是显示数据了。显示数据的代码也只需对上一节代码做部分修改即可。声明绘制分类收入的函数,将MakeLineChart函数内容复制并修改如下:
    private void MakePieChart(string Year)
    {
    //使用ReadData函数读出数据
    DataSet dsCategory = ReadData(Year);
    //创建存储数据的数组,MyCategory存放类别数据,MyMonthName存放类别名称
    int[] MyCategory = new int[dsIncome.Tables["Income"].Rows.Count];
    string[] MyCategoryName = new string[dsIncome.Tables["Income"].Rows.Count];

    //声明存放显示用字符串的变量,strMonthName存放月份信息,strMonthIncome存放数据
    string strCategoryName = "";
    string strCategory = "";
    //声明总收入,用来计算各分类收入百分比
    int IncomeSum = 0;
    //将数据放入数组,同时计算总收入
    for(int i=0;i< dsIncome.Tables["Income"].Rows.Count;i++)
    {
    MyCategory[i] = Convert.ToInt16(dsIncome.Tables["Income"].Rows[i][0]);
    MyCategoryName[i] = Convert.ToString(dsIncome.Tables["Income"].Rows[i][1]);
    IncomeSum += MyCategory[i];
    }
    //用已有的数据来生成图表显示所需的字符串
    for(int i=0;i< dsIncome.Tables["Income"].Rows.Count;i++)
    {
    //计算出各分类所占百分比
    int PercentCategory= 100*MyCategory[i]/IncomeSum;
    strCategory += MyCategoryName[i]+" "+PercentCategory.ToString()+ "%"+'\t';
    strValue += MyCategory[i].ToString()+'\t';
    }
    //下面代码与上一节基本相同不再重复
    //仅给出需要修改的部分

    //指定图表的类型为线性图 改为饼图
    myChart.Type = OWC.ChartChartTypeEnum.chChartTypePie;
    //指定图表是否需要图例
    myChart.HasLegend = true;
    //给定标题
    myChart.HasTitle = true;
    myChart.Title.Caption= ddlYear.SelectedItem.Text + "收入图";
    //给定x,y轴的图示说明 ,去掉XY轴图示说明部分
    /*
    myChart.Axes[0].HasTitle = true;
    myChart.Axes[0].Title.Caption = "万元";
    myChart.Axes[1].HasTitle = true;
    myChart.Axes[1].Title.Caption = "月份";
    */

    }
    18.3.3.3 按钮点击事件
    由于增加了新功能,按钮点击的代码修改如下:
    private void btnSubmit_Click(object sender, System.EventArgs e)
    {
    //根据ddlChartType的选项判断执行的内容
    if(ddlChartType.SelectedItem.Value=="Income")
    MakeLineChart(ddlYear.SelectedItem.Text); //显示公司盈利统计
    else if(ddlChartType.SelectedItem.Value=="Category")
    MakePieChart(ddlYear.SelectedItem.Text);//显示收入分布
    }
    至此,公司盈利状况统计功能完全实现,运行后选择收入分布点击确定按钮。结果如图18-18:
           
            图18-18 公司收入分块图效果
    报表产出
    前面的几个小节完成了对数据的统计并以图表的形式呈现给用户,使用户能够一目了然的获取所需信息。这一节将把统计结果以Excel报表的形式输出,以免用户提交报表时手工输入的麻烦,提高工作效率。
    报表产出主要使用了Office Web Components的Spreadsheet控件。利用该控件创建并编辑数据表格,并将最终结果输出到Excel报表。步骤如下:
    ● Step1创建SpreadsheetClass对象,用来放置数据表格
    类似于Chart控件中的ChartSpace,Spread控件中也需要创建一个放置SpreadsheetClass的对象作为单个表的容器。
    SpreadsheetClass exl = new SpreadsheetClass();
    ● Step2利用SpreadsheetClass的ActiveSheet获得当前处于活动状态的表格
    一个SpreadsheetClass对象就相当于一个运行中的Excel,通过其ActiveSheet属性能够得到当前处于活动状态的表格。一个Worksheet对象就相当于Excel中的一张表格。将SpreadsheetClass对象的ActiveSheet属性赋值给Worksheet对象。就可以在后面的代码中对表格进行操作了。
    OWC.Worksheet ws = exl.ActiveSheet;
    ● Step3 编辑表格
    编辑表格使用的是Worksheet对象的Cells属性。Cells属性就代表着表格中的每个单元格。使用Cells[row,col]的格式引用,row表示行号,col表示列号。需要注意的是行号和列号都是从1开始的,而不是像C#的数组是从0开始。例如Cells[2,2]就表示表格的第二行,第二列的单元格。下面是产生盈利状况统计报表的编辑表格代码(该段代码添加在MakePieChart函数末尾,其中的变量延用之前的声明):
    //为表格设定标题
    ws.Cells[1, 1] = "收入(万元)";
    ws.Cells[1,2] = "类别";
    ws.Cells[1,3] = "所占比重";
    //将数据写入表格
    for(int i=0;i<dsIncome.Tables[0].Rows.Count;i++)
    {
    ws.Cells[i+2,1] = MyCategory[i].ToString();
    ws.Cells[i+2,2] = MyCategoryName[i];
    int Percent = MyMonthIncome[i]*100/IncomeSum;
    ws.Cells[i+2,3] = Percent.ToString() + "%";
    }
    //将总收入写入表格
    ws.Cells[dsIncome.Tables[0].Rows.Count + 2,1] = IncomeSum.ToString();
    ws.Cells[dsIncome.Tables[0].Rows.Count + 2,2] = "总和";
    ws.Cells[dsIncome.Tables[0].Rows.Count + 2,3] = "100%";
    Step4 导出表格
    导出表格使用Worksheet对象的Export方法,将表格导出为Excel文件即可。考虑到可能出现异常,使用了try,catch来捕获可能出现的异常,输出错误信息。
    try
    {
    //输出Excel报表到服务器文件系统
    ws.Export(Server.MapPath(" ") + @"\Excel\report.xls", OWC.SheetExportActionEnum.ssExportActionNone);
    }
    catch
    {
    //错误时输出错误提示
    Info.Text = "保存报表错误,请与管理员联系";
    }
    将上述代码添加到MakePieChart函数的末尾,重新运行,在工程所在文件夹下的子Excel目录中就会有report.xls文件。其结果如图18-19。
           
            图18-19 生成报表结果图
    小结
    这一章先对ASP.NET中生成统计图表进行了介绍,然后对GDI+与Office Web Components的使用进行了详细说明,为后面做好了知识储备。随后利用公司盈利状况统计和公司收入分块图两个实例详细的介绍了如何利用Office Web Components与数据库结合绘制统计图表以及生成报表。
    通过本章的学习,读者对于.NET中统计报表的生成有了深刻的理解,相信精美、清晰的报表一定会为成为Web程序的亮点。

  • 相关阅读:
    Cesium原理篇:4Web Workers剖析(2)
    Cesium原理篇:4Web Workers剖析
    Cesium原理篇:3最长的一帧之地形(1)
    Cesium原理篇:2最长的一帧之网格划分
    Cesium原理篇:1最长的一帧之渲染调度
    CSS3火焰文字特效制作教程
    一款非常棒的纯CSS3 3D菜单演示及制作教程
    jQuery/CSS3类似阿里巴巴的商品导航菜单实现教程
    CSS3 3D立方体翻转菜单实现教程
    强大!HTML5 3D美女图片旋转实现教程
  • 原文地址:https://www.cnblogs.com/zengwei/p/624659.html
Copyright © 2020-2023  润新知