使用 AngularJS、Web API 和 Json 的 Flot 图表
使用 Web API 和 Json 绘制 Flot 图表
引言
我当时正在评估用于我项目的 JavaScript 图表框架。我发现了 jQuery Flot 库,它支持各种图表。在本文中,我尝试使用 jQuery Flot 库绘制一个多时间轴图表。它使用 ASP.NET Web API 从数据库获取数据。我遇到的问题是获取数据,数据的格式必须能够绑定到 Flot 图表。我不得不对 Json 数据进行大量尝试,最终才使其与 Flot 一起工作。
使用代码
让我解释一下这个场景。需求是显示票务数据 - 一个月内收到的总票数、当月解决的总票数、当月未决的总票数。这些数据需要在单个具有多个轴的图表上绘制。代码分为三个部分
1. 数据库
2. WebAPI
3. 用于显示图表的 Angular JS 客户端应用程序
Web API 和 Angular JS 客户端应用程序是独立的 Visual Studio 解决方案。我这样做是为了了解如何启用 CORS。
首先,我们将了解数据库对象。数据存储在一个表中,并在其顶部创建一个视图以获取数据。
表脚本
CREATE TABLE [dbo].[Tickets1](
[TicketId] [int] NOT NULL,
[CreationDate] [datetime] NOT NULL,
[TicketStatus] [smallint] NOT NULL,
[ResolvedDate] [datetime] NULL,
CONSTRAINT [PK_Tickets1] PRIMARY KEY CLUSTERED
( [TicketId] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON)
ON [PRIMARY]
) ON [PRIMARY]
GO
视图脚本
CREATE VIEW [dbo].[MonthWiseTickets]
AS
SELECT newid() AS Id, MonthYear,
[1] AS ResolvedTickets, [0] AS OpenTickets, [1] + [0] AS TotalTickets
FROM (SELECT CAST(YEAR(creationdate) AS VARCHAR(4)) + '-' + CONVERT(varchar(2),
creationdate, 101) + '-'+
'01' AS MonthYear, creationdate, TicketStatus
FROM Tickets1) up PIVOT (Count(CreationDate) FOR TicketStatus IN ([1], [0])) AS pvt
上述视图以以下格式给出输出
我们的数据库现在已设置好,接下来我们创建一个 Web API 从数据库获取数据。因此,我们直接使用 Visual Studio 创建一个 Web API 项目。
Web API
该项目的基本结构如下。首先,我们将创建模型类,然后启用 CORS,然后创建控制器以从数据库获取数据。
我们在 Models 文件夹内创建一个 Model Tickets.cs,它将表示 SQL 视图的字段。
public class Ticket
{
public string Id { get; set; }
public string MonthYear { get; set; }
public int ResolvedTickets { get; set; }
public int OpenTickets { get; set; }
public int TotalTickets { get; set; }
}
然后我们需要启用 CORS,以便客户端应用程序可以调用 Web API。为此,我们需要从 NuGet 安装 CORS 包。完成后,打开 WebApiConfig.cs 并添加以下代码行。
// Web API configuration and services
config.EnableCors();
现在我们需要创建一个控制器来调用数据库中的视图。我们添加一个新的控制器文件 FlotChartController。以下是控制器的代码,注意第一行,我们在其中为客户端应用程序启用 CORS。
然后我们使用 ADO.NET 使用命令对象调用 SQL 视图。
[EnableCors(origins: "https://:52306", headers: "*", methods: "*")]
public class FlotChartController : ApiController
{
public dynamic Get()
{
List<Ticket> Tickets = new List<Ticket>();
ConnectionStringSettings settings = ConfigurationManager.ConnectionStrings["charts"];
using (SqlConnection con =
new SqlConnection(settings.ConnectionString.ToString()))
{
SqlCommand cmd = con.CreateCommand();
cmd.CommandText = "Select * From MonthWiseTickets order by CONVERT(datetime,monthyear)";
cmd.CommandTimeout = 120;
cmd.CommandType = CommandType.Text;
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
Ticket ticket = new Ticket();
ticket.Id = reader.GetGuid(0).ToString();
ticket.MonthYear = reader.GetString(1);
ticket.ResolvedTickets = reader.GetInt32(2);
ticket.OpenTickets = reader.GetInt32(3);
ticket.TotalTickets = reader.GetInt32(4);
Tickets.Add(ticket);
}
}
var ret = new[] {
new { label="Open Tickets", data = Tickets.Select(x=>new string[]{ x.MonthYear, x.OpenTickets.ToString() })},
new { label="Resolved Tickets", data = Tickets.Select(x=>new string[]{ x.MonthYear, x.ResolvedTickets.ToString() })},
new { label="Total Tickets", data = Tickets.Select(x=>new string[]{ x.MonthYear, x.TotalTickets.ToString() })},
};
return ret;
}
}
现在我们的服务器组件已准备就绪,我们现在需要创建客户端应用程序来使用 Web API。在下一节中,我们将看到如何设置 AngularJS 客户端应用程序。
AngularJS
以下是设置客户端应用程序所需库的步骤
1. 在 Visual Studio 中创建一个空的 ASP.NET 项目
2. 添加 jQuery、AngularJS 和 Flot 的 Nuget 包
3. 添加 Angular Flot 的模块
这是添加这些库后您的解决方案的样子。
现在在项目中添加一个名为 App 的文件夹,并添加两个子文件夹 Controllers 和 Services。
现在让我们开始添加一些代码,创建一个 app.js 文件并添加以下代码。当 index 页面加载时,这将实例化我们的应用程序。
var app = angular.module('MorrisApp', ['ngRoute', 'angular-flot']); var serviceBase = 'https://:51419/'; app.constant('ngAuthSettings', { apiServiceBaseUri: serviceBase, });
在 services 文件夹下添加 flotService.js 文件,这将调用我们之前创建的 Web API。
'use strict'; app.factory('flotService', ['$http', 'ngAuthSettings', function ($http, ngAuthSettings) { var serviceBase = ngAuthSettings.apiServiceBaseUri; var flotServiceFactory = {}; var _getMonthlyTicketsSummary = function () { return $http.get(serviceBase + 'api/FlotChart').then(function (results) { return results; }); }; flotServiceFactory.getMonthlyTicketsSummary = _getMonthlyTicketsSummary; return flotServiceFactory; }]);
现在是编写控制器以调用服务并绘制图表的主要部分。
app.controller('FlotCtrlJson', ['$scope', 'flotService', function ($scope, flotService) { //declare an array for month names to be dispaled on the x axis var monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] // generate the tool tip function getTooltip(label, x, y) { var date = new Date(x) return label + " for " + monthNames[date.getMonth()] + " " + date.getFullYear() + " are " + y; } // set options for the flot graph $scope.options = { legend: { container: "#legendjson", show: true, noColumns: 3, }, axisLabels: { show: true }, xaxis: { mode: "time", minTickSize: [1, "month"], timeformat: " %b %y", axisLabel: "Month", monthNames: monthNames, //ticks: [[1,"Jan"],[2,"Feb"]] }, yaxes: [{ position: "left", axisLabel: "Total Tickets", axisLabelUseCanvas: true, axisLabelColour: "rgb(2,198,137)" }, { position: "right", axisLabel: "Overdue Tickets", axisLabelUseCanvas: true, axisLabelColour: "#FF0000" }, { position: "right", axisLabel: "Resolved Tickets", axisLabelUseCanvas: true, axisLabelColour: "#0062FF" }, ], grid: { hoverable: true //IMPORTANT! this is needed for tooltip to work }, tooltip: true, tooltipOpts: { content: getTooltip } }; //var data3 = [[1420050600000, 6], [1422729000000, 5]]; // call the service to get the data in JSON format flotService.getMonthlyTicketsSummary().then(function (results) { // debugger; var monthlyTicketsSummary = results.data; var totalTickets = monthlyTicketsSummary[2].data; var totalOverdueTickets = monthlyTicketsSummary[0].data; var totalCompletedTickets = monthlyTicketsSummary[1].data; var data6 = []; var data7 = []; var data8 = []; // alert(new Date("2015-01-01").getTime()) for (j = 0; j < totalTickets.length; j++) { var i = totalTickets[j].toString(); data5 = i.split(","); data6 = data6 + "[" + new Date(data5[0]).getTime() + "," + data5[1] + "]" + "," //data6[j] = "[5,10]" } data6 = JSON.parse("[" + data6.substring(0, data6.length - 1) + "]"); for (j = 0; j < totalOverdueTickets.length; j++) { var i = totalOverdueTickets[j].toString(); data5 = i.split(","); data7 = data7 + "[" + new Date(data5[0]).getTime() + "," + data5[1] + "]" + "," //data6[j] = "[5,10]" } data7 = JSON.parse("[" + data7.substring(0, data7.length - 1) + "]"); for (j = 0; j < totalCompletedTickets.length; j++) { var i = totalCompletedTickets[j].toString(); data5 = i.split(","); data8 = data8 + "[" + new Date(data5[0]).getTime() + "," + data5[1] + "]" + "," //data6[j] = "[5,10]" } data8 = JSON.parse("[" + data8.substring(0, data8.length - 1) + "]"); // set the data to be plotted on different y axes $scope.dataset = [{ data: data6, label: 'Total Tickets', color: "rgb(2,198,137)", bars: { show: true, barWidth: 24 * 60 * 60 * 6000, lineWidth: 1, align: "center", } }, { data: data7, label: ['Total Overdue Tickets'], yaxis: 2, color: "#FF0000", lines: { show: true, }, points: { fillColor: "#FF0000", symbol: "triangle", show: true, } }, { data: data8, label: ['Total Resolved Tickets'], yaxis: 3, color: "#0062FF", lines: { show: true, }, points: { fillColor: "#0062FF", symbol: "diamond", show: true, } }, ]; } , function (error) { alert(error.data); } ); }]);
现在一切就绪,我们只需运行我们的 API 项目,然后从 Visual Studio 运行 Angular 项目。
关注点
我真的不得不花时间来弄清楚如何将我从 JSON 中获取的日期转换为 Flot 库理解的格式。