我使用Angular Material来为MATLAB Production Server的Web前端示例增加了一些时尚的元素
在将用MATLAB编写的分析算法系统化时,可以通过编译并在MATLAB Production Server上部署,从而可以通过RESTful API进行交互,并可以从JavaScript调用。我试着制作了一个Web前端,并记录了下来。
范本
既有示例的文件中包含了以债券计算为主题的MATLAB代码和HTML/JavaScript样本,所以首先可以从这里开始尝试一下。
HTML/JavaScript部分
将bptool.html和calculatePrice.js复制粘贴,几乎完成,但是需要取消注释bptool.html中的。
MATLAB一方
直接使用 pricecalc.m 的样本。
function price = pricecalc(face_value, coupon_payment,...
interest_rate, num_payments)
M = face_value;
C = coupon_payment;
N = num_payments;
i = interest_rate;
price = C * ( (1 - (1 + i)^-N) / i ) + M * (1 + i)^-N;
点击MATLAB的“应用”->“Production Server编译器”,打开编译界面。
-
- タイプ:デフォルトの「配布可能なアーカイブ」のまま。
-
- エクスポートする関数:pricecalc.mを追加
- アーカイブ情報:「BondTools」に変更
请转到“测试”选项卡,并按照以下设置。
-
- ポート:デフォルトの9910のまま
- CORSを有効にする:チェックを入れる
当点击「启动」按钮时,服务会在 http://localhost:9910/BondTools 上开始监听。
确认动作
不需要搭建Web服务器,只需将先前的HTML / JavaScript文件放置在个人电脑的桌面上,并在浏览器中打开bptool.html。
但是,由于我正在使用原生的HTML/JavaScript来创建界面,所以界面看起来很简陋。我想要更加华丽的界面。
继续下半场。
我想要一个更加精致的网页前端。
既然要做,那就试着用框架来创建Material Design的界面吧,这是备忘录的后半部分。关于Angular的安装,可以参考Angular的快速入门指南或其他文章,从使用ng命令创建项目开始。
创建Angular项目
我們將專案命名為mpsBondCalc,然後使用ng new來建立專案。
使用`ng new mpsBondCalc`命令将创建一个包含各种Angular模板的项目。
安装Angular-Material
切换到项目的根文件夹,然后安装Angular-Material的全部组件。
cd mpsBondCalc
npm install –save @angular/material @angular/cdk
npm install –save @angular/animations
npm install –save hammerjs
根据Angular的入门教程中的第五步:手势支持,如果要使用滑块功能,则必须安装HammerJS,并在main.ts文件中添加import ‘hammerjs’。
在该模块中,使用Angular-Material导入了输入表单、滑块等控件(以Mat*为前缀)。
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatCardModule, MatInputModule, MatSliderModule, MatDividerModule } from '@angular/material';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { HttpModule } from '@angular/http';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
FormsModule,
ReactiveFormsModule,
MatCardModule,
MatInputModule,
MatSliderModule,
MatDividerModule,
BrowserAnimationsModule,
HttpModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
将主要的app.component.html和app.component.ts文件进行移植,同时修改为适用于Angular的DOM操作,包括将示例中的bptool.html和calculatePrice.js进行移植。在bptool.html中使用了
作为分隔线,而在这里我们尝试使用Angular-Material的divider(mat-divider)。
<mat-card class="result">
<mat-card-content>
<h1><a>Bond Pricing Tool</a></h1>
<h2></h2>
This example shows an application that calculates a bond price from a simple formula.<p>
You run this example by entering the following known values into a simple graphical interface:<p>
<ul>
<li>Face Value (or value of bond at maturity) - M</li>
<li>Coupon payment - C</li>
<li>Number of payments - N</li>
<li>Interest rate - i</li>
</ul>
The application calculates price (P) based on the following equation:<p>
P = C * ( (1 - (1 + i)^-N) / i ) + M * (1 + i)^-N<p>
<mat-divider [inset]="true"></mat-divider>
<h3>M: Face Value </h3>
<form class="example-form form-inline" novalidate>
<mat-form-field class="example-full-width">
<input matInput type="number" name="facevalueValue" [(ngModel)]="facevalueValue" min="0" max="10000" (change)="calculatePrice()">
</mat-form-field>
<mat-slider
name="couponPaymentSlider"
class="example-margin"
[max]=10000
[min]=0
[(ngModel)]="facevalueValue"
(change)="calculatePrice()">
</mat-slider>
</form>
<h3>C: Coupon Payment </h3>
<form class="example-form" novalidate>
<mat-form-field class="example-full-width">
<input matInput type="number" name="couponPaymentValue" [(ngModel)]="couponPaymentValue" min="0" max="1000" (change)="calculatePrice()">
</mat-form-field>
<mat-slider
name="couponPaymentSlider"
class="example-margin"
[max]=1000
[min]=0
[step]=0.01
[(ngModel)]="couponPaymentValue"
(change)="calculatePrice()">
</mat-slider>
</form>
<h3>N: Number of payments </h3>
<form class="example-form" novalidate>
<mat-form-field class="example-full-width">
<input matInput type="number" name="numPaymentsValue" [(ngModel)]="numPaymentsValue" min="0" max="1000" (change)="calculatePrice()">
</mat-form-field>
<mat-slider
name="numPaymentsSlider"
class="example-margin"
[max]=1000
[min]=0
[(ngModel)]="numPaymentsValue"
(change)="calculatePrice()">
</mat-slider>
</form>
<h3>i: Interest rate </h3>
<form class="example-form" novalidate>
<mat-form-field class="example-full-width ">
<input matInput type="number" name="interestRateInput" [(ngModel)]="interestRateValue" min="0" max="1" step="0.01" (change)="calculatePrice()">
</mat-form-field>
<mat-slider
name="interestRateSlider"
id="interest_rate_slider"
class="example-margin"
[max]=1
[min]=0
[step]=0.01
[(ngModel)]="interestRateValue"
(change)="calculatePrice()">
</mat-slider>
</form>
<h2>BOND PRICE</h2>
<p id="price_of_bond_value" style="font-weight: bold" #price_of_bond_value>
<p id="error" style="color:red" #error>
<mat-divider [inset]="true"></mat-divider>
<h3>Request to MPS Server</h3>
<p id="request" #request>
<h3>Response from MPS Server</h3>
<p id="response" #response>
<mat-divider [inset]="true"></mat-divider>
</mat-card-content>
</mat-card>
import {Component, ViewChild, ElementRef} from '@angular/core';
import {Http, Headers} from "@angular/http";
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
@ViewChild('request') requestElement: ElementRef;
@ViewChild('response') responseElement: ElementRef;
@ViewChild('error') errorElement: ElementRef;
@ViewChild('price_of_bond_value') priceOfBondValueElement: ElementRef;
// Initial values
facevalueValue = 0;
couponPaymentValue = 0;
numPaymentsValue = 0;
interestRateValue = 0;
httpOptions = {
headers: new Headers({
'Content-Type': 'application/json',
'Accept': 'application/json'
})
};
constructor(private http: Http) {}
// Calculate
calculatePrice() {
let url = "http://localhost:9910/BondTools/pricecalc";
//Use MPS RESTful API to specify params using JSON
let params = {
"nargout": 1,
"rhs": [this.facevalueValue, this.couponPaymentValue, this.interestRateValue, this.numPaymentsValue]
};
let requestElement = this.requestElement.nativeElement;
requestElement.innerHTML = "URL: " + url + "<br>" + "Method: POST <br>" + "Data:" + JSON.stringify(params);
const response = this.http.post(url, params, {headers: this.httpOptions.headers}).toPromise()
.then(response => {
//Use MPS RESTful API to check HTTP Status
if (response.status === 200) {
// Deserialization: Converting text back into JSON object
// Response from server is deserialized
let result = response.json();
//Use MPS RESTful API to retrieve response in "lhs"
if ('lhs' in result) {
let errorElement = this.errorElement.nativeElement;
errorElement.innerHTML = "";
let priceOfBondValueElement = this.priceOfBondValueElement.nativeElement;
priceOfBondValueElement.innerHTML = "Bond Price: " + result.lhs[0].mwdata;
} else {
let errorElement = this.errorElement.nativeElement;
errorElement.innerHTML = "Error: " + result.error.message;
}
} else {
let errorElement = this.errorElement.nativeElement;
errorElement.innerHTML = "Error:" + response.statusText;
}
let responseElement = this.responseElement.nativeElement;
responseElement.innerHTML = "Status: " + response.status + "<br>"
+ "Status message: " + response.statusText + "<br>" +
"Response text: " + JSON.stringify(response.json());
});
}
}
我希望尽量减少修改,但使用ngModel在输入表单和滑块处非常方便实现,所以我进行了相当大的修改。
执行结果
现在我们来确认一下使用Angular-Material在Web前端的执行结果。
运行命令:ng serve –open。
不错不错,输入表单和滑动条变得现代化了,感觉不错。
在部署到 Web 服务器时,可以使用 ng build –prod 命令进行 TypeScript 编译,然后将生成的 HTML/JavaScript 文件放置在 Web 服务器上。而将 MATLAB Production Server 从 MATLAB 上的“模拟”转化为真正的打包好的 CTF 文件,并将其传递给 MATLAB Production Server 进行执行即可。但在开发 Web 前端时,方便调试的“模拟”方法会更加便利。