ASP.NET+jqPlot實作線上即時統計圖表(Chart)

如果你以前想在ASP.NET下做畫一些統計圖表(Chart),那可能會選擇Microsoft Chart Controls,這個東西叫「伺服器控制項」,也就是說它吃的資源是「伺服器」,雖然是個不錯的解決方法,但還必須K點資料才能上手玩玩。題外話,在Visual Studio 2010裡我有看到已經內建Chart控制項。

那有沒有「輕鬆入門」的Chart套件,網路世界無奇不有,首先先介紹一套jQuery的plug-in的函式庫:jqPlot,我認為這個plug-in有幾點很不錯:

  1. 免費
  2. chart功能完整
  3. 輕鬆入門
  4. 範例清礎
  5. javascript(資源是吃Client)

一般而言,這種Chart的東西通常都要收費,而且費用還不低。而這套jqPlot,除了免費而且使用簡單,你只要產出jqPlot所需要的格式參數,那它就會幫你把想要的統計圖表一張一張產生出來。

1. include the Files

請在頁面<head>裡加入以下Script,路徑請自行修改。

<!--[if IE]><script language="javascript" type="text/javascript" src="excanvas.js"></script><![endif]-->
<script language="javascript" type="text/javascript" src="jquery-1.3.2.min.js"></script>
<script language="javascript" type="text/javascript" src="jquery.jqplot.min.js"></script>
<link rel="stylesheet" type="text/css" href="jquery.jqplot.css" />

這裡有幾件事要注意,
  1. 第一行那個if IE一定要放,不然在IE圖會出不來
  2. 只能在IE8上執行,IE8以下圖一樣會出不來(這個bug我抓了好久)
  3. 可以將jquery-1.3.2.min.js換成jquery-1.4.2.min.js
第1,2點請注意,如果使用者不會使用到IE來看圖,你可以不放。第3點,1.4.2版的執行效率比1.3.2版提升不少,我測試使用上是還沒有碰到問題。

2. 增加一個目標區(div)

也就是要讓jqPlot畫圖的區塊,重點是div的id屬性,等一下只要把id值給jqPlot函式,jqPlot就會幫你畫美美的圖表了。

3. 建立圖表參數

使用上,我會建議你直接上jqPlot Examples, 去找你所需要圖表,然後它會跟你提醒兩件事:

  1. 此Chart除了上面的Script外,必須額外加那些plug-in,這些plug-in放在plugins目錄中,將這些附加到上面Script的後面即可。
  2. 此Chart所需要的參數格式

第2點,就是我們的重點,也就是說,要透過ASP.NET與ADO.NET產生所需要的格式。

1. 實作:問卷分析統計圖表

我設計了一個問卷活動的程式,收集到問卷資料後,必須產生相關的統計圖表。在資料庫部份,我將所有資料選項都化為0,1,2這種字串(char),單選就簡單,利用SQL語法做加總即可,複選就複雜一點,我在存入資料庫時,先把所有選擇值整理成一個"0,1,3,5,7,9"的字串格式儲存,統計時再取出放到陣列來進行每一項目的統計。

資料庫和統計程式,我不方便透漏。不過運作的演算法可以分享一下。

一、在Default.aspx放入一個PlaceHolder控制項,拿來放產生後的javascript。

二、在Default.aspx放入畫圖參數(請查jqPlot Examples),範例:


/*問卷統計圓餅圖*/
var plot1 = $.jqplot('chartQ1', [line1], {
    title: 'Q1職業分析',
    seriesDefaults: { renderer: $.jqplot.PieRenderer, rendererOptions: { sliceMargin: 8} },
    legend: { show: true }
});

