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控件来显示数据图,这只是一个简单的程序,我们还有很大的改善空间,提供一个内容丰富和功能强大的程序是每个程序员的目标。

参考

 

Demo

更新:08/02/2013

ASP.NET MVC实现仪表程序的更多相关文章

  1. ASP.NET MVC - 探究应用程序文件夹

    为了学习 ASP.NET MVC,我们将构建一个 Internet 应用程序. 第 2 部分:探究应用程序文件夹. MVC 文件夹 一个典型的 ASP.NET MVC Web 应用程序的文件夹内容如下 ...

  2. 在 ASP.NET MVC Web 应用程序中输出 RSS Feeds

    RSS全称Really Simple Syndication.一些更新频率较高的网站可以通过RSS让订阅者快速获取更新信息.RSS文档需遵守XML规范的,其中必需包含标题.链接.描述信息,还可以包含发 ...

  3. asp.net -mvc框架复习(2)-创建ASP.NET MVC 第一个程序以及MVC项目文件夹说明

    建议vs2013或2013以上版本的vs,要是跨平台的话最好用vs2015或vs2017的asp.net mvc core . 1.创建ASP.NET MVC 第一个程序 打开vs2013->文 ...

  4. 二 ASP.NET MVC 第一个程序 hello world

    二 ASP.NET MVC 第一个程序 hello world   https://blog.csdn.net/xmroom/article/details/51335917 我使用的Visual s ...

  5. 对ASP.NET 5和ASP.NET MVC 6应用程序进行集成测试

    (此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 题记:之前有文章谈到如何对ASP.NET 5的应用程序进行单元测试(需使用xunit),今天 ...

  6. ASP.NET MVC 4应用程序文件夹

    App_Start It has configuration classes to reduce clutter code in the Global.asax 它包含了配置类来减少在Global.a ...

  7. Asp.net MVC学习--默认程序结构、工作流程

    二.MVC 默认程序结构 MVC新建好之后,会对应的出现几个包,分别是:Controller.Model.View --即MVC 其中的默认的Default.aspx文件可以方便url重写,如果不设置 ...

  8. asp.net mvc或者其他程序无法打开excel——解决方案,C#处理Excel文件

    问题描述:今天处理Excel时遇到一个问题,本地使用Microsoft.Jet.OLEDB.4.0处理,正常完成了需求, 上传到服务器后发生了异常,通过排查发现问题出现在对Excel文件的读取上,然后 ...

  9. ASP.NET MVC 5 03 - 安装MVC5并创建第一个应用程序

    不知不觉 又逢年底, 穷的钞票 所剩无几. 朋友圈里 各种装逼, 抹抹眼泪 MVC 继续走起.. 本系列纯属学习笔记,如果哪里有错误或遗漏的地方,希望大家高调指出,当然,我肯定不会低调改正的.(开个小 ...

随机推荐

  1. 原生JS中apply()方法的一个值得注意的用法

    今天在学习vue.js的render时,遇到需要重复构造多个同类型对象的问题,在这里发现原生JS中apply()方法的一个特殊的用法: var ary = Array.apply(null, { &q ...

  2. Ruby:字符串处理函数

    字符串处理函数1.返回字符串的长度 str.length => integer 2.判断字符串中是否包含另一个串 str.include? other_str => true or fal ...

  3. 在Linux上安装最新版java的JDK

    之前写过一篇关于MC建服的文章(http://www.cnblogs.com/apollospotatolikett/p/6149042.html),文章中使用的JDK不是最新的版本,当时没有细说如何 ...

  4. Hibernate-list()与iterate()方法的区别

    对于list方法而言,实际上Hibernate是通过一条Select SQL获取所有的记录.并将其读出,填入到POJO中返回.而iterate 方法,则是首先通过一条Select SQL 获取所有符合 ...

  5. Github 新的项目管理模式——Projects

    Github 新的项目管理模式--Projects Issues Github 中传统的项目管理是使用 issue 和 pull request 进行的,这部分内容不是本文重点,不再赘述. 但有一些功 ...

  6. GIT FLOW 时序图

    git flow sequence md link: git branching model master->master branch: use default branch Note rig ...

  7. storm入门(二):关于storm中某一段时间内topN的计算入门

    刚刚接触storm 对于滑动窗口的topN复杂模型有一些不理解,通过阅读其他的博客发现有两篇关于topN的非滑动窗口的介绍.然后转载过来. 下面是第一种: Storm的另一种常见模式是对流式数据进行所 ...

  8. 基于Axure的快速原型方法

    Axure是一个专业的快速原型设计工具,让负责定义需求和规格.设计功能和界面的专家能够快速创建应用软件或Web网站的线框图.流程图.原型和规格说明文档.作为专业的原型设计工具,它能快速.高效的创建原型 ...

  9. 每天记一些php函数,jQuery函数和linux命令(二)

    简介:学习完了php和jQuery之后,对函数的记忆不到位,导致很多函数没记住,所以为了促进自己的记忆,每天花一点时间来写这个博客. 时间:2016-12-19   地点:太原    天气:晴 一.p ...

  10. inno 实现水波特效

    安装Inno Setup时如果选择了水波效果插件(如下图),将在Inno Setup的安装目录下自带有水波特效的例子,如路径:C:\Program Files (x86)\Inno Setup 5\E ...