写点什么

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

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

关注

评论

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

火山引擎ByteHouse:一套方案,让OLAP引擎在精准投放场景更高效

字节跳动数据平台

大数据 云原生 Clickhouse 企业号 8 月 PK 榜

利用CI机制管控jar依赖树 | 京东云技术团队

京东科技开发者

ci CI/CD jar包 企业号 8 月 PK 榜

RPA+智能问答实现微信端智能客服 | 京东云技术团队

京东科技开发者

微信 RPA 智能客服 企业号 8 月 PK 榜

深入理解 Flutter 图片加载原理 | 京东云技术团队

京东科技开发者

flutter 移动开发 图片懒加载 企业号 8 月 PK 榜

LED小间距屏幕的COB封装技术应用和优势

Dylan

技术 封装 PCB LED显示屏

OTP令牌是什么?有什么作用?是怎么实现的?

行云管家

运维 堡垒机 双因子认证 OTP令牌

数仓备份经验分享丨详解roach备份原理及问题处理套路

华为云开发者联盟

数据库 后端 华为云 华为云开发者联盟 企业号 8 月 PK 榜

软件测试丨Chrome 115之后的版本,如何更新driver?

测试人

chrome 程序员 软件测试 自动化测试 chromedriver

ABAQUS正版授权软件怎么下载?达索中国代理商思茂信息

思茂信息

abaqus abaqus软件 有限元仿真技术 有限元分析 结构仿真

电商小程序微服务架构

艾瑾行

架构训练营

透彻理解 Axios Blob 的使用与优化

Apifox

性能优化 后端 HTTP API web开发

前端合成海报并保存到本地

南城FE

JavaScript 小程序 前端 图片合成

ARM64是什么意思?与x86有什么区别?

行云管家

arm64

快手光合大会公开全模态大模型AIGC解决方案 人机协同助力创作全流程提效

Geek老T

AI 短视频

十问Huawei Cloud Toolkit:开发插件如何提升云上开发效能

华为云开发者联盟

ide 开发 华为云 华为云开发者联盟 企业号 8 月 PK 榜

chatglm2-6b模型在9n-triton中部署并集成至langchain实践 | 京东云技术团队

京东科技开发者

人工智能 #LangChain langchain 企业号 8 月 PK 榜 ChatGLM2-6B

开源XL-LightHouse与Flink、ClickHouse之类技术相比有什么优势

feng

大数据 flink Clickhouse 流式计算 流式统计

AI 自动开发软件并部署到云服务器,DevOpsGPT实现从自然语言需求到可运行的软件!

booboosui

AI Codec AI开发软件 ChatGPT

晋级名单公布!“域见杯”复赛今日火热开启

华为云开发者联盟

人工智能 华为云 华为云开发者联盟 企业号 8 月 PK 榜

关于跨国文件传输需要了解的5点

镭速

跨国文件传输

食品包装MES系统解决方案

万界星空科技

MES系统

小白都会的数据可视化大屏搭建,速来学习

华为云开发者联盟

开发 开发工具 华为云 华为云开发者联盟 企业号 8 月 PK 榜

低代码实现探索(五十九)SAP底层技术研究

零道云-混合式低代码平台

大容量文件传输的高速传输协议解决方案评估与比较

镭速

大文件传输 大容量文件传输

你可以信任由编译器优化的代码吗?

互联网工科生

编译器 simd 数据流

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