OceaBase开发者大会落地上海!4月20日共同探索数据库前沿趋势!报名戳 了解详情
写点什么

使用 shieldUI Chart 控件在 ASP.NET 和 MVC 应用程序中创建一个销售仪表板

  • 2013-12-11
  • 本文字数:7500 字

    阅读完需:约 25 分钟

本文中,我们将处理一个常见的数据可视化任务,即创建一个销售仪表板(dashboard)。在商业演示中经常会使用销售仪表板来展现某个商业流程或商业目标的关键绩效指标,而完成这样一个演示的关键不仅在于对数据进行良好的可视化展示,还要有赏心悦目的外观。为了完成这一任务,我会使用相关的图表组件,它提供了全部的所需功能。这个示例中将使用 ShieldUI 中的图表组件,这一系列产品可以从网站的免费下载。

完成后的展示请见下图:

(点击图像放大)

本示例将使用ASP.NET 与MVC 两种方式讲解。

使用代码

ASP.NET 版本

我首先建立一个 Visual Studio 的 web 项目,这个 web 应用包含一个单独的.aspx 文件,其中包含了相关的控件。第二步则是将图表组件所在的.dll 文件加入当前项目:

将组件所在的.dll 文件加入项目之后,我们还需要在项目中引用它。可以直接在.aspx 页面中完成,请见下面的示例:

复制代码
<%@ Register Assembly="Shield.Web.UI"
Namespace="Shield.Web.UI" TagPrefix="shield" %>

因为这个控件其实是对一个客户端 JavaScript 组件的服务端封装,我们还需要引用基础的 JavaScript 图表文件,同样也在.aspx 文件中完成:

复制代码
<head>
<link rel="stylesheet" type="text/css"
href="shield-chart.1.2.2-Trial/shield-chart.1.2.2-Trial/css/shield-chart.min.css"/>
<script src="shield-chart.1.2.2-Trial/shield-chart.1.2.2-Trial/js/jquery-1.9.1.min.js"
type="text/javascript"></script>
<script src="shield-chart.1.2.2-Trial/shield-chart.1.2.2-Trial/js/shield-chart.all.min.js"
type="text/javascript"></script>
</head>

接下来就是要将需求转化为代码了,需求中表示我们需要两个或者更多的图表。在这个示例中,我们将使用一个图表显示所有的季度,另外用一个图表显示每个季度的相关数据,最后还有一个图表与第二个图表相关联。这样,我们就可以按照季度和产品线进行分类,这对于销售仪表板来说是一种常见的数据可视化场景。按照以上所概括的步骤,让我们首先将第一个图表加入.aspx 文件中。它的声明部分如下所示:

复制代码
<asp:UpdatePanel ID="UpdatePanel2" runat="server" UpdateMode="Conditional"
ChildrenAsTriggers="false">
<ContentTemplate>
<shield:ShieldChart ID="ShieldChart1" runat="server" AutoPostBack="true"
OnSelectionChanged="ShieldChart1_SelectionChanged" Width="320px" Height="330px"
OnTakeDataSource="ShieldChart1_TakeDataSource">
<PrimaryHeader Text="Quarterly Sales">
</PrimaryHeader>
<ExportOptions AllowExportToImage="false" AllowPrint="false" />
<TooltipSettings CustomPointText="Sales Volume: <b>{point.y}</b>">
</TooltipSettings>
<Axes>
<shield:ChartAxisX CategoricalValuesField="Quarter">
</shield:ChartAxisX>
<shield:ChartAxisY>
<Title Text="Quarter verview"></Title>
</shield:ChartAxisY>
</Axes>
<DataSeries>
<shield:ChartBarSeries DataFieldY="Sales">
<Settings EnablePointSelection="true" EnableAnimation="true">
<DataPointText BorderWidth="">
</DataPointText>
</Settings>
</shield:ChartBarSeries>
</DataSeries>
<Legend Align="Center" BorderWidth=""></Legend>
</shield:ShieldChart>
</ContentTemplate>
</asp:UpdatePanel>

这里用一个 update panel 将控件包装起来,以提供更平滑的视觉上的更新。

为了将数据加载到图表控件中,我们利用了 TakeDataSource 这个事件处理器,以下是.aspx 文件的 code behind 中的部分代码:

