说一下写这个效果的背景,本人之前是做java后端的,那个时候看前端的页面了解到echarts,它自带的鼠标移动事件效果确实很好。现在在做工控上位机,用的是winform framework,它自带的chart图效果看起来很一般,而且手写鼠标移动效果很麻烦,根据鼠标位置与x轴上的数据取点会出现异常(打点的左右值一直是0) ,后来看到webbrowser控件可以直接加载html,可以用到echarts框架,轻松实现动画效果, 直接上效果图。
首先 winform内嵌echarts需要用到webbrowser控件,直接拖一个在winform里,在资源中新建一个html(选中c#项目新建项 在web中手动改后缀为html)新建完如图 html文件放在下图,function里的参数和split方法后面会讲,先大概看一下echarts的代码 我的是(smooth属性为true的)折线图。这边要注意要先引入echarts包 ,这边其实只需要引入ehcarts.js包就可以了。在html里导包,在html文件里可以看到。
直接上代码
html文件:
<!DOCTYPE html>
<html>
<head>
<title>ECharts</title>
<!-- 引入 echarts.js -->
<script src="echart/echarts.js"></script>
</head>
<body>
<div id="main" style="width: 1300px;height:500px;"></div>
<script type="text/javascript">
var myChart = echarts.init(document.getElementById('main'));
function show(timelist, actlist, setlist, nitlist, toplist, botlist) {
var time = timelist.split(",");
var act = actlist.split(",");
var set = setlist.split(",");
var nit = nitlist.split(",");
var top = toplist.split(",");
var bot = botlist.split(",");
option = {
title: {
text: '变化曲线'
},
tooltip: {
trigger: 'axis'
},
legend: {
data: ['实际温度', '设定温度', '一区温度', '二区温度', '氮势']
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
toolbox: {
feature: {
saveAsImage: {}
}
},
xAxis: {
type: 'category',
boundaryGap: false,
data: time
},
yAxis: {
type: 'value'
},
series: [
{
name: '实际温度',
type: 'line',
smooth:true,
data: act
},
{
name: '设定温度',
type: 'line',
smooth: true,
data: set
},
{
name: '一区温度',
type: 'line',
smooth: true,
data: top
},
{
name: '二区温度',
type: 'line',
smooth: true,
data: bot
},
{
name: '氮势',
type: 'line',
smooth: true,
data: nit
}
]
};
myChart.setOption(option);
}
</script>
</body>
</html>
然后回到c#中,cs文件
首先 根据 this.webBrowser1.Url = new Uri("D:\\vs\\jsdyl\\jsdyl\\chart.html");
这个的意思是你的webbrowser根据这个路径打开html 这边我用的是绝对路径,在网上看用的都是相对路径,不过这个没什么影响。这行代码要放在form_load中 程序启动就加载html。
然后是这个方法 可以看下面的注释。
private void initWebBrowser()
{
//防止 WebBrowser 控件打开拖放到其上的文件。
webBrowser1.AllowWebBrowserDrop = false;
//防止 WebBrowser 控件在用户右击它时显示其快捷菜单.
webBrowser1.IsWebBrowserContextMenuEnabled = false;
//以防止 WebBrowser 控件响应快捷键。
webBrowser1.WebBrowserShortcutsEnabled = false;
//以防止 WebBrowser 控件显示脚本代码问题的错误信息。
webBrowser1.ScriptErrorsSuppressed = true;
//可以通过这个属性,把WINFROM中的变量,传递到JS中,供内嵌的网页使用
webBrowser1.ObjectForScripting = this;
}
在public Form1这边加入initWebBrowser()方法。
public Form1()
{
InitializeComponent();
initWebBrowser();
}
然后需要注意一下程序关闭时 要释放掉这个webbrowser资源。
在form中的方法 双击formclosing
如图:
然后在formClosing方法中加入dispose()方法
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
this.webBrowser1.Dispose();
}
ok,回到winform里, 在你的webrowser控件旁边添加一个按钮,然后双击该按钮,进入按钮点击事件,直接展示按钮点击事件的代码,
private void foxButton1_Click(object sender, EventArgs e)
{
List<string> time1 = new List<string>();
List<int> acttmp1 = new List<int>();
List<int> settmp1 = new List<int>();
List<double> nitrogen_potential1 = new List<double>();
List<int> toptmp1 = new List<int>();
List<int> bottomtmp1 = new List<int>();
string timelist;
string actlist;
string setlist;
string nitlist;
string toplist;
string botlist;
conn.Open();
MySqlCommand cmd = new MySqlCommand("SELECT acttmp,settmp,nitrogen_potential,toptmp,bottomtmp,time " +
"FROM sdl2_tmp order by time asc ", conn);
MySqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
int acttmp = reader.GetInt32("acttmp");
int settmp = reader.GetInt32("settmp");
double nitrogen_potential = reader.GetDouble("nitrogen_potential");
int toptmp = reader.GetInt32("toptmp");
int bottomtmp = reader.GetInt32("bottomtmp");
DateTime recordtime = reader.GetDateTime("time");
string a = recordtime.ToString("yy-MM-dd HH:mm");
time1.Add(a);
acttmp1.Add(acttmp);
settmp1.Add(settmp);
nitrogen_potential1.Add(nitrogen_potential);
toptmp1.Add(toptmp);
bottomtmp1.Add(bottomtmp);
}
conn.Close();
timelist = String.Join(",", time1);
actlist = String.Join(",", acttmp1);
setlist = String.Join(",", settmp1);
nitlist = String.Join(",", nitrogen_potential1);
toplist = String.Join(",", toptmp1);
botlist = String.Join(",", bottomtmp1);
webBrowser1.Document.InvokeScript("show", new object[] { timelist, actlist, setlist, nitlist, toplist, botlist });
}
关键是后台与html的交互 也是在网上查了大量的资料 ,但都是一些很简单的饼状图和柱状图,几乎没有与折线图的交互。
读代码,一开始新建的许多类型的集合便是根据我数据库查找得到的多种类型的数据。使用集合的好处是方便我在下面的从数据库返回的reader.read方法中使用list.add方法存值,拿到所有的值。作为一个后端,在交互的时候确实头疼了很久,主要还是因为不熟悉cs与html的交互。经过两天的摸索和大量的逛贴,终于搞懂了。回到正题 ,关键的方法是
webBrowser1.Document.InvokeScript("show", new object[] { timelist, actlist, setlist, nitlist, toplist, botlist });
交互的时候还需要在cs文件的一开始加上
[System.Runtime.InteropServices.ComVisible(true)]这行代码,如下图
cs与html的交互方式有很多,但却会受到很多限制,webBrowser1.Document.InvokeScript这个方法可以有两个参数,也可以有一个参数,第一个参数的含义是html文件中的function的方法名,第二个参数传值的时候会用到,他是一个objecet类型的数组,我试过直接传数组或集合给前台,但很遗憾,始终拿不到我想要的值,因为我在各种帖子上看的发现都是传的一些简单的objecet类型的数组包裹着一个或两个string,这明显满足不了我想要的展示多个y轴的折线图。突然灵光一现。后台数据都成功拿到了,使用的是集合的形式,通过 你的string = String.Join(",",你的 List) 这个方法,可以把集合转为string,集合里的数据用","隔开,成功的转为string类型,几个y轴的数据, 通过一样的方式,这样我就拿到了多个string,这里我定义了六个string,一个是时间,就是echarts上的x轴,还有5个就是y轴的各项了。
webBrowser1.Document.InvokeScript("show", new object[] { timelist, actlist, setlist, nitlist, toplist, botlist });
通过这个方法,我们可以将object[]里的多个string传递给html
回到html
因为这边html无法打断点,在程序中看不到变量的值,我们可以用几个alert测试一下有没有拿到相应的string的值。经过测试,成功拿到6个参数的值,然后我们需要对这几个值进行处理,ehcarts中的x轴和series的data类型都是数组,我们通过split(",")方法可以将string类型用“,”拆分开来,这样就会得到我们想要的各个数组了,然后将数组放到对应的“data:”后,可以看我一开始贴的html代码,ehcarts就可以成功展示了,并且数据是我们通过后台查询得到的,到这就结束了。
PS:后面如果用到范围查询,要注意我们cs文件中声明的集合和string类型的作用域问题,我的建议是直接在我们的“查找所有”、“按范围查找”的按钮点击事件里面声明,即需要对集合List和string初始化。还有echarts初始化的方法(echarts.init)需要放到function的外面,不然会出现echarts更新失效(不能重复查询)的问题。