本文介绍如何使用echarts.js来创建一个图形计算软件,并打包成应用程序。生成的图像可以进行交互,也可以用作论文出图之用。

一、项目背景

现需根据若干公式生成两个变量的曲线图像。并由此探讨变量关系。常用于各类实验、仿真中,并可以利用生成的图像填写到论文中。

本文需要计算的公式如下图所示:

公式

其中f是我们需要具体进行计算的数据,它由若干个参数确定。λ pu、λ mall、T都是常数。并且M需要由L和V HGB:pu确定,因此需要对其进行变形如下:

公式

这样我们就能得到M的公式,后面只需进行计算即可。

另外在该项目中,需要求出L固定时,f与V HGB:pu的关系;V HGB:pu固定时,f与L的关系。也就是说要画出两个关系的函数图像。

二、技术思考

为了使应用程序轻量化且便于部署到各类平台中,这里主要考虑借助WEB技术,也就是说程序的核心是一个网页。这样的应用简单便携且界面美观。因此本文需要的技术基础包括基本的htmljs语法知识。为了是应用界面更加漂亮,这里还是用了bootstrap前端框架对软件的界面进行制作。

三、装备工作

1、下载需要的js脚本。

这里需要的脚本包括三个方面:

  • jquery.js:使用jquery语法必备,主要为了使代码更加简洁。下载地址为jquery官方网站

  • bootstrap.js:应用非常广泛的前端框架,能够通过简单的引入制作能适应多种设备比例的页面。下载地址为bootstrap官方网站

  • echarts.js:百度出品的图像计算框架,用于绘制各种可交互的WEB图表下载地址为echarts.js

2、建立文件结构

先将下载好的文件放到文件夹中,其文件结构为:

1
2
3
4
5
6
7
index.html
├── js
│ ├── bootstrap.min.js
│ ├── echarts.min.js
│ └── jquery-3.4.1.min.js
└── css
└── bootstrap.min.css

其中index.html由编辑器建立。

四、开发流程

1、编写界面

下面开始编写index.html,首先建立页面的基本数据输入框,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>图形计算软件</title>
<!-- 引入css文件 -->
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css" />
<!-- 引入js文件 -->
<script src="js/jquery-3.4.1.min.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/echarts.min.js"></script>
</head>
<body>
<nav class="navbar navbar-dark bg-dark mb-3">
<div class="container">
<a class="navbar-brand" href="#">图形计算软件</a>
</div>
</nav>
<div class="container">
<div class="row">
<div class="col-md-4 col-sm-12">
<div class="card" style="width: 100%;">
<div class="card-header">
基础计算
</div>
<div class="card-body">
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1">L</span>
</div>
<input id="L" type="text" class="form-control" placeholder="" aria-describedby="basic-addon1" value="20">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1">μm</span>
</div>
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1">V HGB</span>
</div>
<input id="vhgb" type="text" class="form-control" placeholder="" aria-describedby="basic-addon1" value="0.5">
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1">λ pu</span>
</div>
<input id="lp" type="text" class="form-control" placeholder="" aria-describedby="basic-addon1" value="0.182">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1">W/(m*k)</span>
</div>
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1">λ mall</span>
</div>
<input id="lm" type="text" class="form-control" placeholder="" aria-describedby="basic-addon1" value="1.27">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1">W/(m*k)</span>
</div>
</div>
<button id="count" type="button" class="btn btn-primary btn-block mb-3" data-dismiss="modal">计算</button>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1">λ g</span>
</div>
<input id="lg" type="text" class="form-control" placeholder="" aria-describedby="basic-addon1">
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1">λ hgb</span>
</div>
<input id="lhgb" type="text" class="form-control" placeholder="" aria-describedby="basic-addon1">
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1">M</span>
</div>
<input id="M" type="text" class="form-control" placeholder="" aria-describedby="basic-addon1">
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1">导热系数(f)</span>
</div>
<input id="F" type="text" class="form-control" placeholder="" aria-describedby="basic-addon1">
</div>
</div>
</div>
</div>
<div class="col-md-8 col-sm-12">
<div class="card mb-3" style="width: 100%;">
<div class="card-header">
f与V HGB:pu的关系
</div>
<div class="card-body">
<div class="input-group mb-1">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1">V HGB最小</span>
</div>
<input id="vhgba" type="text" class="form-control" placeholder="" aria-describedby="basic-addon1" value="0">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1">V HGB最大</span>
</div>
<input id="vhgbb" type="text" class="form-control" placeholder="" aria-describedby="basic-addon1" value="1">
<div class="input-group-prepend">
<button class="btn btn-primary" type="button" id="plot1">绘图</button>
</div>
</div>
</div>
<div id="canvas1" style="width: 100%;height:200px;"></div>
</div>
<div class="card" style="width: 100%;">
<div class="card-header">
f与L的关系
</div>
<div class="card-body">
<div class="input-group mb-1">
<div class="input-group-prepend">
<span class="input-group-text">V hgb:pu</span>
</div>
<input id="vhgbpu" type="text" class="form-control" placeholder="" aria-describedby="basic-addon1" value="0.264158">
<div class="input-group-prepend">
<span class="input-group-text">L最小</span>
</div>
<input id="la" type="text" class="form-control" placeholder="" aria-describedby="basic-addon1" value="0">
<div class="input-group-prepend">
<span class="input-group-text">μm</span>
</div>
<div class="input-group-prepend">
<span class="input-group-text">L最大</span>
</div>
<input id="lb" type="text" class="form-control" placeholder="" aria-describedby="basic-addon1" value="10">
<div class="input-group-prepend">
<span class="input-group-text">μm</span>
</div>
<div class="input-group-prepend">
<button class="btn btn-primary" type="button" id="plot2">绘图</button>
</div>
</div>
</div>
<div id="canvas2" style="width: 100%;height:200px;"></div>
</div>
</div>
</div>
</div>
</body>
</html>

