报名参加CloudWeGo黑客松,奖金直推双丰收! 了解详情
写点什么

使用 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:502535
用户头像

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

关注

评论

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

ElasticSearch从入门到精通:数据导入

Jackpop

攻防演练中的防泄露全家福

穿过生命散发芬芳

6月月更 防泄露

一次革命、两股力量、三大环节:《工业能效提升行动计划》背后的“减碳”路线图

脑极体

程序员女友给我做了一个疲劳驾驶检测

华为云开发者联盟

人工智能 疲劳驾驶检测

为什么越来越多的人选择云渲染?

Finovy Cloud

服务器 渲染 云渲染

为什么一定要从DevOps走向BizDevOps?

阿里云云效

阿里云 DevOps 研发 BizDevOps

学习总结

ASCE

Windbg调试工具介绍

dvlinker

c++ windbg 调试工具

HashMap分析-扩容

zarmnosaj

6月月更

什么是反向代理?Nginx反向代理如何配置?

wljslmz

nginx 反向代理 6月月更

全技术栈、全场景、全角色云原生系列培训重磅首发,助力企业打造硬核云原生技术团队

York

容器 云原生 IT建设 技术培训 开发运维

居家办公没有“血泪史”| 社区征文

穿过生命散发芬芳

居家办公 6月月更 初夏征文

激发新动能 多地发力数字经济

CECBC

“信任机器”为发展赋能

CECBC

设计电商秒杀系统

流火

盘点华为云GaussDB(for Redis)六大秒级能力

华为云开发者联盟

数据库 后端 华为云

做一个 Scrollbar 的思考

cssghost

全文手敲代码,教你用Java实现扫雷小游戏

华为云开发者联盟

Java

数字货币:影响深远的创新

CECBC

远程办公期间,项目小组微信群打卡 | 社区征文

IT蜗壳-Tango

6月月更 初夏征文

电商秒杀系统

Dean.Zhang

leetcode 474. Ones and Zeroes 一和零(中等)

okokabcd

LeetCode 动态规划 算法与数据结构

如何使用物联网低代码平台进行服务管理?

AIRIOT

低代码 物联网 低代码开发平台 低代码,项目开发

实践GoF的23种设计模式:装饰者模式

华为云开发者联盟

开发 对象 装饰者模式

毕业设计

ASCE

元宇宙可能成为互联网发展的新方向

CECBC

ElasticSearch从入门到精通:基础知识

Jackpop

NLP 论文领读|文本生成模型退化怎么办?SimCTG 告诉你答案

澜舟孟子开源社区

人工智能 自然语言处理 机器学习 nlp 文本生成

ElasticSearch从入门到精通:Logstash妙用

Jackpop

ElasticSearch从入门到精通:常用操作

Jackpop

开源实习经验分享:openEuler软件包加固测试

openEuler

开源 操作系统 部署 openEuler 实习

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