复制代码
protected void ShieldChart1_TakeDataSource(object sender,Shield.Web.UI.
ChartTakeDataSourceEventArgs e)
{
ShieldChart1.DataSource = new object[]
{
new {Quarter = "Q1", Sales = 312 },
new {Quarter = "Q2", Sales = 212 },
new {Quarter = "Q3", Sales = 322 },
new {Quarter = "Q4", Sales = 128 }
};
}

控件的 DataSource 属性告诉了图表需要传递给它以实现可视化的数据是什么。我们传入了一个简单的对象数组,它包含了每个季度的销售数据,这样图表就可以表现出每个季度的数据了。接下来将第二个相关的图表也加入.aspx 文件中,看起来是这样的:

复制代码
<div id="container2" style="width: 490px; height: 340px; margin: auto; top: 5px;
left: 5px; position: inherit;">
<asp:UpdatePanel ID="UpdatePanel1" runat="server" pdateMode="Conditional"
ChildrenAsTriggers="false">
<ContentTemplate>
<shield:ShieldChart ID="ShieldChart2" nTakeDataSource="ShieldChart2_
TakeDataSource" AutoPostBack="true"
OnSelectionChanged="ShieldChart2_SelectionChanged" runat="server"
Width="463px" Height="331px">
<ExportOptions AllowExportToImage="false" AllowPrint="false" />
<PrimaryHeader Text="Select a Quarter to show products sales">
</PrimaryHeader>
<Axes>
<shield:ChartAxisY>
<Title Text="Break-Down for selected quarter"></Title>
</shield:ChartAxisY>
</Axes>
<DataSeries>
<shield:ChartDonutSeries EnableValueXSorting="false" ollectionAlias="Q
Data" DataFieldY="Data" DataFieldX="Product">
<Settings EnablePointSelection="true" EnableAnimation="true"
AddToLegend="true">
<DataPointText BorderWidth="">
</DataPointText>
</Settings>
</shield:ChartDonutSeries>
</DataSeries>
<Legend Align="Center" BorderWidth=""></Legend>
</shield:ShieldChart>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="ShieldChart1" EventName="SelectionChanged" />
</Triggers>
</asp:UpdatePanel>
</div>

第一和第二个图表控件都应用了一个被选择的事件处理器,以允许对相关控件进行重建,因为他们各自带有一个子图表。这个项目允许最终用户在“SheidChart1”控件以可视化方式显示的 4 个季度选择一个季度。接下来,对所选中的季度,“ShieldChart”控件会以饼图的方式显示所有可用的数据。用户接下来可以从饼图中选择一个特定的分类,这又载入了第三个图表的数据。它的定义如下所示:

复制代码
<div id="container3_box" style="width: 925px; height: 300px; border: 2px solid #40B3DF;
margin: auto; top: 420px; left: 25px; position: absolute;">
<div id="container3" style="width: 890px; height: 290px; margin: auto; top: 5px;
left: 5px; position: inherit;">
<asp:UpdatePanel ID="UpdatePanel3" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<shield:ShieldChart ID="ShieldChart3" runat="server" nTakeDataSource=
"ShieldChart3_TakeDataSource"
Width="905px" Height="280px">
<DataSeries>
<shield:ChartLineSeries DataFieldY="QuarterSales">
<Settings AddToLegend="false">
<DataPointText BorderWidth="">
</DataPointText>
</Settings>
</shield:ChartLineSeries>
</DataSeries>
<PrimaryHeader Text="Select a product to show sales details...">
</PrimaryHeader>
<ExportOptions AllowExportToImage="false" AllowPrint="false" />
<Legend Align="Center" BorderWidth=""></Legend>
</shield:ShieldChart>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="ShieldChart2" EventName="SelectionChanged" />
</Triggers>
</asp:UpdatePanel>
</div>
</div>

为了允许对子图表进行重建,还需要加入一个额外的步骤。这一步是当图表被选择的事件触发后在服务端完成的,这样就可以避免编写客户端代码了。具体的服务端代码如下所示:

