使用HighCharts实现实时数据展现

  在众多的工业控制系统领域经常会实时采集现场的温度、压力、扭矩等数据,这些数据对于监控人员进行现场态势感知、进行将来趋势预测具备重大指导价值。工程控制人员若是只是阅读海量的数据报表,对于现场整个态势的掌控会十分困难,所以每每但愿借助一些图表进行展现,其中趋势图是经常使用的实时数据展现方式之一。目前实现趋势图、曲线图的工具不少也很成熟,一些是经过CS模式开发的,须要在工程控制人员操做的计算机上安装相应软件,这种方式有其特有的优点,可是有时也有不方便的地方。因而一些基于BS模式的展示方式就天然而然的被普遍应用起来。采用BS模式的展示方式工程控制人员能够经过任何一台能够链接Web服务器的PC,经过经常使用的浏览器就能够实时的查看当前环境现场的各类指标参数,其便利性是显而易见的。下面我就介绍一下这种BS模式的实时数据展示曲线图的方法。因为本文的目的不是去实现一个现场环境可用的应用产品,所以只是针对涉及的技术进行讲解,起一个指导做用,所以参考者请依据本身项目的实际须要对本文章涉及的代码进行优化使用。
      在经过BS系统实现趋势图、曲线图的可选方案不少,本文主要经过Highcharts.com旗下的Highcharts API包来实现。因为此包是经过JS脚本实现的,所以我的认为相对来讲适应面可能更好,固然经过诸如jFreeChart这类工具也是能够实现的。
      言归正传,咱们来说解如何经过Highcharts API实现趋势图在页面上的呈现。
      首先咱们须要简单规划一下咱们系统的架构。因为实现实时数据的趋势图呈现,所以系统大体咱们能够设计成三层:显示层、逻辑层、数据源。以下图所示:javascript

      显示层就是将数据呈现给工程控制人员的的展现页面,这层主要由JSP、JS、CSS等文件构成,工程控制人员经过浏览器(诸如IE、火狐等)就能直接看到但愿的曲线图。显示层只负责显示,而显示须要的数据是通过必定清洗、规格化的,显示层拿到符合规格化要求的数据后,就能够直接进行显示,并响应和人的交互。数据的清洗、规格化工做都是在逻辑层中实现,逻辑层经过获取的数据源信息,进行必要的数据逻辑转换、数据清洗、数据规格化处理。数据源是一个复杂的重要的,它能够是直接来自下位机的数据通信,也能够是下位机将数据存储在中间数据库中,也能够是一系列的数据文件。
      在本文中只是模拟数据源,并非实现数据源的读取。而且对应逻辑层的处理,也进行了忽略,这部份内容由于涉及具体的数据获取、清洗、转换、规格化,和具体工程项目的需求有较大关系,加之也不是本文规划的中心,所以此部分代码设计实现本文也不涉及。
      显示层的实现涉及到JSON、JQuery、Highcharts,咱们首先创建一个标准的Web应用(其实若是做为例子,使用一个html文件也行,此处本人计划后期会扩展本案例,实现后续一些诸如逻辑层的功能,所以创建了一个Web应用工程,有点多此一举,还请见谅)。本人采用Netbeans IDE 7.2版本开发(如何用Netbeans IDE开发Web应用请参考本人其它文章),所以创建完成后的工程结构以下:html

      要使用Highcharts,咱们须要导入highcharts.js文件。highcharts.js文件能够从Highcharts官网得到(官网地址:http://www.highcharts.com/),从官网下载的压缩文件中包含有咱们开发须要的highcharts.js文件外,还包含一些其它的文件,诸如例子文件等。
      Highcharts是使用js来实现的,同时应用到了JQuery技术,所以还须要去得到最新版的JQuery包(官网地址:http://jquery.com/)。
      以上两块准备好后,咱们将其加入新建的工程中,在工程文件中咱们规划了一个放置全部js文件的地方,有一个js目录,将highcharts.js、jquery-1.8.3.min.js文件都放置到此目录下。你们看到个人工程中在js目录下有一个modules子目录,此子目录下放置的exporting.js文件是无关紧要的,若是你们要使用将图表导出等功能就须要使用此文件,所以须要导入工程中,不然彻底能够不须要。
     工程环境准备停当,咱们就能够打开本工程的默认,也是惟一的一个jsp页面,对此页面作一个编写修改。主要修改有以下几个地方:
     第一,在jsp页面头部引入highcharts.js、jquery-1.8.3.min.js文件,应用代码参考以下:java

<scripttype="text/javascript"src="http://zhaowenbinmail.blog.163.com/blog/js/jquery-1.8.3.min.js"></script>jquery

<scriptsrc="http://zhaowenbinmail.blog.163.com/blog/js/highcharts.js"></script>数据库

     第二,在jsp页面的Body体中加入一个div元素,highcharts将在这个div元素中绘制曲线图。数组

<divid="container"style="min-width:100px; height:400px; margin:0auto"></div>浏览器

     注意:咱们为这个div指定了一个id值,这个id值未来对咱们颇有用,它是使highcharts知道在何处绘制图表的根源。
     第三,咱们须要在jsp页面中加入咱们本身的js文件。这个文件用来实现特定的业务呈现逻辑。服务器

<scripttype="text/javascript"src="http://zhaowenbinmail.blog.163.com/blog/js/chart.js"></script>

     如今我来说解一下我须要实现的业务的大致需求。我须要在页面上显示大桥表面一天24小时的温度变化状况(固然这些温度值的变化本案例中都是经过随机数来产生的)。在咱们的很轴方向上须要显示从0点开始到晚上23点的时间刻度,而且要求固定就显示0到23这24个刻度,在纵轴方向显示桥面传感器检测到的本小时内温度最大值,而后模拟时间推移显示每小时的温度变化曲线图。
     依据以上需求分析,在页面呈现时,咱们就要去读取本天从0点开始到当前时刻的数据,并将数据绘制显示成曲线图。所以咱们接下来就要编辑咱们本身的js文件——chart.js。在此文件中建立Highcharts对象,经过设置相关的属性来影响曲线图的呈现,使其知足咱们的需求要求。
     咱们首先定义一个全局的图表对象,咱们命名为chart,同时示例化Highcharts对象,具体见下面代码:架构

var chart;dom

$(function(){
$(document).ready(function(){
chart =newHighcharts.Chart({
chart:{
renderTo:'container',
type:'line',
marginRight:130,
marginBottom:80,
events:{
load:loadTime
}
},
title:{
text:'大桥采集数据',
x:-20
},
subtitle:{
text:'传感器编号: 传感器1',
x:-20
},
xAxis:{
title:{
enabled:true,
text:'时间(小时)'
},
max:23,
min:0,
tickPixelInterval:50
},
yAxis:{
title:{
text:'压力 (℃)'
},
plotLines:[{
value:0,
width:1,
color:'#808080'
}]
},
tooltip:{
formatter:function(){
return'<b>'+this.series.name +'</b><br/>'+
this.x +': '+this.y +'℃';
}
},
legend:{
x:-50,
y:10,
enabled:true
},
exporting:{
enabled:false
},
plotOptions:{
line:{
gapSize:100
}
},
series:[{
name:'最大值',
data: getFirstData()
}]
});
});

});

       在上面代码中咱们实例化了一个Highcharts对象,并指定了此对象一些属性。在定义中咱们能够看到以下代码:

     chart:{
renderTo:'container',
type:'line',
marginRight:130,
marginBottom:80,
events:{
load:loadTime
}
}

      在这段代码中就知道了图表须要绘制到的div元素,注意看上面红色字体部分。这个地方的container就是jsp页面上div的id值(你们能够回过去查看一下我前面的代码)。
      其后指定了这个图表的类型(见上面代码中蓝色字体部分)。这里指定的Line类型,这就会绘制成曲线。
      代码中还指定了图表的事件,目前只指定了一个load事件,在图表装载时将会调用执行load时间对应的函数。代码后面的loadTime是我编写的一个js函数,这个函数后面介绍。
      经过title、subtitle指定图表的标题、子标题,见下面代码:

     title:{
text:'大桥采集数据',
x:-20
},
subtitle:{
text:'传感器编号: 传感器1',
x:-20
},

      经过改变这里的设置能够影响图表上显示的效果,显示效果以下图红框选中部份内容。

      经过xAxis、yAxis设定图表中横坐标、纵坐标的属性。

      xAxis:{
title:{
enabled:true,
text:'时间(小时)'
},
max:23,
min:0,
tickPixelInterval:50
},
yAxis:{
title:{
text:'压力 (℃)'
},
plotLines:[{
value:0,
width:1,
color:'#808080'
}]
},

       经过在xAxis、yAxis中设置title属性控制横坐标、纵坐标上的文字描述显示。
       在横坐标中有时咱们是须要指定坐标上每一个坐标点须要显示的文字内容的,这时咱们须要使用到一个categories属性,经过将一个数组值传给categories属性,这样在横坐标上的每一个坐标点就会按照指定的属性内容显示坐标点信息。为了实现如上目的,咱们须要再设置一个变量,并将这个变量赋予categories属性。详见下:

var x_arr=['0:00','1:00','2:00','3:00','4:00','5:00',
'6:00','7:00','8:00','9:00','10:00','11:00',
'12:00','13:00','14:00','15:00','16:00','17:00',
'18:00','19:00','20:00','21:00','22:00','23:00'];

 

         经过上面代码段咱们定义了一个变量,而后看看如何指定到chart对象中,请注意以下代码端中红色部门,就是较前面代码端增长的地方:

xAxis:{
title:{
enabled:true,
text:'时间(小时)'
},
categories:x_arr,
max:23,
min:0,
tickPixelInterval:50
},

        如今页面上显示的图表效果以下图所示:

        横坐标上就是按照咱们在x_arr变量中设定的内容显示的。若是设定的内容少于横坐标的坐标点,则前面的坐标点将按x_arr变量中设定内容显示,后面的坐标点将按默认的坐标点信息显示。
        工程控制人员经过此曲线图能够知道每一个时间点的最高温度状况,可是具体某个点温度是多少,工程人员但愿经过将鼠标指向图表中采集点就能够展示出来。要实现这个功能,咱们须要在chart对象中指定tooltip属性,见下面代码:

tooltip:{
formatter:function(){
return'<b>'+this.series.name +'</b><br/>'+
this.x +': '+this.y +'℃';
}
},

         配置上了这个属性就能获得下图显示的效果:

         当鼠标移动到10点中的采集点时,屏幕上会当即显示当时的温度值。
         针对有些应用场合,咱们在一个图表中将展现多个线条表明不一样的含义,这时就须要经过图例来讲明什么颜色线条表明什么含义,这种状况下就须要启用图例说明,要启用图例说明就必须经过以下属性进行配置:

    egend:{
x:-50,
y:10,
enabled:true
},

 

       只要使egend对象中的enabled属性设置为true就能够。设置为false,将不显示图例。
       上面介绍的是图例基本的属性设置,如今咱们须要模拟一些大桥传感器得到的数据,依据这些数据来显示曲线图。在这里咱们首先要定义两个js函数,这三个函数就是模拟获取数据的,请看下面:

function loadTime(){
window.setTimeout(getData,TIMEOUT);
}

       上面这个函数就是咱们在chart对象中设置events中的load事件指定的函数。在本函数中主要启动了一个定时器,在超过指定时间计秒后,将调用函数getData。

function getFirstData(){
var data =[];
var y_mx=Math.round(Math.random()*10);
var i;

for(i =0; i <=0; i++){
data.push({
x: current_time,
y: y_mx
});
if(current_time<=23){
current_time++;
}
}
return data;
}

       这个函数是用来模拟初始化chart对象时,得到的大桥桥面温度值。其返回的是一个数组对象,数组中的每一个对象包含x、y属性,这两个属性用来告诉chart对象x轴的某个坐标上面的y值是多少,并在此处显示一个坐标点,同时将链接相邻两个坐标点造成曲线。代码中的current_time是一个全局变量,用来对当前采集显示次数进行计数。

function getData(){
var current_x=x_arr[current_time];

//获取最大值
var series_mx = chart.series[0];
var y_mx=Math.round(Math.random()*10);

series_mx.addPoint([current_time, y_mx],true,false);

current_time++;

if(current_time<=23){
window.setTimeout(getData,TIMEOUT);
}
}

 

      上面这个函数其它部分都很简单,关键的一个重点代码是

series_mx.addPoint([current_time, y_mx],true,false);

       这一段,这段代码是在chart图表中加入一个新的坐标点。
       截至到目前,所有的代码就编写完成,如今运行它,就能够模拟出大桥桥面稳定24小时检测状况的实时趋势图。

       其实使用highcharts来作实时趋势图简单的处理仍是比较简单的,更多的应用还能够在这些基础应用上进行拓展

 

<script type="text/javascript">
var x_arr = ['0:00', '1:00', '2:00', '3:00', '4:00', '5:00','6:00', '7:00', '8:00', '9:00', '10:00', '11:00','12:00', '13:00', '14:00', '15:00', '16:00', '17:00','18:00', '19:00', '20:00', '21:00', '22:00', '23:00'];
var chart;
var current_time = 0;
var TIMEOUT = 1000;
$(function () {
$(document).ready(function () {
chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
type: 'line',
marginRight: 130,
marginBottom: 80,
events: {
load: loadTime
}
},
title: {
text: '大桥采集数据',
x: -20
},
subtitle: {
text: '传感器编号: 传感器',
x: -20
},
xAxis: {
title: {
enabled: true,
text: '时间(小时)'
},
categories: x_arr,
max: 23,
min: 0,
tickPixelInterval: 50
},
yAxis: {
title: {
text: '压力 (℃)'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
tooltip: {
formatter: function () {
return '<b>' + this.series.name + '</b><br/>' +
this.x + ': ' + this.y + '℃';
}
},
legend: {
x: -50,
y: 10,
enabled: true
},
exporting: {
enabled: false
},
plotOptions: {
line: {
gapSize: 100
}
},
series: [{
name: '最大值',
data: getFirstData()
}]
});
});

});

function loadTime() {
window.setTimeout(getData, TIMEOUT);
}

function getFirstData() {
var data = [];
var y_mx = Math.round(Math.random() * 10);
var i;

for (i = 0; i <= 3; i++) {
data.push({
x: current_time,
y: y_mx
});
if (current_time <= 23) {
current_time++;
}
}
return data;
}

function getData() {
var current_x = x_arr[current_time];

//获取最大值
var series_mx = chart.series[0];
var y_mx = Math.round(Math.random() * 10);

series_mx.addPoint([current_time, y_mx], true, false);

current_time++;

if (current_time <= 23) {
window.setTimeout(getData, TIMEOUT);
}
}

</script>

相关文章
相关标签/搜索