其中主要使用了bootstrap框架,内部拥有13个输入框,两个预留的绘图区域,具体显示效果如下图所示:

界面

2、编写核心计算js

根据如下图中的公式,我们要来构建出计算的核心函数。

公式

使用js构建的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script type="text/javascript">
//核心计算js
function countlg(l) {
return (3.954*Math.pow(10,-3)+7.7208*Math.pow(10,-5)*298-1.6082*Math.pow(10,-8)*Math.pow(298,2))/(1+2*2*1.38*Math.pow(10,-23)*298*l/(Math.sqrt(2)*3.14*3.798*Math.pow(10,-10)*100000));
};
function countlhgb(l,lm,lg) {
return 1/(0.8/(l*lm)+(l-0.8)/((l-0.8)*lg+0.8*lm));
};
function countm(l,vhgb) {
return Math.sqrt(Math.pow(l,2)/vhgb+Math.pow(l,2));
};
function countf(m,l,lp,lhgb) {
return 1/((m-l)/(m*lp)+l/(l*lhgb+(m-l)*lp));
};
</script>

这里的函数分别表示:

  • countlg(l)用于计算λ g,输入变量为L。
  • countlhgb(l,lm,lg)用于计算λ HGB,输入变量为L、λ mall、λ g。
  • countm(l,vhgb)用于计算M,输入变量为L和V hgb。
  • countf(m,l,lp,lhgb)用于计算M,输入变量为M、L、λ PU、λ HGB。

其中有几个点需要注意:

  • Math.pow(a,b)代表计算a的b次方
  • Math.sqrt(a)代表a的开放

3、完成基础计算行为

构建完核心计算的js代码后,需要对页面的行为进行构建,同样使用js代码,具体如下:

1
2
3
4
5
6
7
8
9
<script type="text/javascript">
//计算代码
$("#count").click(function(){
$('#lg').val(countlg($("#L").val()));
$('#lhgb').val(countlhgb($("#L").val(),$("#lm").val(),$("#lg").val()));
$('#M').val(countm($("#L").val(),$("#vhgb").val()));
$('#F').val(countf($("#M").val(),$("#L").val(),$("#lp").val(),$("#lhgb").val()));
});
</script>

这里使用了jquery的语法用于获取输入框的值及给输入框赋值,也就是说通过左边的输入直接得到中间值及输出。