复制代码
protected void ShieldChart1_SelectionChanged(object sender,
ChartSelectionChangedEventArgs e)
{
if (e.Selected)
{
SelectedQuarter = e.Name;
DataPerformance = GetPerformanceData().Where(d => d.Quarter == electedQuarter).
ToList();
}
else
{
DataPerformance = null;
}
ShieldChart2.DataBind();
}
protected void ShieldChart2_SelectionChanged(object sender,
ChartSelectionChangedEventArgs e)
{
if (e.Selected)
{
SalesData = GetSalesDataProducts().Where(s => s.Quarter == SelectedQuarter &&
s.Product == e.Item.ValueX.ToString()).ToList();
}
else
{
SalesData = null;
}
ShieldChart3.DataBind();
}

以上就完成了 ASP.NET 的版本,销售仪表板已经可以使用了。请随意下载该示例代码并作为今后的参考。

MVC 应用程序

这个示例也可以很方便地搭建在 MVC 上。首先建立一个新的 Visual Studio 2012 MV 应用程序,使用.NET Framework 4.0。为了使用图表控件的功能,我在项目中添加了对 Shield.Mvc.UI 这个 dll 文件的引用:

以下是该应用程序的文件夹结构:

接下来我会逐一地讲解每个文件夹中令人感兴趣的部分,并讲述一些代码之外的信息,以及每段代码的重要性。首先从 Views 文件夹开始,它包含了四个不同的视图,三个用来显示图表,另一个则包含主体页面结构。第一个视图是“Layout.cshtml”,它决定了页面的主体结构,并且加入了图表组件与它的封装所需的各种 css 文件与 js 文件的引用。

复制代码
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Sales Dashboard - Shield Chart for ASP.NET MVC</title>
<link rel="stylesheet" type="text/css" href="content/shield-chart.1.2.3-
Trial/css/shield-chart.min.css" />
<script src="content/shield-chart.1.2.3-Trial/js/jquery-1.9.1.min.js"
type="text/javascript"></script>
<script src="content/shield-chart.1.2.3-Trial/js/shield-chart.all.min.js"
type="text/javascript"></script>
<link rel="stylesheet" type="text/css" href="content/css/site.css" />
<script src="content/js/scripts.js" type="text/javascript"></script>
</head>
<body>
<div class="page">
<div class="header">
</div>
<div class="main">
@RenderBody()
</div>
<div class="clear">
</div>
</div>
<div class="footer">
</div>
</body>
</html>

该视图中还包含了一个对“scripts.js”的引用,这个文件包含了客户端事件的处理器,但本文的末尾部分讨论了该文件的更多细节。

下一个视图“Index.cshtml”包含了“季度”图表的定义,这是唯一一个会在初始化页面时就显示的图片,选择这张图表上的某个季度就会加载相应的饼图。这个视图的声明部分包括了设置控件的各种必需属性,例如它的 X 轴与 Y 轴,还有 DataSeries 属性以及实际的数据。其中有趣的一点是“Events”属性,它定义了从条状图中选择某个点之后的事件处理器,这一点对于关联图表与子图表非常关键,当用户从第一张图表中选择了某个季度后,子图表就会显示相应的数据。该页面的代码如下所示:

复制代码
@{
ViewBag.Title = "Sales Dashboard with Shield Chart for ASP.NET MVC";
Layout = "~/Views/Shared/Layout.cshtml";
}
@model IEnumerable<SalesDashboardMVC.Models.QuarterlySales>
<div class="dashboard">
<div class="header">
Sales DashBoard using <span class="highlight">Shield
UI MVC Chart</span>
</div>
<div class="topleft">
@(Html.ShieldChart(Model)
.Name("quarterlySales")
.HtmlAttribute("class", "chart")
.PrimaryHeader(header => header.Text("Quarterly Sales"))
.Export(false)
.Tooltip(tooltip => tooltip.CustomPointText("Sales Volume: <b>{point.y}</b>"))
.AxisX(axisX => axisX.CategoricalValues(model => model.Quarter))
.AxisY(axisY => axisY.Title(title => title.Text("Quarterly Overview")))
.DataSeries(dataSeries => dataSeries
.Bar()
.Data(model => model.Sales)
.EnablePointSelection(true))
.ChartLegend(chartLegend => chartLegend
.Align(Shield.Mvc.UI.Chart.Align.Center))
.Events(events => events.PointSelect("app.quarterSelected")))
</div>
<div class="topright">
</div>
<div class="bottom">
</div>
</div>

