如何在ASP.NET中用OWC绘制图表

一、概述  
 
    在开发应用程序时,经常会遇到必须提供交互式图表的情况。例如,你可能在开发一个管理销售和产品数据的应用程序,数据保存在 SQL Server 数据库上,应用程序允许用户添加数据、更新现有数据,但除了这些功能之外,客户还要求应用程序能够用饼图、柱形图或 XY 散点图的形式直观地描述数据。  
Windows 桌面应用程序中,这类要求从来不成为问题,可供选用的图形库和绘图组件实在太多了。但对于 Web 应用程序,问题就变得复杂多了。要在 Web 应用中绘制图表,可供选择的办法包括:  
  客户端:  
利用各种 ActiveX 组件, Web 浏览器内完全有可能达到 丰富 ”Windows 客户程序那样的功能。缺点是客户端的设置复杂化,要求发布客户端软件,通常按照每客户端的方式计算许可证费用。另外,非 MS Windows/IE 的客户端一般难以运行。  
  服务器端:  
利用 Web 服务器上运行的服务器端代码,动态地生成图表,然后以 GIF JPG 图形的形式发送给客户端。这种办法的优点是,客户端只需要一个标准的浏览器。与客户端技术相比的缺点是,图形的交互能力差(除非向服务器提交新的请求,否则就不能缩放、滚动)。许多地图网站(例如 Mapquest.com )大量地运用了这一技术。注意,地图图形不是保存在 Web 服务器上,而是用户发出一个请求时动态从地图数据库生成。  
本文主要讨论如何利用服务器端的图表绘制技术在 ASP.NET Web 页面中提供图形功能
二、设置图表引擎  
如果要在 ASP.NET 应用程序中绘制图表,必须要有一个合适的图表引擎。 ASP.NET 有一个内建的图形工具库,即 System.Drawing 名称空间的 GDI+ ,可以用来创建简单的饼图、柱形图、折线图等,不过它属于低级的 API ,算不上绘制图表的引擎,特别是不适合绘制复杂的图表。  
   
