在大多數情況下,我們的Web程序不僅僅需要給用戶提供具體數據,在一些情況下,我們還需要給高級的用戶或管理者提供數據匯總和分析圖表之類的功能。
如果我們不想顯示一大堆煩心的數據,希望通過餅圖或條形圖來直觀地顯示數據,這是我們可以考慮使用圖表控件顯示。
大家在訪問我的博客時,在左邊都可以看到一個統計每天的訪問人數的工具,這就是一個簡單的數據儀表程序,我們可以通過它直觀地知道當日的訪問數和時間。
在接下來的博文中,我們將向大家介紹數據儀表板程序的實現。
前一陣子有一篇博文關於StackOverflow 上的編程趨勢,它通過條形和區域圖,向我們展示了Stackoverflow上的熱門的問題標簽。
通過上圖,我們可以直觀地了解Stackoverflow上的熱門標簽的變化趨勢,現在,我們通過儀表程序實現同樣的功能。
在儀表程序界面中,我們會通過餅狀圖、區域圖和條形圖顯示數據,這裡我們使用Google Charts控件來顯示餅狀圖、區域圖和條形圖數據圖。
Google Charts通過Javascript實現動態圖片的繪制,它的使用非常簡便,我們只需給相應的繪圖函數傳遞相應的數據,就可以生成相應的數據圖表了。
現在,我們要在主界面(Dashboard)中,顯示數據的餅狀圖、區域圖和條形圖,那麼我們使用Google Charts控件動態地把三種圖形加載到Index.cshtml頁面中,下面是Index.cshtml頁面代碼:
@{ Html.RenderAction("Dashboard_Pie", "DashBoard"); } @{ Html.RenderAction("Dashboard_AreaChart", "DashBoard"); } @{ Html.RenderAction("Dashboard_ColumnChart", "DashBoard"); }
上面,我們定義了三個div元素,Index.cshtml頁面動態地加載Dashboard_Pie、Dashboard_AreaChart以及Dashboard_ColumnChart的內容。
接下來,我們要定義Dashboard_Pie(餅狀圖)、Dashboard_AreaChart(區域圖)和Dashboard_ColumnChart(條形圖)頁面,在定義數據圖界面之前,首先讓我們介紹Google Charts的使用。
前面我們提到Google Charts的使用十分方便,首先我們需要引用jsapi庫,在頁面代碼中添加如下代碼:
Google的JSAPI,不僅可以加載Google自身提供的AJAX API(如:Google Map API、Google Search API和Google Earth API),它還可以加載各種常用的JS庫(如:jQuery、jQuery UI、Prototype、MooTools和Dojo等)。
現在,我們在頁面中添加如下Javascript代碼,引用Google的visualization庫:
google.load(, , { packages: [] }); google.setOnLoadCallback(drawPieChart);
上面,我們使用google的load()方法加載了visualization庫,並且定義了加載成功後的回調函數為drawPieChart()。
也許有人會問:“為什麼不直接用Google CDN中提供Javascript庫呢?”有兩個原因,首先我們在Google CDN中沒有找到和visualization庫相關的引用地址(如有請告訴一下),其次,google的load()方法會加載一系列相關的資源(如:Javascript和CSS),這樣我們就無需一個個引用了。
前面,我們定義了回調函數drawPieChart(),但還沒有實現該方法,接下來,我們需要實現回調函數drawPieChart(),它負責獲繪制數據圖,具體實現如下:
drawPieChart() { $.ajax({ type: , dataType: , url: , data: {}, success: (data) { dt = google.visualization.DataTable(); dt.addColumn(, ); dt.addColumn(, ); (i = 0; i < data.length; i++) { dt.addRow([data[i].Name, data[i].Question]); } options = { title: }; chart = google.visualization.PieChart(document.getElementById()); chart.draw(dt, options); }, error: (xhr, textStatus, e) { console.log(+ textStatus + + e.toString()); }, complete: () { } }); }
上面,我們實現了回調函數drawPieChart(),它通過調用$.ajax()方法從後端中獲取數據,如果數據獲取成功,就把數據傳遞給draw()方法繪制數據圖表。
接著,我們實現Dashboard_Pie數據圖界面,具體代碼如下:
上面,我們在form元素中添加了一個div元素,由於我們在回調函數drawPieChart()中,指定了餅狀圖的加載位置,所以我們需要在頁面中添加餅狀圖的div元素。
前面,我們提到回調函數drawPieChart(),通過$.ajax()方法從後端中獲取數據,現在,我們需要提供API方法,讓客戶端通過調用API獲取相應的數據。
這裡,我們使用Stackoverflow Jan/01/2010到July/01/2013的熱門標簽數據(從這裡下載)。
由於數據是CSV格式的,所以我們可以使用Excel查看數據。
通過上圖中的數據,我們定義Language類,它包含四個字段分別是Id、Name、Question和CreateOn,具體定義如下:
{ Id { ; ; } Name { ; ; } Question { ; ; } CreateOn { ; ; } }
上面,我們定義了QuestionTag類,接下來,我們需要定義控制器類,它負責返回後端數據,所以我們在Controllers文件中創建DashboardController類,並且我們添加GetLanguageRank()方法,具體實現如下:
JsonResult GetLanguageRank() { }
上面,我們定義了DashboardController類,它包含GetLanguageRank()方法,接下來我們把CSV數據保存到數據庫中。
首先,我們在數據庫中創建數據表,具體SQL代碼如下:
GO GO GO [dbo][QuestionTags][Name] [varchar]50Chinese_PRC_CI_AS [Question] [int] [CreateOn] [datetime] [PRIMARY] GO
接著,我們CSV數據導入到SQL Server中,具體實現如下:
QuestionTags FIRSTROW 2FIELDTERMINATOR ROWTERMINATOR ERRORFILE ,? TABLOCK
上面,我們直接使用SQL語句把CSV數據導入到數據庫中,其中,我們定義了導入數據的源文件和數據格式,並且定義了ErrorLog文件記錄導入失敗的數據,最後,我們在表QuestionTags中添加自增型的Id主鍵。
現在,我們已經把數據儲存到數據庫中了,接下來我們將使用EF獲取數據庫中的數據,接觸過EF的應該都知道EF的編程模型有3種:
Database First:數據庫先行
Model First:模型先行
Code First:代碼先行
由於,前面我們已經把數據表定義好了,所以我們將使用數據庫先行(Database First)模型對數據庫進行訪問。
接下來,讓我們實現GetLanguageRank()方法,具體代碼如下:
JsonResult GetLanguageRank(index = 0) { (var db = DashboardDbContext()) { var result = (from tags db.QuestionTags orderby tags.CreateOn ascending select { tags.Id, tags.Name, tags.Question, tags.CreateOn }).Skip((index % 42) * 25).Take(25).ToList(); Json(result, JsonRequestBehavior.AllowGet); } }
我們實現了GetLanguageRank()方法,它根據index值獲取指定時間的數據,然後通過JSON數據格式返回給客戶端。
現在,我們已經實現了餅狀圖(Dashboard_Pie)了,接下來,讓我們運行Index.cshtml頁面查看運行的效果吧!
我們注意到圖1是一個動態圖,它直觀的展示了Stackoverflow熱門標簽的變化趨勢,如果我們也要實現動態生成數據圖該如何實現呢?
其實,問題轉化為實時獲取數據,然後生成數據圖就OK了,如果要實現實時獲取時間,我們想到的方法有:
1.Timer()
2.方法二數據庫實時方法數據(SqlDependency)
3.Other(請大家分享好方法)
接下來,我們將使用Javascript中Timer()函數來定時訪問GetLanguageRank()方法,所以我們需要修改Javascript代碼,通過Timer()函數定時調用drawColumnChart()方法,具體實現如下:
google.load(, , { packages: [] }); google.setOnLoadCallback(timerStart); cnt = 0, t; timerStart() { t = window.setInterval(drawColumnChart, 1000); } timerStop() { clearTimeout(t); } drawColumnChart() { $.ajax({ type: , dataType: , url: , data: { index: cnt }, success: (data) { dt = google.visualization.DataTable(); dt.addColumn(, ); dt.addColumn(, ); (i = 0; i < data.length; i++) { dt.addRow([data[i].Name, data[i].Question]); } dateTime = Date(parseInt(data[0].CreateOn.substr(6))); options = { title: + (dateTime.getMonth() + 1) + + dateTime.getDate() + + dateTime.getFullYear(), height: 500 }; chart = google.visualization.ColumnChart(document.getElementById()); chart.draw(dt, options); }, error: (xhr, textStatus, e) { timerStop(); console.log(+ textStatus + + e.toString()); }, complete: () { cnt = cnt + 1; } }); }
當Google的visualization庫加載完畢後,訪問回調函數timerStart(),然後使用setInterval()方法每隔1s就調用drawColumnChart()繪制新的柱狀圖。