ASP.NET MVC实现仪表程序
1.1.1 摘要
在大多数情况下,我们的Web程序不仅仅需要给用户提供具体数据,在一些情况下,我们还需要给高级的用户或管理者提供数据汇总和分析图表之类的功能。
如果我们不想显示一大堆烦心的数据,希望通过饼图或条形图来直观地显示数据,这是我们可以考虑使用图表控件显示。
大家在访问我的博客时,在左边都可以看到一个统计每天的访问人数的工具,这就是一个简单的数据仪表程序,我们可以通过它直观地知道当日的访问数和时间。
在接下来的博文中,我们将向大家介绍数据仪表板程序的实现。
目录
1.1.2 正文
前一阵子有一篇博文关于StackOverflow 上的编程趋势,它通过条形和区域图,向我们展示了Stackoverflow上的热门的问题标签。
图1 Stackoverflow的热门标签
通过上图,我们可以直观地了解Stackoverflow上的热门标签的变化趋势,现在,我们通过仪表程序实现同样的功能。
在仪表程序界面中,我们会通过饼状图、区域图和条形图显示数据,这里我们使用Google Charts控件来显示饼状图、区域图和条形图数据图。
Google Charts通过Javascript实现动态图片的绘制,它的使用非常简便,我们只需给相应的绘图函数传递相应的数据,就可以生成相应的数据图表了。
UI设计
图2 Dashboard界面
现在,我们要在主界面(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的使用。
Javascript
前面我们提到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数据
ASP.NET控制器
现在,我们已经把数据储存到数据库中了,接下来我们将使用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仪表程序
1.1.3 总结
在本博文中,我们通过使用ASP.NET MVC和EF的Database First实现了简单的仪表程序,使用Google Charts控件来显示数据图,这只是一个简单的程序,我们还有很大的改善空间,提供一个内容丰富和功能强大的程序是每个程序员的目标。
参考
更新:08/02/2013
ASP.NET MVC实现仪表程序的更多相关文章
- ASP.NET MVC - 探究应用程序文件夹
为了学习 ASP.NET MVC,我们将构建一个 Internet 应用程序. 第 2 部分:探究应用程序文件夹. MVC 文件夹 一个典型的 ASP.NET MVC Web 应用程序的文件夹内容如下 ...
- 在 ASP.NET MVC Web 应用程序中输出 RSS Feeds
RSS全称Really Simple Syndication.一些更新频率较高的网站可以通过RSS让订阅者快速获取更新信息.RSS文档需遵守XML规范的,其中必需包含标题.链接.描述信息,还可以包含发 ...
- asp.net -mvc框架复习(2)-创建ASP.NET MVC 第一个程序以及MVC项目文件夹说明
建议vs2013或2013以上版本的vs,要是跨平台的话最好用vs2015或vs2017的asp.net mvc core . 1.创建ASP.NET MVC 第一个程序 打开vs2013->文 ...
- 二 ASP.NET MVC 第一个程序 hello world
二 ASP.NET MVC 第一个程序 hello world https://blog.csdn.net/xmroom/article/details/51335917 我使用的Visual s ...
- 对ASP.NET 5和ASP.NET MVC 6应用程序进行集成测试
(此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 题记:之前有文章谈到如何对ASP.NET 5的应用程序进行单元测试(需使用xunit),今天 ...
- ASP.NET MVC 4应用程序文件夹
App_Start It has configuration classes to reduce clutter code in the Global.asax 它包含了配置类来减少在Global.a ...
- Asp.net MVC学习--默认程序结构、工作流程
二.MVC 默认程序结构 MVC新建好之后,会对应的出现几个包,分别是:Controller.Model.View --即MVC 其中的默认的Default.aspx文件可以方便url重写,如果不设置 ...
- asp.net mvc或者其他程序无法打开excel——解决方案,C#处理Excel文件
问题描述:今天处理Excel时遇到一个问题,本地使用Microsoft.Jet.OLEDB.4.0处理,正常完成了需求, 上传到服务器后发生了异常,通过排查发现问题出现在对Excel文件的读取上,然后 ...
- ASP.NET MVC 5 03 - 安装MVC5并创建第一个应用程序
不知不觉 又逢年底, 穷的钞票 所剩无几. 朋友圈里 各种装逼, 抹抹眼泪 MVC 继续走起.. 本系列纯属学习笔记,如果哪里有错误或遗漏的地方,希望大家高调指出,当然,我肯定不会低调改正的.(开个小 ...
随机推荐
- spring知识大全(3)
4 Spring对持久层的支持 Spring对持久层的支持:① JDBC,② O/R Mapping(Hibernate,TopLink等) 一.Spring对持久层支持采用的策略: 1.Spring ...
- redis五种数据类型的使用(zz)
redis五种数据类型的使用 redis五种数据类型的使用 (摘自:http://tech.it168.com/a2011/0818/1234/000001234478_all.shtml ) 1.S ...
- heap c++ 操作 大顶堆、小顶堆
在C++中,虽然堆不像 vector, set 之类的有已经实现的数据结构,但是在 algorithm.h 中实现了一些相关的模板函数.下面是一些示例应用 http://www.cplusplus.c ...
- Map中的entry
是java中的一个对象,一般可以通过map.entrySet()得到.1,entrySet实现了Set接口,里面存放的是键值对.一个K对应一个V.2,用来遍历map的一种方法.Set<Map.E ...
- VS2013无调试信息
Debug模式,运行时完全正常,但是一调试就出现对话框,显示出错信息: "无法找到"XXX.exe"的调试信息,或者调试信息不匹配.未使用调试信息生成二进制文件.&quo ...
- JavaScript 中 申明变量的方式--let 语句
let 语句 - 声明一个块范围变量. 语法 let 变量名 = 初始化值; 例子 "use strict"; let name = '赵敏'; (function opt(){ ...
- bond配置
Bonding的模式一共有7种: #defineBOND_MODE_ROUNDROBIN 0 (balance-rr模式)网卡的负载均衡模式 #defineBOND_MODE_ACTI ...
- 【转】Python中的赋值、浅拷贝、深拷贝介绍
这篇文章主要介绍了Python中的赋值.浅拷贝.深拷贝介绍,Python中也分为简单赋值.浅拷贝.深拷贝这几种"拷贝"方式,需要的朋友可以参考下 和很多语言一样,Python中 ...
- ExtJs 3.0 动态生成 CheckBox
在开发过程中,往往需要利用数据动态生成Checkbox.如权限节点.考试答案,调查选项等等.在Extjs中,有两种方法来获取后台数据,一是Ext.Ajax()方法,第二种是利用 Store,store ...
- ubuntu下面mysql,通过载入txt文件初始化数据表
环境:ubuntu12.04 mysql(通过apt安装) (1)根据数据表中的属性列,对应在txt中构造记录(一行对应一条记录),不同属性之间通过tab键(以/root目录下构建的init.tx ...