用Flash与C语言制作工程实时数据动态曲线图
宋国志
本文旨在说明如何利用Flash和C语言制作BS模式下的实时数据动态曲线图,现在流行的实时数据曲线图,大都是采用了CS模式的开发语言,BS模式的虽有一些实例,比如google上的股市曲线图,但其实现的方式和流程在网上很少能见到。
其运行时的界面如下,数据实时更新,曲线图从左往右动态移动:
下面先讲在实现过程中的工作环境以及开发工具进行简单的介绍:
1. Macromedia Flash Professional 8;
2. Macromedia Dreamweaver 8;
3. 标准C;
4. 操作系统:Windows,主要用来制作Flash和网页;
5. 操作系统:Linux,用作网站的服务器,安装apache;
6. apache软件。
假设以上的环境都已经安装完毕,并经测试运行正常,下面就逐步的介绍开发过程:
一.在制作此例前,我假设您已了解以下Flash知识点:
1.使用this.createEmptyMovieClip动态创建MovieClip;
2.使用AS绘制线条或矩形;
3.对Flash中“深度”的理解;
4.使用this.createTextField动态创建文本框
二.正式开始
1.创建一个空白文档,有两个层:
看上图,两个层:
A.script:放置一些脚本;
B.坐标曲线: 放置一个MovieClip,即生成的曲线;
2.按Ctrl+F8新建一个影片剪辑(MovieClip),里面放置一个动态文本框,实例名称为:tips,如下图:
3.返回场景,将刚才制作的mc坐库中托至场景(放在可视区域外),并且命名为:mouse_mc,如图:
4.按Ctrl+F8新建一个影片剪辑(MovieClip):坐标曲线,有三个层:,如下图:
A. script:放置一些脚本;
B. 文字:放置x,y轴的说明文字;
C. xy轴: 放置x,y坐标轴;
5.在影片剪辑“坐标曲线”的“xy轴”层上画x,y坐标线:
这步就是注意坐标轴的中心点,画在影片剪辑的注册点上,即_x=0,_y=0处;
6.在坐标轴附近,创建二个动态文本框,分别指定变量名为:name_x,name_y,如下图:
这二个文本框用来显示坐标轴的说明文字;
7. 接着在的“script”层的第一帧,加入如下代码:
//载入实时数据的对象
newFollow=new LoadVars();
//x,y轴的名称
name_x = "Time(S)";
name_y = "Data";
//x轴刻度总长
var xtotal:Number=120;
//y轴刻度总长
var ytotal:Number=100;
//存放曲线上点的数组
var point_arr:Array=new Array();
//曲线上点的个数,最大为120(表示2分钟)
var numPoints:Number;
numPoints=0;
//x轴单位刻度的像素数
var xspace = Math.floor(360/xtotal);
//y轴单位刻度的像素数
var yspace = Math.floor(200/ytotal);
//画X轴刻度
DrawScalX(xtotal);
//画Y轴刻度
DrawScalY(ytotal);
//画X轴刻度
function DrawScalX(total:Number) {
createEmptyMovieClip("scalX_mc", 1);
scalX_mc.lineStyle(1, 0x6699CC, 80);
var i:Number;
for (i=1; i<total+1; i++) {
if (i%10 == 0) {
scalX_mc.lineStyle(1, 0x6699CC, 70);
scalX_mc.moveTo(xspace*i, 0);
scalX_mc.lineTo(xspace*i, -6);
CreateText(i, xspace*i-14-5*xspace+15, 5);
} else {
scalX_mc.lineStyle(1, 0x6699CC, 30);
scalX_mc.moveTo(xspace*i, 0);
scalX_mc.lineTo(xspace*i, -4);
}
}
}
function DrawScalY(total:Number) {
createEmptyMovieClip("scalY_mc", 2);
var i:Number;
for (i=1; i<total+1; i++) {
if (i%10 == 5) {
scalY_mc.lineStyle(1, 0x6699CC, 50);
scalY_mc.moveTo(0, 0-(yspace*i));
scalY_mc.lineTo(7, 0-(yspace*i));
} else if (i%10 == 0) {
scalY_mc.lineStyle(1, 0x6699CC, 80);
scalY_mc.moveTo(0, 0-(yspace*i));
scalY_mc.lineTo(8, 0-(yspace*i));
CreateText(i, -30, 0-(yspace*i)-9);
} else {
scalY_mc.lineStyle(1, 0x6699CC, 30);
scalY_mc.moveTo(0, 0-(yspace*i));
scalY_mc.lineTo(4, 0-(yspace*i));
}
}
}
//建立x,y轴的坐标文本
function CreateText(txt:Number, X:Number, Y:Number) {
var my_txt = createTextField("my_txt"+txt, Math.floor(Math.random()*100000), X, Y, 30, 30);
my_txt.multiline = false;
my_txt.wordWrap = true;
my_txt.selectable = false;
var my_fmt:TextFormat = new TextFormat();
my_fmt.color = 0x999999;
my_fmt.align = "center";
my_txt.text = txt;
my_txt.setTextFormat(my_fmt);
}
//画曲线
function DrawLine() {
createEmptyMovieClip("curve_mc", 3);
//曲线填充色
curve_mc.beginFill(0xFFFFCC, 50);
//曲线颜色
curve_mc.lineStyle(1, 0xFF6600, 100);
curve_mc.moveTo(0, 0);
for (var i = 0; i<point_arr.length; i++) {
curve_mc.lineTo(i*xspace, 0-point_arr[i]*yspace);
DrawCircle((i), 0-(point_arr[i]));
}
curve_mc.lineTo(((point_arr.length-1)*xspace), 0);
curve_mc.lineStyle(1, 0x000000, 0);
curve_mc.lineTo(0, 0);
curve_mc.endFill();
if (point_arr[0])
_root.cnp="即时数据:"+point_arr[0]+" P/S";
}
//构造曲线上点的数组
function display() {
//曲线上新点的y轴坐标值
var str:String;
var i:Number;
newFollow.load("/cgi-bin/getdata.cgi?nocahe="+getTimer());
newFollow.onLoad=function(){
str=newFollow.new_point;
for (i=numPoints; i>0; i--) {
point_arr[i]=point_arr[i-1];
}
if (numPoints<120)
numPoints++;
point_arr[0]=str;
}
//画曲线
DrawLine();
}
setInterval(display,1000);
stop();
8.返回场景,在场景的第一帧加入如下代码:
//让鼠标提示内容的宽度根据内容的多少自动调整
mouse_mc.tips.autoSize = true;
//页面的编码方式
System.useCodepage = true;
9.将库中的“坐标曲线”影片剪辑拖至场景中,命名为:mc,如下图:
10.参数说明:
//载入实时数据的对象
newFollow=new LoadVars();
//x,y轴的名称
name_x = "Time(S)";
name_y = "Data";
//x轴刻度总长
var xtotal:Number=120;
//y轴刻度总长
var ytotal:Number=100;
//存放曲线上点的数组
var point_arr:Array=new Array();
//曲线上点的个数,最大为120(表示2分钟)
var numPoints:Number;
numPoints=0;
11.制作Flash影片
导出影片并保存为Real-Time_curve.swf,制作一个网页,将该影片插入到网页中,保存网页为Real-Time_curve.html,然后将该网页和Flash影片一起上传到apache服务器的htdocs目录中。但记得要修改这两个文件的权限,否则在测试的时候会出现无权访问的错误。
三.制作实时数据源
在Linux下编写一个模拟实时数据产生器,其代码如下:
#include <stdio.h>
int main(void)
{
srand((int)time(0));
printf("Content-type: text/html/n/n");
printf("new_point=%d", rand()%101);
return 0;
}
将代码保存为getdata.c,并将编译后的可执行文件命名为getdata。将可执行的getdata保存到apache服务器的cgi-bin目录中。
在上面的代码中,值得注意的是两个printf语句。第一个printf语句是cgi编程的规范,在这里我不做阐述,可以查阅相关资料做进一步的理解,而第二个printf语句实际上与前面介绍的Flash中的newFollow.load("/cgi-bin/getdata.cgi?nocahe="+getTimer())构成了一个实时数据的通信接口。
四.问题讨论
1.保证数据的实时刷新。在IE浏览器中可能由于缓存的原因而导致Flash无法实时动态的显示,因此在Flash中必须使浏览器每次都从服务器上去读取数据,而不会使用本地的缓存,因此在Flash中调用实时数据源时加上了参数nochae=getTimer(),由于getTimer()在每次调用的时候的值不同,使浏览器认为是调用一个新的程序,这样保证数据的有效性和实时性。
2.动态曲线的刷新频率。setInterval(display,1000)使浏览器每隔一秒钟就调用一次display()函数,重新获取一次数据,然后绘制新的曲线。
3.曲线上点的值保存在一维数组point_arr中,使用该一维数组可以同时体现出曲线上坐标点的位置,数组元素的下标值即为曲线的X坐标值,该下标所对应的数组元素值就为曲线的Y坐标值。由于曲线上总共可以显示120个点的值,也即是2分钟的数据,因此数组的长度也设置为120,2分钟之前的元素没有采用溢出,而是采用的覆盖的方式,这样对系统来说也安全,以免造成内存问题。
4.当然,曲线图的X/Y轴的名称以及轴上的刻度大小都是可以通过html或者其他语言在调用Flash影片时作为参数传递给Flash。
作者:宋国志