在大多數狀況下,咱們的Web程序不單單須要給用戶提供具體數據,在一些狀況下,咱們還須要給高級的用戶或管理者提供數據彙總和分析圖表之類的功能。javascript
若是咱們不想顯示一大堆煩心的數據,但願經過餅圖或條形圖來直觀地顯示數據,這是咱們能夠考慮使用圖表控件顯示。html
你們在訪問個人博客時,在左邊均可以看到一個統計天天的訪問人數的工具,這就是一個簡單的數據儀表程序,咱們能夠經過它直觀地知道當日的訪問數和時間。java
在接下來的博文中,咱們將向你們介紹數據儀表板程序的實現。程序員
前一陣子有一篇博文關於StackOverflow 上的編程趨勢,它經過條形和區域圖,向咱們展現了Stackoverflow上的熱門的問題標籤。ajax
圖1 Stackoverflow的熱門標籤數據庫
經過上圖,咱們能夠直觀地瞭解Stackoverflow上的熱門標籤的變化趨勢,如今,咱們經過儀表程序實現一樣的功能。編程
在儀表程序界面中,咱們會經過餅狀圖、區域圖和條形圖顯示數據,這裏咱們使用Google Charts控件來顯示餅狀圖、區域圖和條形圖數據圖。json
Google Charts經過Javascript實現動態圖片的繪製,它的使用很是簡便,咱們只需給相應的繪圖函數傳遞相應的數據,就能夠生成相應的數據圖表了。後端
圖2 Dashboard界面api
如今,咱們要在主界面(Dashboard)中,顯示數據的餅狀圖、區域圖和條形圖,那麼咱們使用Google Charts控件動態地把三種圖形加載到Index.cshtml頁面中,下面是Index.cshtml頁面代碼:
<!-- Dashboard UI START --> <body> <div> @{ Html.RenderAction("Dashboard_Pie", "DashBoard"); } </div> <div> @{ Html.RenderAction("Dashboard_AreaChart", "DashBoard"); } </div> <div> @{ Html.RenderAction("Dashboard_ColumnChart", "DashBoard"); } </div> </body> <!-- Dashboard UI END -->
上面,咱們定義了三個div元素,Index.cshtml頁面動態地加載Dashboard_Pie、Dashboard_AreaChart以及Dashboard_ColumnChart的內容。
接下來,咱們要定義Dashboard_Pie(餅狀圖)、Dashboard_AreaChart(區域圖)和Dashboard_ColumnChart(條形圖)頁面,在定義數據圖界面以前,首先讓咱們介紹Google Charts的使用。
前面咱們提到Google Charts的使用十分方便,首先咱們須要引用jsapi庫,在頁面代碼中添加以下代碼:
<!-- Adds Google js api reference.--> <script type="text/javascript" src="https://www.google.com/jsapi"></script>
Google的JSAPI,不只能夠加載Google自身提供的AJAX API(如:Google Map API、Google Search API和Google Earth API),它還能夠加載各類經常使用的JS庫(如:jQuery、jQuery UI、Prototype、MooTools和Dojo等)。
如今,咱們在頁面中添加以下Javascript代碼,引用Google的visualization庫:
<script type="text/javascript"> google.load("visualization", "1", { packages: ["corechart"] }); google.setOnLoadCallback(drawPieChart); </script>
上面,咱們使用google的load()方法加載了visualization庫,而且定義了加載成功後的回調函數爲drawPieChart()。
也許有人會問:「爲何不直接用Google CDN中提供Javascript庫呢?」有兩個緣由,首先咱們在Google CDN中沒有找到和visualization庫相關的引用地址(若有請告訴一下),其次,google的load()方法會加載一系列相關的資源(如:Javascript和CSS),這樣咱們就無需一個個引用了。
前面,咱們定義了回調函數drawPieChart(),但尚未實現該方法,接下來,咱們須要實現回調函數drawPieChart(),它負責獲繪製數據圖,具體實現以下:
/** * Draws the pie chart. **/ function drawPieChart() { // Gets data from GetLanguageRank(). $.ajax({ type: 'GET', dataType: 'json', url: '<%= Url.Content("") %>', data: {}, success: function(data) { var dt = new google.visualization.DataTable(); dt.addColumn('string', 'Language'); dt.addColumn('number', 'Question'); // Adds data. for (var i = 0; i < data.length; i++) { dt.addRow([data[i].Name, data[i].Question]); } var options = { title: "Top 25 programming language" }; // Draws pie implemention. var chart = new google.visualization.PieChart(document.getElementById('pieChart')); chart.draw(dt, options); }, error: function(xhr, textStatus, e) { console.log('Status: ' + textStatus + ' Error: ' + e.toString()); }, complete: function() { } }); }
上面,咱們實現了回調函數drawPieChart(),它經過調用$.ajax()方法從後端中獲取數據,若是數據獲取成功,就把數據傳遞給draw()方法繪製數據圖表。
接着,咱們實現Dashboard_Pie數據圖界面,具體代碼以下:
<!-- Pie chart page --> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head id="Head1" runat="server"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> </head> <body> <form id="form2" runat="server"> <div id="pieChart"> </div> </form> </body> </html>
上面,咱們在form元素中添加了一個div元素,因爲咱們在回調函數drawPieChart()中,指定了餅狀圖的加載位置,因此咱們須要在頁面中添加餅狀圖的div元素。
前面,咱們提到回調函數drawPieChart(),經過$.ajax()方法從後端中獲取數據,如今,咱們須要提供API方法,讓客戶端經過調用API獲取相應的數據。
這裏,咱們使用Stackoverflow Jan/01/2010到July/01/2013的熱門標籤數據(從這裏下載)。
因爲數據是CSV格式的,因此咱們可使用Excel查看數據。
圖3 熱門標籤數據
經過上圖中的數據,咱們定義Language類,它包含四個字段分別是Id、Name、Question和CreateOn,具體定義以下:
圖4 Language類
/// <summary> /// The language model. /// </summary> public class QuestionTag { public int Id { get; set; } public string Name { get; set; } public int Question { get; set; } public DateTime CreateOn { get; set; } }
上面,咱們定義了QuestionTag類,接下來,咱們須要定義控制器類,它負責返回後端數據,因此咱們在Controllers文件中建立DashboardController類,而且咱們添加GetLanguageRank()方法,具體實現以下:
圖5 DashboardController類
/// <summary> /// Gets language rank data. /// </summary> /// <returns>JSON arrary.</returns> public JsonResult GetLanguageRank() { // Gets data from database. }
上面,咱們定義了DashboardController類,它包含GetLanguageRank()方法,接下來咱們把CSV數據保存到數據庫中。
首先,咱們在數據庫中建立數據表,具體SQL代碼以下:
-- ============================================= -- Author: JKhuang -- Create date: 07/25/2013 -- Description: Table for storing question tag data -- ============================================= SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO SET ANSI_PADDING ON GO CREATE TABLE [dbo].[QuestionTags]( [Name] [varchar](50) COLLATE Chinese_PRC_CI_AS NOT NULL, [Question] [int] NOT NULL, [CreateOn] [datetime] NOT NULL ) ON [PRIMARY] GO SET ANSI_PADDING OFF
接着,咱們CSV數據導入到SQL Server中,具體實現以下:
-- ============================================= -- Author: JKhuang -- Create date: 07/25/2013 -- Description: Imports csv data into database. -- ============================================= BULK INSERT QuestionTags FROM 'C:\Users\Administrator\Desktop\Stackoverflow Tags Data.csv' WITH ( FIRSTROW = 2, -- Start row excludes header. FIELDTERMINATOR = ',', --CSV field delimiter ROWTERMINATOR = '\n', --Use to shift the control to next row ERRORFILE = 'C:\Users\Administrator\Desktop\ErrorLog.csv',? TABLOCK )
上面,咱們直接使用SQL語句把CSV數據導入到數據庫中,其中,咱們定義了導入數據的源文件和數據格式,而且定義了ErrorLog文件記錄導入失敗的數據,最後,咱們在表QuestionTags中添加自增型的Id主鍵。
圖6 導入CSV數據
如今,咱們已經把數據儲存到數據庫中了,接下來咱們將使用EF獲取數據庫中的數據,接觸過EF的應該都知道EF的編程模型有3種:
Database First:數據庫先行
Model First:模型先行
Code First:代碼先行
因爲,前面咱們已經把數據表定義好了,因此咱們將使用數據庫先行(Database First)模型對數據庫進行訪問。
接下來,讓咱們實現GetLanguageRank()方法,具體代碼以下:
/// <summary> /// Gets language rank data. /// </summary> /// <param name="index">Specifies the range of data, /// for instance, when index is 0, then get the data range from Jan/1/2010 till Feb/2/2010. /// </param> /// <returns>JSON Array</returns> public JsonResult GetLanguageRank(int index = 0) { using (var db = new DashboardDbContext()) { var result = (from tags in db.QuestionTags orderby tags.CreateOn ascending select new { tags.Id, tags.Name, tags.Question, tags.CreateOn }).Skip((index % 42) * 25).Take(25).ToList(); return Json(result, JsonRequestBehavior.AllowGet); } }
咱們實現了GetLanguageRank()方法,它根據index值獲取指定時間的數據,而後經過JSON數據格式返回給客戶端。
如今,咱們已經實現了餅狀圖(Dashboard_Pie)了,接下來,讓咱們運行Index.cshtml頁面查看運行的效果吧!
圖7 餅狀圖
咱們注意到圖1是一個動態圖,它直觀的展現了Stackoverflow熱門標籤的變化趨勢,若是咱們也要實現動態生成數據圖該如何實現呢?
其實,問題轉化爲實時獲取數據,而後生成數據圖就OK了,若是要實現實時獲取時間,咱們想到的方法有:
1.Timer()
2.方法二數據庫實時方法數據(SqlDependency)
3.Other(請你們分享好方法)
接下來,咱們將使用Javascript中Timer()函數來定時訪問GetLanguageRank()方法,因此咱們須要修改Javascript代碼,經過Timer()函數定時調用drawColumnChart()方法,具體實現以下:
<script type="text/javascript"> google.load("visualization", "1", { packages: ["corechart"] }); google.setOnLoadCallback(timerStart); var cnt = 0, t; function timerStart() { t = window.setInterval(drawColumnChart, 1000); } function timerStop() { clearTimeout(t); } function drawColumnChart() { $.ajax({ type: 'GET', dataType: 'json', url: '<%= Url.Content("~/Dashboard/GetLanguageRank") %>', data: { index: cnt }, success: function(data) { var dt = new google.visualization.DataTable(); dt.addColumn('string', 'Language'); dt.addColumn('number', 'Question'); for (var i = 0; i < data.length; i++) { dt.addRow([data[i].Name, data[i].Question]); } var dateTime = new Date(parseInt(data[0].CreateOn.substr(6))); var options = { title: "Top 25 programming language on " + (dateTime.getMonth() + 1) + '/' + dateTime.getDate() + '/' + dateTime.getFullYear(), //width: 600, height: 500 }; var chart = new google.visualization.ColumnChart(document.getElementById('columnChart')); chart.draw(dt, options); }, error: function(xhr, textStatus, e) { timerStop(); console.log('Status: ' + textStatus + ' Error: ' + e.toString()); }, complete: function() { cnt = cnt + 1; } }); } </script>
當Google的visualization庫加載完畢後,訪問回調函數timerStart(),而後使用setInterval()方法每隔1s就調用drawColumnChart()繪製新的柱狀圖。
圖8 柱狀圖
如今,咱們經過Timer()函數實時的訪問API接口,數據經過柱狀圖動態地顯示出來。
如今,咱們已經完成了餅狀圖和柱狀圖,接下來,咱們須要給儀表程序添加一些簡單的CSS效果,具體代碼以下:
/*Dashboard APP CSS*/ .pageHeader { height: 20px; background-color: #2C2C2C; padding: 10px 10px; margin-bottom: 10px; color: White; position: relative; } .pageHeader h1 { font: normal 1.2em Arial; color: White; margin: 0; padding: 0; } .pageHeader .platformular { position: absolute; top: 10px; right: 10px; } .pageBody { margin: 0 10px; } .pageFooter { clear: both; padding-top: 10px; width: 100%; text-align: center; font-size: 0.8em; color: #686868; margin: 25px 0 0 0; border-top: solid 1px #e7e7e7; }
如今,咱們從新運行程序查看頁面效果。
圖10儀表程序
在本博文中,咱們經過使用ASP.NET MVC和EF的Database First實現了簡單的儀表程序,使用Google Charts控件來顯示數據圖,這只是一個簡單的程序,咱們還有很大的改善空間,提供一個內容豐富和功能強大的程序是每一個程序員的目標。
更新:08/02/2013