当用户从页面初始化时就显示的条状图中选择了某个季度后,第一个子图表就会加载相应的数据,并显示为一个饼图。它的定义包含在“_PerformanceChart.cshtml”视图中,代码如下所示:

复制代码
@model IEnumerable<SalesDashboardMVC.Models.PerformanceData>
@(Html.ShieldChart(Model)
.Name("productsByQuarter")
.HtmlAttribute("class", "chart")
.Export(false)
.PrimaryHeader(header => header.Text("Select a Quarter to show products sales"))
.AxisY(axisY => axisY.Title(title => title.Text("Break-Down for selected quarter")))
.DataSeries(dataSeries => dataSeries
.Donut()
.Name("Q Data")
.Data(model => new
{
collectionAlias = model.Product,
x = model.Product,
y = model.Data,
})
.EnablePointSelection(true)
.AddToLegend(true))
.ChartLegend(chartLegend => chartLegend.Align(Shield.Mvc.UI.Chart.Align.Center))
.Events(events => events.PointSelect("app.productSelected")))

当用户选择了饼图里的某一项之后,就会加载数据并显示最后一张图表。它的代码包含在“_SalesDetailsChart.cshtml”文件中,具体定义如下:

复制代码
@model IEnumerable<SalesDashboardMVC.Models.SalesByProduct>
@(Html.ShieldChart(Model)
.Name("salesDetails")
.HtmlAttribute("class", "chart")
.PrimaryHeader(header => header.Text("Select a product to show sales details"))
.Export(false)
.DataSeries(dataSeries => dataSeries
.Line()
.Data(model => model.QuarterSales)
.AddToLegend(false)))

“Models”文件夹包含了数据的模型,它将用以加载三个不同的图表。举例来说,首个图表将对应类型“QuarterlySales”中的数据,它的代码如下:

复制代码
namespace SalesDashboardMVC.Models
{
public class QuarterlySales
{
public string Quarter { get; set; }
public decimal Sales { get; set; }
public static IEnumerable<QuarterlySales> GetData()
{
yield return new QuarterlySales() { Quarter = "Q1", Sales = 312 };
yield return new QuarterlySales() { Quarter = "Q2", Sales = 212 };
yield return new QuarterlySales() { Quarter = "Q3", Sales = 322 };
yield return new QuarterlySales() { Quarter = "Q4", Sales = 128 };
}
}

其它图表也将对应类似的数据类,我在这里就略过不提了。“Controllers”文件夹包含了一个单独的控制器,它将响应图表的选择所对应的各种行为。代码如下:

复制代码
public class HomeController: Controller
{
//
// GET: /Home/
public ActionResult Index()
{
return View(QuarterlySales.GetData());
}
public ActionResult Performance(string quarter)
{
return View("_PerformanceChart",
PerformanceData.GetDataByQuarter(quarter));
}
public ActionResult Details(string product, string quarter)
{
return View("_SalesDetailsChart", alesByProduct.
GetDataByProductAndQuarter(product, quarter));
}
}

有一段重要的代码需要引起注意,那就是“Content”文件夹下的“scripts.js”文件。从以上的代码声明可以看出,第一与第二个图表包括了选择事件的处理器。这些处理器将处理客户端的事件,这是由用户在条状图或饼图中选择了一段数据所触发的,而“scripts.js”文件则包含了这些事件的客户端处理器,它的代码如下:

复制代码
(function (jQuery) {
this.app = {
quarter: "",
quarterSelected: function (e) {
var quarter = app.quarter = e.point.name;
$(".topright").load("/performance/" + quarter);
$(".bottom").empty();
},
productSelected: function (e) {
var product = e.point.x,
quarter = app.quarter;
$(".bottom").load("/details/" + product + "/" + quarter);
}
};
}).call(this, jQuery);

实质上,这段代码会发起一个 Ajax 请求,它将处理被选择的数据,而这是由方法的参数中传递的。该请求将触发“Performance”或者“Details”的行为处理器,它们都由“HomeController”中的控制器所定义。

我们的代码中最主要的部分到这里差不多就介绍完了,完整的代码和一个可运行的项目都可以在这里下载。

关于作者

David Johnson来自于英国伦敦,他已经是一位 37 岁的“老”程序员了。过去的 15 年来他主要工作于 web 技术的领域,而过去 10 年中他主要专注于 ASP.NET 和 MVC 平台。David 作为一名外包开发者参与了许多项目,最近的职位是在 ShieldUI 担任首席开发者。

查看英文原文: Creating a sales dashboard for ASP.NET and MVC with ShieldUI Chart

2013-12-11 21:502243
用户头像

发布了 428 篇内容, 共 171.9 次阅读, 收获喜欢 38 次。

关注

评论

发布
暂无评论
发现更多内容

对标小程序 _ _快应用_开发入门指南,移动应用开发课程设计

android 程序员 移动开发

巧用Android网络通信技术,在网络上直接传输对象,android设计模式总结

android 程序员 移动开发

应聘腾讯,面试官和我聊了一个小时的人生,flutterrow换行

android 程序员 移动开发

学习不系统学过的Android知识全忘记了?思维导图+手写笔记

android 程序员 移动开发

安卓11重磅上线,快来看看,是不是熟悉的配方,大专生面试阿里P7居然过了

android 程序员 移动开发

安卓指纹对称加密及登录功能的实现,阿里P8大牛从零开始教Android开源框架

android 程序员 移动开发

工作出现瓶颈,学习效率下降?通学这份Android进阶知识体系

android 程序员 移动开发

干货来袭-通过这份Android-中高级架构师教学资料(全套)在公司大裁员下

android 程序员 移动开发

字节面试官:看了3000多份简历,面试1000场后,androidjni开发书籍

android 程序员 移动开发

学习 View 事件分发,就像外地人上了黑车!(1),kotlin安卓开发书籍

android 程序员 移动开发

实现Flutter离线验证码组件,跳槽面试大厂被拒

android 程序员 移动开发

巧用Android网络通信技术,在网络上直接传输对象(2),android开发入门基础教程

android 程序员 移动开发

已经说过千万遍了!!面试官,一线互联网大厂中高级Android面试真题收录

android 程序员 移动开发

巧用Android网络通信技术,在网络上直接传输对象 (1),安卓面试题宝典app

android 程序员 移动开发

带你一起探究Android事件分发机制,-让面试提问不在畏惧!

android 程序员 移动开发

年后想跳槽涨薪?你想要的面试题全在这里,activity事件分发

android 程序员 移动开发

屌丝的眼泪,因为错过的初恋,才搞清楚PNG图片压缩原理(1)

android 程序员 移动开发

底层图像处理之微信32Kb图片压缩方案-(二),android双击事件响应

android 程序员 移动开发

学习 View 事件分发,就像外地人上了黑车!,真的已经讲烂了

android 程序员 移动开发

安卓指纹对称加密及登录功能的实现(1),技术实现

android 程序员 移动开发

屌丝的眼泪,因为错过的初恋,才搞清楚PNG图片压缩原理

android 程序员 移动开发

年终总结攻略|3个步骤,让老板给你的工作汇报点赞,2021Android精选面试实战总结整理

android 程序员 移动开发

底层学习---Android-IPC机制(二)序列化机制,张口就来

android 程序员 移动开发

字节跳动正式启动2021届秋季校招!这份字节跳动历年校招Android面试真题解析,你确定不收藏

android 程序员 移动开发

字节跳动面试,第三面挂了,这原因我服了,快速上手

android 程序员 移动开发

孽缘啊,同套面试题中午我把你挂了,晚上你把我挂了,农民工看完都会了

android 程序员 移动开发

学会这些Android开发热门前沿知识,2020年你就不用愁了!

android 程序员 移动开发

完美!腾讯技术官发布Android零基础就业宝典,不用再怀疑人生了

android 程序员 移动开发

小厂开发五年,成功入职腾讯,这是我的复盘和总结,阿里P8Android架构师谈

android 程序员 移动开发

巧用Android网络通信技术,在网络上直接传输对象(1),讲的真详细

android 程序员 移动开发

已拿字节、腾讯、墨墨 offer,【面试总结

android 程序员 移动开发

使用shieldUI Chart控件在ASP.NET和MVC应用程序中创建一个销售仪表板_语言 & 开发_David Johnson_InfoQ精选文章