天天看點

如何在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的運作機制 

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可以從微軟免費下載下傳,安裝時隻要采用所有預設選項即可。 

下載下傳得到的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">

  </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 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 _

    '添加一個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/" + strrelativepath + "'/>"

    ChartHolder.Controls.Add(New LiteralControl(strImageTag))

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;

    case 2:

     myTE=Microsoft.Office.Interop.OWC.ChartChartTypeEnum.chChartTypeSmoothLine;

    case 3:

     myTE=Microsoft.Office.Interop.OWC.ChartChartTypeEnum.chChartTypeArea;

    case 4:

     myTE=Microsoft.Office.Interop.OWC.ChartChartTypeEnum.chChartTypeRadarLine;

    default:

   }

  }

  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的全部檔案和源碼。

本文轉自 qianshao 51CTO部落格,原文連結:http://blog.51cto.com/qianshao/202152,如需轉載請自行聯系原作者