动态 Highcharts – ASP.NET Core, Angular6





5.00/5 (7投票s)
在本文中,我们将使用 Angular6 和 ASP.NET Core 实现动态 Highchart。
引言
在前一篇文章中,我们探讨了如何使用 ASP.NET Core 和 Angular 从零开始构建一个单页应用程序 (SPA)。
基于之前的文章,本文将扩展以实现图表功能。我们将通过从 github 下载完整的源代码来修改/扩展现有的示例应用程序。
现在开始,打开现有应用程序,首先,我们将向应用程序添加包。
安装 Node 包
让我们向应用程序添加前端包。我们需要修改 package.json 文件。打开 package.json 文件,然后添加下方列出的依赖项。
依赖项
"angular-highcharts": "^6.2.6",
"highcharts": "^6.1.1"
开发依赖
"@types/highcharts": "^5.0.22",
这是我们的前端包依赖列表。
{
"version": "1.0.0",
"name": "asp.net",
"private": true,
"dependencies": {
"@angular/common": "^6.0.2",
"@angular/compiler": "^6.0.2",
"@angular/core": "^6.0.2",
"@angular/forms": "^6.0.2",
"@angular/http": "^6.0.2",
"@angular/platform-browser": "^6.0.2",
"@angular/platform-browser-dynamic": "^6.0.2",
"@angular/router": "^6.0.2",
"@angular/upgrade": "^6.0.2",
"bootstrap": "^4.1.1",
"core-js": "^2.5.6",
"reflect-metadata": "^0.1.12",
"rxjs": "^6.1.0",
"systemjs": "^0.21.3",
"zone.js": "^0.8.26",
"angular-highcharts": "^6.2.6",
"highcharts": "^6.1.1"
},
"devDependencies": {
"@types/core-js": "^0.9.46",
"typescript": "^2.8.3",
"typings": "^2.1.1",
"@types/node": "^10.0.4",
"@types/highcharts": "^5.0.22",
"concurrently": "^3.5.1",
"json-server": "^0.12.2",
"gulp": "^3.9.1",
"gulp-concat": "^2.6.1",
"gulp-rename": "^1.2.2",
"gulp-cssmin": "^0.2.0",
"gulp-uglify": "^3.0.0",
"gulp-htmlclean": "^2.7.20",
"rimraf": "^2.6.2"
}
}
安装所有包后,让我们将所需的库从 node_modules 文件夹传输到 “wwwroot/lib”。
管理已安装的包
我们需要将以下任务添加到 gulp 文件中,该文件会将新添加的包库传输到 “wwwroot/lib” 文件夹。
gulp.src('./node_modules/angular-highcharts/**/*.js')
.pipe(gulp.dest(root_path.package_lib + 'angular-highcharts'));
gulp.src('./node_modules/highcharts/**.js')
.pipe(gulp.dest(root_path.package_lib + 'highcharts'));
这是修改后的 gulp 文件
/// <binding AfterBuild='build-all' />
var gulp = require("gulp"),
rimraf = require("rimraf"),
concat = require("gulp-concat"),
cssmin = require("gulp-cssmin"),
uglify = require("gulp-uglify"),
rename = require("gulp-rename");
var root_path = {
webroot: "./wwwroot/"
};
//library source
root_path.nmSrc = "./node_modules/";
//library destination
root_path.package_lib = root_path.webroot + "lib/";
gulp.task('copy-lib-js', function () {
gulp.src('./node_modules/core-js/**/*.js')
.pipe(gulp.dest(root_path.package_lib + 'core-js'));
gulp.src('./node_modules/@angular/**/*.js')
.pipe(gulp.dest(root_path.package_lib + '@angular'));
gulp.src('./node_modules/zone.js/**/*.js')
.pipe(gulp.dest(root_path.package_lib + 'zone.js'));
gulp.src('./node_modules/systemjs/**/*.js')
.pipe(gulp.dest(root_path.package_lib + 'systemjs'));
gulp.src('./node_modules/reflect-metadata/**/*.js')
.pipe(gulp.dest(root_path.package_lib + 'reflect-metadata'));
gulp.src('./node_modules/rxjs/**.js')
.pipe(gulp.dest(root_path.package_lib + 'rxjs'));
gulp.src('./node_modules/angular-highcharts/**/*.js')
.pipe(gulp.dest(root_path.package_lib + 'angular-highcharts'));
gulp.src('./node_modules/highcharts/**.js')
.pipe(gulp.dest(root_path.package_lib + 'highcharts'));
});
gulp.task("copy-all", ["copy-lib-js"]);
//Copy End
gulp.task('min-js', function () {
gulp.src(['./clientapp/**/*.js'])
.pipe(uglify())
.pipe(gulp.dest(root_path.webroot + 'app'))
});
gulp.task('copy-html', function () {
gulp.src('clientapp/**/*.html')
.pipe(gulp.dest(root_path.webroot + 'app'));
});
gulp.task("build-all", ["min-js", "copy-html"]);
//Build End
右键单击 gulpfile.js,然后转到 “任务运行程序资源管理器”。
在新窗口中,刷新任务,然后像下面屏幕一样右键单击任务以运行它。
正如我们所见,所需的库已加载到 “wwwroot/lib” 文件夹中。
在导入模块之前,我们需要通过将以下列表中的 bundle 添加到 System.config()
函数来修改 SystemJS。
'angular-highcharts': 'npm:angular-highcharts/angular-highcharts.umd.js',
'highcharts': 'npm:highcharts/highcharts.src.js'
SystemJS 配置: systemjs.config.js
/**
* System configuration for Angular samples
* Adjust as necessary for your application needs.
*/
(function (global) {
System.config({
paths: {
// paths serve as alias
'npm:': '/lib/'
},
// map tells the System loader where to look for things
map: {
// our app is within the app folder
'app': 'app',
// angular bundles
'@angular/core': 'npm:@angular/core/bundles/core.umd.js',
'@angular/common': 'npm:@angular/common/bundles/common.umd.js',
'@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
'@angular/platform-browser':
'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
'@angular/platform-browser-dynamic':
'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
'@angular/http': 'npm:@angular/http/bundles/http.umd.js',
'@angular/router': 'npm:@angular/router/bundles/router.umd.js',
'@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
// highchart bundles
'angular-highcharts': 'npm:angular-highcharts/angular-highcharts.umd.js',
'highcharts': 'npm:highcharts/highcharts.src.js',
// other libraries
'rxjs': 'npm:rxjs',
'rxjs-compat': 'npm:rxjs-compat',
'rxjs/operators': 'npm:rxjs/operators'
},
// packages tells the System loader how to load when no filename and/or no extension
packages: {
'app': {
main: 'main.js',
defaultExtension: 'js',
meta: {
'': {
format: 'cjs'
}
}
},
'rxjs': {
main: 'index.js',
defaultExtension: 'js'
},
'rxjs/operators': {
main: 'index.js',
defaultExtension: 'js'
}
}
});
})(this);
TypeScript 配置
我们需要在编译器选项中添加新的类型 "highcharts",以下代码片段是针对 tsconfig.json 文件的。
配置 TypeScript: tsconfig.json
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"sourceMap": true,
"declaration": false,
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "es5",
"typeRoots": [
"node_modules/@types"
],
"lib": [
"es2017",
"dom"
],
"types": [
"core-js",
"highcharts"
]
},
"includes": [
"/**/*.ts"
]
}
根模块:现在让我们在 module.ts 中导入新添加的图表模块和组件。
import { ChartModule } from 'angular-highcharts';
以下是 module.ts 中的更新代码片段。
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { Routes, RouterModule } from '@angular/router';
import { LocationStrategy, HashLocationStrategy } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { ChartModule } from 'angular-highcharts';
//Components
import { AppComponent } from './component/app/component';
import { HomeComponent } from './component/home/component';
import { AboutComponent } from './component/about/component';
import { UserComponent } from './component/user/component';
import { ChartComponent } from './component/chart/component';
//Routes
const routes: Routes = [
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'home', component: HomeComponent },
{ path: 'about', component: AboutComponent },
{ path: 'user', component: UserComponent },
{ path: 'chart', component: ChartComponent }
];
@NgModule({
imports: [BrowserModule, HttpModule, FormsModule,
ReactiveFormsModule, RouterModule.forRoot(routes), ChartModule],
declarations: [AppComponent, HomeComponent, AboutComponent, UserComponent, ChartComponent],
bootstrap: [AppComponent]
})
export class AppModule { }
接下来,我们将创建 SQL 数据库表。
创建数据库
让我们在 MSSQL Server 中创建一个数据库。这是我们存储数据的地方。在查询窗口中运行以下脚本以创建新数据库。
CREATE DATABASE [dbCore]
创建表
USE [dbCore]
GO
/****** Object: Table [dbo].[User] Script Date: 8/15/2018 9:22:00 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[User](
[Id] [int] IDENTITY(1,1) NOT NULL,
[FirstName] [nvarchar](250) NULL,
[LastName] [nvarchar](250) NULL,
[Email] [nvarchar](250) NULL,
[Phone] [nvarchar](50) NULL,
CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED
(
[Id] 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
/****** Object: Table [dbo].[UserMarks] Script Date: 8/15/2018 9:22:00 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[UserMarks](
[id] [int] NOT NULL,
[userId] [int] NULL,
[mark] [decimal](18, 2) NULL,
CONSTRAINT [PK_UserMarks] PRIMARY KEY CLUSTERED
(
[id] 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
脚手架 MSSQL 数据库
我们将使用包管理器控制台中的命令通过反向工程从现有数据库重新生成 EF 模型。
命令
Scaffold-DbContext "Server=DESKTOP-7OJNKVF;Database=dbCore;Trusted_Connection=True;"
Microsoft.EntityFrameworkCore.SqlServer -Output serverapp/models -Force
正如我们在解决方案资源管理器中看到的,models 文件夹已经创建,包含 Context 和 Entities。
现在打开 DbContext 文件,然后添加一个构造函数,将配置(如 connectionstring
)传递到 DbContext
中。
public dbCoreContext(DbContextOptions<dbCoreContext> options) : base(options)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
//if (!optionsBuilder.IsConfigured)
//{
// #warning To protect potentially sensitive information in your connection string,
// you should move it out of source code.
// See http://go.microsoft.com/fwlink/?LinkId=723263 for guidance on storing connection strings.
// optionsBuilder.UseSqlServer
// (@"Server=DESKTOP-7OJNKVF;Database=dbCore;Trusted_Connection=True;");
//}
}
修改 WebAPI
将以下结果函数添加到现有的 web-api 中,以从数据库检索结果数据。
// GET: api/Values/GetResult
[HttpGet, Route("GetResult")]
public async Task<List<vmMarks>> GetResult()
{
List<vmMarks> query = null;
try
{
using (_ctx)
{
query = await (from um in _ctx.UserMarks
join m in _ctx.User on um.UserId equals m.Id
select new vmMarks
{
mid = (int)m.Id,
mName = m.FirstName + " " + m.LastName,
mMark = (decimal)um.Mark
}).OrderByDescending(x => x.mMark).ToListAsync();
}
}
catch (Exception ex)
{
ex.ToString();
}
return query;
}
好了,我们的 WebAPI 已修改并准备好检索数据。我们的下一步是准备客户端模型、组件和服务来与 WebAPI 交互。让我们创建一个 TypeScript 模型类,然后在另一个组件中通过导入它来使用它,例如:
//Model
import { ResultModel } from './model';
TypeScript 模型: ResultModel
export class ResultModel {
mid: number;
mName: string;
mMark: any;
}
组件: ChartComponent
import { Component } from '@angular/core';
import { ResultModel } from './model';
import { ResultService } from './service';
import { Chart } from 'angular-highcharts';
@Component({
selector: 'chart',
templateUrl: './app/component/chart/chart.html',
providers: [ResultService]
})
export class ChartComponent {
public marks: ResultModel[];
public chart: Chart;
title: string;
constructor(private resService: ResultService) {
this.title = ''
}
ngOnInit() {
this.getChart();
}
//Get All
getChart() {
//debugger
this.resService.getall().subscribe(
response => {
this.marks = response;
let chartData = [];
for (var i = 0; i < this.marks.length; i++) {
chartData.push({
"name": this.marks[i].mName,
"y": this.marks[i].mMark,
sliced: true,
selected: true
})
}
this.chart = new Chart({
chart: {
plotBackgroundColor: null,
plotBorderWidth: null,
plotShadow: false,
type: 'pie',
backgroundColor: null,
options3d: {
enabled: true,
alpha: 45,
beta: 0
}
},
title: {
text: 'Angular-6 + Highcharts-6',
},
subtitle: {
text: 'Result Pie-Chart!'
},
tooltip: {
pointFormat: '{series.name}: <b>{point.y}</b>'
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
depth: 35,
dataLabels: {
enabled: true,
format: '<b>{point.name}</b>: {point.percentage:.1f} %'
}
}
},
series: [{
name: 'Total Mark',
data: chartData
}]
});
}, error => {
console.log(error);
}
);
}
}
HTTP 客户端服务: ResultService
import { Injectable, Component } from '@angular/core';
import { HttpModule, Http, Request, RequestMethod, Response, RequestOptions, Headers }
from '@angular/http';
import { Observable, Subject, ReplaySubject } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
//Model
import { ResultModel } from './model';
@Component({
providers: [Http]
})
@Injectable()
export class ResultService {
public headers: Headers;
public _getUrl: string = '/api/Values/GetResult';
constructor(private _http: Http) { }
//Get
getall(): Observable<ResultModel[]> {
return this._http.get(this._getUrl)
.pipe(map(res => <ResultModel[]>res.json()))
.pipe(catchError(this.handleError));
}
private handleError(error: Response) {
return Observable.throw(error.json().error || 'Opps!! Server error');
}
}
HTTP 视图: chart.html
<div class="container-fluid">
<div class="row">
<h2>{{title}}</h2>
<div [chart]="chart"></div>
</div>
</div>
在浏览器中测试
现在是时候构建并运行应用程序了,转到图表菜单,正如我们在下面的屏幕截图中所看到的,饼图已动态生成。
总结
在这个示例中,我们将 ASP.NET Core 和 Angular 结合起来创建了一个示例 SPA 应用,而且没有使用任何 CLI,学习了如何从一个空的 ASP.NET Core 应用程序开始提供静态 HTML 页面。
我们还深入研究了最新的前端技术,如 Angular6,从零开始构建一个单页应用程序,简要概述了 Angular6 的依赖项,并对模块、组件有了初步了解。然后,我们使用示例应用程序执行了一些数据库操作。最后,我们实现了动态 Highchart。希望这对您有所帮助。