注意:
  1. 建立對應的div區塊,id必須與$.jqplot('chartQ1',[line1]…的'chartQ1'相同。
  2. 產生數據參數名稱,必須與[line1]相同
  3. var plot1參數名稱不能重覆
  4. 如果在同一頁產生多張Chart,程式會依順序執行,如果其中一個發生問題,會影響後面全部Chart的產生
第1,2,3點很好理解。第4點意思是說,假設我一次要產生10張Chart圖,所以我的畫圖參數就會有var plot1, var plot2, var plot3...var plot10(由上而下排列),每個plot1...plot10帶不同參數, 假設line5產生的數據有問題,所以造成plot5的圖產生失敗,那接下來plot6,7,8,9,10就都不會產生(這個bug我也抓了好久)。

三、Default.apsx.vb產生必須的參數值[line]


Dim line As New Literal()
'資料庫處理…
'整理出相關統計數據…

'整理出我們需要的參數格式
line.Text += "<script type='text/javascript'> var " & lineName & " = [['網管(" & Q1sum1.ToString & "票-" & ((Q1sum1 / sum) * 100).ToString("##.##") & "%)'," & Q1sum1.ToString() & _
"],['採購(" & Q1sum2.ToString() & "票-" & ((Q1sum2 / sum) * 100).ToString("##.##") & "%)'," & Q1sum2.ToString() & _
"],['網咖主(" & Q1sum3.ToString() & "票-" & ((Q1sum3 / sum) * 100).ToString("##.##") & "%)'," & Q1sum3.ToString & _
"],['系統人員(" & Q1sum4.ToString() & "票-" & ((Q1sum4 / sum) * 100).ToString("##.##") & "%)'," & Q1sum4.ToString & _
"],['其他(" & Q1sum5.ToString() & "票-" & ((Q1sum5 / sum) * 100).ToString("##.##") & "%)'," & Q1sum5.ToString() & "]]</script>"

'加到PlaceHolder控制項
phJS.Controls.Add(line)
End Sub

範例:
我最後在Default.aspx就產生了以下了javascript程式碼:
<script type='text/javascript'> 
var line1 = [['網管(12票-7.19%)',12],['採購(37票-22.16%)',37],['網咖主(17票-10.18%)',17],['系統人員(17票-10.18%)',17],['其他(0票-%)',0]]
</script>

四、最後看看我們的畫面:



有沒有一種感動到想哭的感覺。 我在一個畫面上產出45張統計圖(含圓餅圖及長條圖),速度要看電腦,原因在上面說過了,但基本測試都還不錯,而且Server Loading又輕,讓我有那種相見恨晚對感覺。

16 則留言:

  1. 您好,
    我有下載這個plugin了, 但不知怎麼用!方便教一下嘛?謝謝~
    我把範例copy下來, 但網頁卻沒顯示圖~~

    回覆刪除
  2. 我這篇文章不就是教你怎麼用嗎?

    回覆刪除
  3. 我有個不解,這控制項怎麼拉進去,我在工具箱裡找不到這控制項~~怎麼加入參考!

    回覆刪除
  4. jqPlot本身是jQuery的plugin,不是ASP.NET的plugin。

    你必須使用Server端的程式產生符合格式的JavaScript,然後Client端就會自動幫你產生圖片。

    回覆刪除
  5. 大大您好
    在試用之後真的發現他的強大
    但是遇到了一個問題
    ['其他(0票-%)',0]
    票數0的部分
    在這邊測試他會涵蓋一大片
    請問,是不是有特殊的方法
    如最後畫面讓右上還是有顯示其他
    而在圓餅途中看不到呢?
    懇請不吝賜教~謝謝

    回覆刪除
  6. 請檢查最後產出的Javascript。
    像你打的o<--是「歐」是不零,零是0。

    回覆刪除
  7. 或把你的專案壓縮一下傳給我:kingkong.bruce小老鼠gmail.com,我找個

    回覆刪除
  8. 版主您好~我是上次那位發問者
    那個『歐』是複製版主的code所以他應該是個零~@@
    實際用0測試會出現涵蓋一整片圓
    原因:新版本的bug 於官網也有人討論
    問題解決辦法:
    1.開啟jqplot.pieRenderer.js
    2.將if (ang1 = ang2) {
    return;
    }
    更正成為
    if (ang1 >= ang2) {
    return;
    }
    問題已解決
    感謝版主熱心發表此篇
    獲益良多。

    回覆刪除
  9. 我使用的是0.9.7版,不是0.9.7rxxx版本。也感謝你的回饋。

    回覆刪除
  10. 請問如果使用 updatepanel 定時重新繪圖,有什麼方式可以解決,因為我只有在第一次成功繪出後,tick 啟動後圖就不見了

    回覆刪除
  11. jqPlot 是 JavaScript 去產生圖形,
    Updatepanel 它會自動去修改 JavaScript 裡的值嗎?

    回覆刪除
    回覆
    1. 對我需要變動更新值

      刪除
    2. 我有將 javascript產生值的部份 放在 updatepanel內,按我的想法是應該會自動重新產生…是嗎?

      刪除
    3. jqPlot 只是忠實的照您給參數的值來進行"Render"動作。我想你應該確認的是,updatepanel 的 javascript 是否有跟著變動?

      另外給你一篇參考:http://blog.darkthread.net/post-2008-11-26-why-not-updatepanel.aspx,"按我的想法是應該會自動重新產生…是嗎?"這句話只有"是嗎?"三個字我認為沒錯。

      你應該試著用 AJAX 去後端取值(不要使用 updatepanel),然後重新修重參數值,這樣 jqPlot 就會自動重新 Render 圖形。

      刪除

感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。