本文要讨论的主角是 OWC ,即 Office Web Components ,或者 “Office Web 组件 。按照微软的定义, OWC 是一种 将类似 Office 的功能扩展到 Web 的微软技术 。它可以在客户端使用,例如我们将 Excel 工作表保存为 Web 页面时就要用到,利用它可以方便地将交互式电子表格和图表发布到 Web 页面。同时, OWC 也是一个优秀的服务器端图表引擎,具有与 MS Excel 同样强大的图表绘制能力。  
三、 OWC 的许可证问题  
如果你曾经用过版本较早的 OWC ,可能已经遇到过微软的许可证问题。以前这个问题相当令人烦恼,微软不仅要求服务器上必须有 Office 许可证,而且每一台客户 PC 上也同样要有。  
实际上,这相当于将 OWC 的用途局限到了 Intranet 之内,只有 Intranet 之内才可以保证客户 PC 上都安装了 Office 许可证。不过现在微软的态度有所放缓 ―― 服务器上仍旧要安装 Office 许可证,但只要图表是 非交互式 用途,例如本文的服务器端图表绘制,客户端就不必再装 Office 许可证。实际上,就连服务器端也不必安装完整的 Office 许可证, Excel 2002 FrontPage 2002 的许可证就已足够,从而使 OWC 变成了价廉物美的服务器端图表引擎。  
那么,在服务器上安装 MS Office ?不,没有必要。虽然从许可证条件看, OWC 应该是 Office 的一部分,但从技术上说, OWC 是一个独立的产品。 Web 服务器上只需安装 OWC 软件包,不必安装整个 Office  
OWC 首次出现于 Office 2000 ,即 OWC 9.0 。在 Office XP 中, OWC 的编程模式已作了修改,这使得 OWC XP (也就是 OWC 10 )不能与 OWC 9.0 完全兼容。 OWC 10 要求在 ASP.NET 环境中运行,所以 OWC 10 软件包必须安装到 ASP.NET 服务器上。  
接下来,很自然的一个问题是:哪里可以下载 OWC 10 软件包?令人惊奇的是,它可以从微软的网站免费下载,地址是 http://office.microsoft.com/downloads/2002/owc10.aspx
(
中文地址: http://www.microsoft.com/downloads/details.aspx?displaylang=zh-cn&FamilyID=982B0359-0A86-4FB2-A7EE-5F3A499515DD  网际浪子注 ) 但要注意的是, Web 服务器上必须安装了某种 Office 2002 的许可证才能合法地使用 OWC 10  
四、 OWC 的运行机制  
OWC 是一组 COM ActiveX )控件的集合,涵盖电子表格、图表、数据透视表等功能。它经常被当作客户端技术使用,这时 COM 控件就安装在客户端 PC 上。如果在服务器端使用,人们主要感兴趣的是它的图表绘制功能。  
有了 OWC ,我们可以在 ASP.NET Web 服务器上动态创建一个图表,然后将图表以 GIF 图形的形式发送到客户端。客户端看到的仅仅是一个普通的图形文件,但在 背后 ,图形文件实际上是由服务器上 ASP.NET 回应客户请求时动态生成的。因此,这种技术对客户端没有特殊的要求,只要能够显示 GIF 图形就可以了,即使 Netscape Opera 也不存在任何问题。  
既然如此,为什么在 ASP.NET 开发领域中, OWC 这一优秀的微软技术尚未被广泛采用呢?微软根本不为 OWC 作市场宣传,再加上令人迷惑的许可证问题,当然令许多开发者望而却步。也许微软认为该产品还没有完全成熟,即将到来的 Office 2003 将会带来 OWC 11 ,它的编程模式还会有所改变。另外,还有一种可能是微软担心 OWC 技术的广泛采用会影响 Office 的销售。  
再者,关于 OWC 的编程实例很少。微软知识库有几个客户端的例子和 传统 ”ASP 的服务器端例子,但找不到在 ASP.NET 环境中使用 OWC 10 的例子。 OWC 的新闻组, microsoft.public.office.developer.web.components ,主要讨论的也是客户端的应用。如果你要在 ASP.NET 环境中使用 OWC 10 ,主要还是靠自己摸索。正是因为这些原因,所以本文从相当广泛的角度探讨了该技术的实际应用。  
五、在 Web 服务器上安装 OWC 10 
要想在 ASP.NET Web 服务器上用 OWC 绘制图表,首先应当安装必要的软件和修改一些配置。  
第一, Web 服务器上当然应该有 ASP.NET 运行环境。除了 .NET Framework Redistributable ,还要有 GACUTIL 程序(属于 .NET 框架 SDK )来配置 OWC 控件,也就是说,还要安装 .NET Framework SDK 工具。如果把 .NET Framework 1.1 Redistributable SDK 安装到了默认目录, PATH 环境变量的内容应当包含: C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322;C:\Program Files\Microsoft.NET\SDK\v1.1\Bin  
接下来再在 Web 服务器上安装 OWC 10 OWC 可以从微软免费下载,安装时只要采用所有默认选项即可。  
由于 OWC 10 是一种 COM 技术,为了让 .NET 代码使用 OWC 10 组件,还必须安装 Office XP Primary Interop Assembly PIA ), PIA 可以从微软网站下载( http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnoxpta/html/odc_oxppias.asp )。
(
网际浪子发现的地址是: http://www.microsoft.com/downloads/details.aspx?FamilyId=C41BD61E-3060-4F71-A6B4-01FEBA508E52&displaylang=en)
下载得到的 OXPPIA.exe 是一个压缩文件,现在把它解压缩到服务器上的一个目录,假设是 C:\oxppia ,然后启动一个命令窗口(注意,确保 PATH 环境变量已正确设置 [ 网际浪子注:可以用我作的 SETPATH.BAT 运行一下 ] ),转到 c:\oxppia 目录,运行 REGISTER.bat  
这个命令把 Office XP PIA 导入到全局程序集缓冲区,修改注册表设置。注意观察 REGISTER.bat 命令的输出,确信 GACUTIL 命令确实在运行。如果 PATH 环境变量设置有误, PIA 不可能正确导入。 README 文档说应当用 VS.NET 命令行环境,但 Web 服务器上可能没有安装 VS.NET ,这时就要手工修改 PATH 环境变量了(效果一样)。  
最后,还要把下面这行代码加入 Web 服务器的 machine.config 文件的 <assemblies> 节,对于 .NET Framework 1.1 machine.config 文件可以在 C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\CONFIG 目录下找到:  

<add assembly="Microsoft.Office.Interop.OWC, Version=10.0.4504.0, 
     Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
 
浪子注明:如果发生不能编译的错误,可能要再次运行注册步骤!我这里这样,大家如果不一样,可以自己试试。
六、 OWC 编程模式  
   
要生成图表的数据称为数据原, Chart Component 组件支持的数据源有:实现 IDataSource 接口的任何数据源; ADO  Recordset 对象; XML 文件;数组或者一定格式的文本字符串。在 ASP 中,我们可以用 ADO Recordset 对象;在 .NET ADO.NET 中,由于 ADO.NET 没有实现 IDataSource .NET 也没有提供 ADO.NET DataSet 对象向 ADO Recordset 对象的直接转换,如果你有一个  DataSet 对象,你要么转换成 XML 文件,要么生成特殊格式的字符串才可以使用。下面就是本例子的结果:
[ 浪子注明:如果出错,可能是文件夹权限的问题,我的就是,要将虚拟目录的 everyone 的全部权限加上! ]
 
下面是实现这种功能的 VB.NET 版本的 ASP.NET 例子与代码:
OWC.aspx:
<%@ Page Language="vb" AutoEventWireup="false" Codebehind="OWC.aspx.vb" Inherits="aspxWeb.OWC"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
  <HEAD>
    <title>WebForm1</title>
    <meta name="GENERATOR" Content="Microsoft Visual Studio 7.0">
    <meta name="CODE_LANGUAGE" Content="C#">
    <meta name="vs_defaultClientScript" content="javascript">
    <meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5";>
  </HEAD>
  <body MS_POSITIONING="GridLayout">
    <form id="Form1" method="post" runat="server">
      <asp:placeholder id="ChartHolder" runat="server"></asp:placeholder>
    </form>
  </body>
</HTML>

OWC.aspx.vb
Imports System
Imports OWC
Imports System.Web.UI
Public Class OWC
  Inherits System.Web.UI.Page
  Protected WithEvents ChartHolder As System.Web.UI.WebControls.PlaceHolder
#Region " Web  窗体设计器生成的代码  "
  ' 该调用是  Web  窗体设计器所必需的。
  <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
  End Sub
  Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
    'CODEGEN: 
此方法调用是  Web  窗体设计器所必需的
    '
不要使用代码编辑器修改它。
    InitializeComponent()
  End Sub
#End Region
  Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    '
在此处放置初始化页的用户代码
    '
创建 ChartSpace 对象来放置图表
    Dim objCSpace As ChartSpace = New ChartSpaceClass()
    '
ChartSpace 对象中添加图表, Add 方法返回 chart 对象
    Dim objChart As WCChart = objCSpace.Charts.Add(0)
    '
指定图表的类型。类型由 OWC.ChartChartTypeEnum 枚举值得到
    objChart.Type = ChartChartTypeEnum.chChartTypeColumnClustered
    ' 指定图表是否需要图例
    objChart.HasLegend = True
    ' 给定标题
    objChart.HasTitle = True
    objChart.Title.Caption = "1-6
说数据分布图 "
    ' 给定 x,y 轴的图示说明
    objChart.Axes(0).HasTitle = True
    objChart.Axes(0).Title.Caption = "Y 
 :  数量 "
    objChart.Axes(1).HasTitle = True
    objChart.Axes(1).Title.Caption = "X 
轴:   月份 "
    ' 计算数据
    '*categories 
 values  可以用 tab 分割的字符串来表示 *
    Dim strSeriesName As String = "
图例  1"
    Dim strCategory As String = "1" + ControlChars.Tab + "2" + ControlChars.Tab _
 + "3" + ControlChars.Tab + "4" + ControlChars.Tab + "5" + ControlChars.Tab _
 + "6" + ControlChars.Tab
    Dim strvalue As String = "9" + ControlChars.Tab + "8" + ControlChars.Tab _
 + "4" + ControlChars.Tab + "10" + ControlChars.Tab + "12" + ControlChars.Tab _
 + "6" + ControlChars.Tab
    ' 添加一个 series
    objChart.SeriesCollection.Add(0)
    ' 给定 series 的名字
    objChart.SeriesCollection(0).SetData(ChartDimensionsEnum.chDimSeriesNames,_
  ChartSpecialDataSourcesEnum.chDataLiteral, strSeriesName)
    ' 给定分类
    objChart.SeriesCollection(0).SetData(ChartDimensionsEnum.chDimCategories,_
  ChartSpecialDataSourcesEnum.chDataLiteral, strCategory)
    ' 给定值
    objChart.SeriesCollection(0).SetData(ChartDimensionsEnum.chDimvalues,_
  ChartSpecialDataSourcesEnum.chDataLiteral, strvalue)
    '
输出成 GIF 文件 .
    Dim strAbsolutePath As String = (Server.MapPath(".")) + "\Images\test.gif"
    objCSpace.ExportPicture(strAbsolutePath, "GIF", 600, 350)
    ' 创建 GIF 文件的相对路径 .
    Dim strRelativePath As String = "Images/test.gif"
    '
把图片添加到 placeholder.
    Dim strImageTag As String = "<IMG SRC='890_files/&quot; + strrelativepath + &quot;'/>"
    ChartHolder.Controls.Add(New LiteralControl(strImageTag))
  End Sub
  
End Class
下面是 C# 版本的 OWC.asp.cs
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using Microsoft.Office.Interop; 
namespace Microsoft.Office.Interop.OWC
使用指南
{
 /// <summary>
 /// WebForm1 
的摘要说明。
 /// </summary>
 public class WebForm1 : System.Web.UI.Page
 {
  protected System.Web.UI.WebControls.PlaceHolder ChartHolder;
  private Microsoft.Office.Interop.OWC.ChartChartTypeEnum GetChartType(int typeIndex)
  {
   int i;
   Microsoft.Office.Interop.OWC.ChartChartTypeEnum myTE;
   i=typeIndex;
   
   switch(i)
   {
    case 0:
     myTE=Microsoft.Office.Interop.OWC.ChartChartTypeEnum.chChartTypeColumnClustered;
     return myTE;
    case 1:
     myTE=Microsoft.Office.Interop.OWC.ChartChartTypeEnum.chChartTypePie;
     return myTE;
    case 2:
     myTE=Microsoft.Office.Interop.OWC.ChartChartTypeEnum.chChartTypeSmoothLine;
     return myTE;
    case 3:
     myTE=Microsoft.Office.Interop.OWC.ChartChartTypeEnum.chChartTypeArea;
     return myTE;
    case 4:
     myTE=Microsoft.Office.Interop.OWC.ChartChartTypeEnum.chChartTypeRadarLine;
     return myTE;
    default:
     myTE=Microsoft.Office.Interop.OWC.ChartChartTypeEnum.chChartTypeColumnClustered;
     return myTE;
   }
  }
  private void Page_Load(object sender, System.EventArgs e)
  {
   // 
在此处放置用户代码以初始化页面
   //
创建 ChartSpace 对象来放置图表
   Microsoft.Office.Interop.OWC.ChartSpace objCSpace = new Microsoft.Office.Interop.OWC.ChartSpaceClass(); 
   // ChartSpace 对象中添加图表, Add 方法返回 chart 对象
   
   Microsoft.Office.Interop.OWC.ChChart   objChart = objCSpace.Charts.Add (0); 
   // 指定图表的类型。类型由 Microsoft.Office.Interop.OWC.ChartChartTypeEnum 枚举值得到
   //objChart.Type = Microsoft.Office.Interop.OWC.ChartChartTypeEnum.chChartTypeColumnClustered;
   //
上面的是画棒图的方法
   //objChart.Type = Microsoft.Office.Interop.OWC.ChartChartTypeEnum.chChartTypeSmoothLine;
   //
上面的是画平滑曲线的方法


   objChart.Type =Microsoft.Office.Interop.OWC.ChartChartTypeEnum.chChartTypeRadarLine;
   //
上面的是画雷达线的方法
   //objChart.Type =Microsoft.Office.Interop.OWC.ChartChartTypeEnum.chChartTypeArea;
   //
上面的是画区域线的方法
   //objChart.Type =Microsoft.Office.Interop.OWC.ChartChartTypeEnum.chChartTypePie;
   //
上面的是画饼图的方法,但是要关掉一些参数,比如
   /*//objChart.Axes[0].HasTitle = true;
   //objChart.Axes[0].Title.Caption = "Y 
  数量 ";
   //objChart.Axes[1].HasTitle = true;
   //objChart.Axes[1].Title.Caption = "X 
  月份 ";
    * */

   //
指定图表是否需要图例
   objChart.HasLegend = true;
   // 给定标题
   objChart.HasTitle = true;
   objChart.Title.Caption= "
上半年分布图 ";
   // 给定 x,y 轴的图示说明
   objChart.Axes[0].HasTitle = true;
   objChart.Axes[0].Title.Caption = "Y 
  数量 ";
   objChart.Axes[1].HasTitle = true;
   objChart.Axes[1].Title.Caption = "X 
  月份 ";
   // 计算数据
   /*categories 
 values  可以用 tab 分割的字符串来表示 */
   string strSeriesName = "
图例  1";
   string strCategory = "1" + '\t' + "2" + '\t' + "3" + '\t'+"4" + '\t' + "5" + '\t' + "6" + '\t';
   string strvalue = "9" + '\t' + "8" + '\t' + "4" + '\t'+"10" + '\t' + "12" + '\t' + "6" + '\t';
   // 添加一个 series
   objChart.SeriesCollection.Add(0);
   // 给定 series 的名字
   objChart.SeriesCollection[0].SetData (Microsoft.Office.Interop.OWC.ChartDimensionsEnum.chDimSeriesNames,
    + (int)Microsoft.Office.Interop.OWC.ChartSpecialDataSourcesEnum.chDataLiteral, strSeriesName);
   // 给定分类
   objChart.SeriesCollection[0].SetData (Microsoft.Office.Interop.OWC.ChartDimensionsEnum.chDimCategories,
    + (int)Microsoft.Office.Interop.OWC.ChartSpecialDataSourcesEnum.chDataLiteral, strCategory);
      
   // 给定值
   objChart.SeriesCollection[0].SetData
    (Microsoft.Office.Interop.OWC.ChartDimensionsEnum.chDimvalues,
    (int)Microsoft.Office.Interop.OWC.ChartSpecialDataSourcesEnum.chDataLiteral, strvalue); 
   //
输出成 GIF 文件 .
   string strAbsolutePath = (Server.MapPath(".")) + "\\test.gif";
   objCSpace.ExportPicture(strAbsolutePath, "GIF", 600, 350);
   // 创建 GIF 文件的相对路径 .
   string strRelativePath = "./test.gif";
   // 把图片添加到 placeholder.
   string strImageTag = "<IMG SRC='" + strRelativePath + "'/>";
   ChartHolder.Controls.Add(new LiteralControl(strImageTag));
  }
  #region Web Form Designer generated code
  override protected void OnInit(EventArgs e)
  {
   //
   // CODEGEN
:该调用是  ASP.NET Web  窗体设计器所必需的。
   //
   InitializeComponent();
   base.OnInit(e);
  }
 
  /// <summary>
  /// 
设计器支持所需的方法  -  不要使用代码编辑器修改
  /// 
此方法的内容。
  /// </summary>
  private void InitializeComponent()
  {    
   this.Load += new System.EventHandler(this.Page_Load);
  }
  #endregion
 }
}

如果用 ADO.NET DataSet 对象,可以生成以 TAB 分割的字符串:
strvalue += (nodes.Item(j).ChildNodes.Item(0).InnerText + '\t');
strCategory += (nodes.Item(j).ChildNodes.Item(1).InnerText + '\t');
 

Microsoft.Office.Interop
名称空间指向 Office XP PIA PIA 应该事先安装到 Web 服务器上。编译源代码时要用到 Office XP PIA OWC DLL 文件。如果用 VS.NET 编译,只要加入一个 Microsoft.Office.Interop.Owc.dll 文件的引用即可(位于解开 Office XP PIA 文件的目录),如果从命令行编译,必须按照下列方式使用 /r: 参数:  
vbc /t:library /out:bin\getchart.dll /r:System.dll /r:System.Web.dll 
   /r:System.Data.dll 
   /r:C:\oxppia\Microsoft.Office.Interop.Owc.dll getchart.aspx.vb
 

上面的代码有许多值得一提的地方。首先,我们假定数据源位于 MSSQL 数据库 OWCDEMO ,该数据库有一个 OWCDATA 表, OWCDATA 表有两个数值列,分别是 X Y getchart.aspx 的目标就是从数据库获取记录,然后用散点图( XY )描述这些数据。  
OWC 图表的数据点无法直接从 ASP.NET DataSet 获取,因此,我们首先要把数据库的数据装入数组,然后用数组的数据填写 OWC 图表的数据点。如果要对本例作改进的话,最好开发一个 ASP.NET 服务器控件,它能够从抽象的数据源(包括 DataSet 对象、 XML 文件或数组)获取数据并生成 XY 散点图。  
DataReader 要比 DataSet 快速、高效,不过,我们首先要确定数据库中的记录数量,根据记录数量来调整数组的大小。为此,我们先用一个 SQL Select count(*) 查询获取记录数量,然后定义数组大小,最后用第二个 SQL SELECT 查询获取数据库记录。  
如果我们要让散点图的各个点用折线连接起来,记录必须依照 X 轴排序,这通过一个 SQL ORDER BY 子句实现。  
OWC 的图表建立在 绘图空间 上。一个绘图空间可以包含一个或多个图表,每一个图表可以有一个或多个数据系列。在生成 OWC 图表时,我们首先创建一个绘图空间,将一个图表加入到绘图空间,设置图表的类型,添加数据系列,最后用数组的数据填写数据系列。  
另外,我们还可以设置(可选)各种布局参数,例如颜色、坐标标题、图表标题、图例,等等。 OWC 提供了数百个布局参数,我们可以随心所欲地调整图表。当然,对于不同的图表类型,绘图模式也略有不同,例如,饼图和散点图的参数设置方法是不同的。在 OWC 10 安装包中有 OWC 帮助文件,里面详细说明了 OWC 图表模型。  
最后, Response.BinaryWrite 参数指定了要输出的图形类型( GIF ),以及图形的宽度、高度(以像素为单位)。在这里,我们可以根据需要缩放从 OWC 图表生成的图形。  
 
对了,忘了说代码的位置了,在 FTP 里的论坛问题解答里,有一个 OWC 使用指南的目录,下面有使用 OWC 的全部文件和源码。

你可能感兴趣的:(职场,asp.net,休闲,owc,绘制图表)