其中的关键点是这几个:

  • $(“#count”)采用的是jquery选择器语法,#代表选择id为count的元素
  • $(“#count”).click()代表点击id为count的按钮后所执行的函数,在click()的括号中输入。
  • (‘#lg’).val()代表获取id为ig的元素的值,也就是输入框中的值;若在val()括号中输入值,将会把该值赋给该元素的值,这样就能完成输出结果的显示。

4、绘制图像

对基础计算编写完成后,我们需要绘制出两组图像。绘制图像的操作我们使用echarts.js插件来完成,具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
<script type="text/javascript">
//绘图1
$("#plot1").click(function(){
//构建数组
var a = new Array();
for(var i=0;i<100*$("#vhgbb").val();i=i+1){
a[i] = new Array();
a[i][0] = i/100;
a[i][1] = countf(countm($("#L").val(),i/100),$("#L").val(),$("#lp").val(),countlhgb($("#L").val(),$("#lm").val(),countlg($("#L").val())));
}
// 初始化echarts实例
var myChart = echarts.init(document.getElementById('canvas1'));
// 指定图表的配置项和数据
var option = {
tooltip : {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#6a7985'
}
}
},
grid:{
x:45,
y:10,
x2:45,
y2:70,
borderWidth:1
},
xAxis: {},
yAxis: {},
series: [{
data: a,
type: 'line'
}],
dataZoom: [
{ // 这个dataZoom组件,默认控制x轴。
type: 'slider', // 这个 dataZoom 组件是 slider 型 dataZoom 组件
start: 0, // 左边在 10% 的位置。
end: 100 // 右边在 60% 的位置。
},
{ // 这个dataZoom组件,也控制x轴。
type: 'inside', // 这个 dataZoom 组件是 inside 型 dataZoom 组件
start: 0, // 左边在 10% 的位置。
end: 100 // 右边在 60% 的位置。
}
]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
});
//绘图2
$("#plot2").click(function(){
//构建数组
var a = new Array();
for(var i=0;i<$("#lb").val()*100;i=i+1){
a[i] = new Array();
l=i/100;
a[i][0] = l;
a[i][1] = countf(countm(l,$("#vhgbpu").val()),l,$("#lp").val(),countlhgb(l,$("#lm").val(),countlg(l)));
}
// 初始化echarts实例
var myChart = echarts.init(document.getElementById('canvas2'));
// 指定图表的配置项和数据
var option = {
tooltip : {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#6a7985'
}
}
},
grid:{
x:45,
y:10,
x2:45,
y2:70,
borderWidth:1
},
xAxis: {},
yAxis: {},
series: [{
data: a,
type: 'line'
}],
dataZoom: [
{ // 这个dataZoom组件,默认控制x轴。
type: 'slider', // 这个 dataZoom 组件是 slider 型 dataZoom 组件
start: 0, // 左边在 10% 的位置。
end: 100 // 右边在 60% 的位置。
},
{ // 这个dataZoom组件,也控制x轴。
type: 'inside', // 这个 dataZoom 组件是 inside 型 dataZoom 组件
start: 0, // 左边在 10% 的位置。
end: 100 // 右边在 60% 的位置。
}
]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
});
</script>

仔细观察代码,我们会发现这样几个点:

  • 在每一个绘图中我们构建了一个数组,数组含有n个元素,每个元素又是一个数组,包含两个元素,分别代表绘图的x轴和y轴。
  • 绘制的区间由输入的最大和最小值构成。
  • 计算代码利用核心js代码进行了几次迭代,最终由一行代码完成,若阅读吃力的话可以使用中间变量拆分开来分别计算。

使用echarts.js时,我们发现:

  • 该插件先在html代码中使用div呈现,并标记了id。
  • 插件的第一步是获取该div。
  • 然后对图标进行配置。

在配置项中,有这样几个点,当然也可以在官网查看相关手册:

  • tooltip代表提示项,用于在鼠标放上去时显示数据。
  • grid代表图像显示的边界。
  • xAxis、yAxis代表坐标轴显示的元素。
  • series代表需要显示的数据及显示的类型。
  • dataZoom代表坐标轴能否进行缩放。

将所有js代码和html代码合并放到一个index.html文件中就能完成该软件的核心代码的编写。现在我们运行一下试试看,通过点击得到如下的界面:
结果

五、打包程序成可执行的exe程序

由于某些项目需要直接可以运行的exe程序,这里我们使用electron对程序进行打包。在安装好git和node.js的前提下使用cmd输入以下指令安装electron:

1
npm install electron

克隆一个electron示例项目

1
git clone https://github.com/electron/electron-quick-start

在C:\Users\用户名下找到克隆好的文件夹,使用cmd进入。然后输入

1
electron

即可查看示例生产的exe界面,我们将做好的软件移动到该文件夹覆盖index.html文件,然后使用

1
electron-packager . 'HelloWorld' --platform=win32 --arch=x64 --icon=icon.ico --out=./out --asar --app-version=0.0.1

即可打包成功,其中HelloWorld是软件名,也可以修改图标窗口大小等配置,具体参考如官方文档