摘 要
SVG是由W3C组织开发的基于可扩展标记语言的一种矢量图形描述语言,已经在互联网上得到了较广泛的应用。为了以图形方式直观地显示雨量数据变化,方便工作人员进行雨量数据的查询及分析,设计了本套基于SVG的雨量分析系统。
该自动站雨量分析系统是基于B/S架构,使用ASP.NET来开发的。主要使用了.NET三层架构、XML程序集、矢量图形的动态生成、Web服务等技术,并实现了系统模块管理、雨量数据管理、城市数据管理、雨量数据查询、生成矢量图形格式的图表等功能模块。在系统中主要对矢量图形文档的生成进行了分析和设计,采用DOM模型来操作该图形文档,并封装了基本的图形元素。
该自动站雨量分析系统作了新的尝试,采用基于可扩展标记语言的矢量图形作为图形格式,系统与Web服务技术相结合,使系统的可重用性和开放性得到了很大的提高。
关键词:可伸缩矢量图形;可扩展标记语言;.NET三层架构;Web服务
2.1 XML介绍
XML是可扩展标记语言的简称,它定义了结构化表示数据的标准格式。XML是W3C(World Wide Web Consortium,万维网联盟)为适应互联网的发展而推出的新型Web语言,是国际标准化组织所制订的SGML(Standard Generalized Markup Language,标准通用标记语言)的子集。它是用于定义其他标识语言的一种元语言。它具有可扩展性、平台独立性、数据与表现分离以及结构化数据等特点,非常适合网络环境下的数据传输和表达。XML通过其可扩展性提供了一种通用的数据格式,不同的软件系统之间可以通过这种新的数据描述方式进行通信,从而实现完全的交互操作,这源于XML将结构化的数据表示为一个纯文本的特性。可以通过XML对信息加以规范化定义和描述,并且在互联网上进行数据的传输。SVG就是XML在图形图像领域的一个应用。
2.2 SVG介绍
SVG是一种基于XML的开放的标准文本式矢量图形描述语言,即它是用XML元语言定义的语言。SVG图像是与XML1.0兼容的文档,SVG元素是指示如何绘制图像的一些指令,阅读器解释这些指令,把SVG图像在指定设备上显示出来。使用SVG可以在网页上显示出各种各样的高质量的矢量图形,包括许多图像处理中常见的功能,如图形、文字、动画、颜色、滤镜效果等。最关键的是SVG完全用普通文本来描述,也就是说,这是一种专门为网络而设计的基于文本的图像格式。由于SVG是基于XML的,所以可扩展性很强,能够描述任何复杂的图像,甚至动态交互式图像。
2.3 SVG的特点
虽然SVG的“矢量描述”并不是一个全新的概念,但它综合了矢量图形、点阵图像和纯文字的优点,以一种标准将其统一起来描述。它由计算机根据矢量数据计算后绘制而成,相较于位图图像矢量图像有以下特点:(1)文件的大小与图形的复杂程度有关,而与图形的具体尺寸无关;(2)图形的显示尺寸可以无限缩放,变化后不影响图形的质量。正是由于矢量图像的这些特征,使得它尤其适合于网上传播。图片和交互在以前是两个独立的概念,而在SVG中,文字与图形并非封装于SVG内,而是可以借助DOM和脚本语言等手段与外界交互,使得在图片内进行交互成为可能,这是以往的图像所不能做到的。统一的标准和开放性是SVG的强大生命力所在。标准统一可增强网络的交流,结束目前业界各种格式并存的混乱局面;开放性则有利于日后的各种新的元素加入其中扩充其功能。SVG使用时,客户端的软件负责解释SVG文本并将其转化成实际的矢量图像,文字仍是文字,线条仍是线条,可在客户端即时修改,这也是SVG的一大特色。
2.4 SVG规范
SVG规范定义了6种类型的对象,包括矢量图形、图像、渐变填充、滤镜、可重用单元和文本。图形对象可以进行组合、添加样式、几何变换等操作。根据功能不同,这些主要对象可归结为基本要素对象和页面描述功能对象两大类,具体请见图1和图2所示。
图1 SVG基本要素
图2 SVG页面描述功能
框架元素,就是组成一个完整SVG文档的基本元素,主要包括<svg>、<g>、<desc>元素和<title>元素等等。<svg>元素是文档元素,必不可少的,它相当于指定一块画布,内部的所有图形元素都将显示在这块画布指定的区域中。因此它有一些标记位置的属性像x,y,width,height。<desc>和<title>元素是用来描述图像的注释性元素。还有一些表示基本图形的标记,如rect,circle等等,SVG图形就是通过组合这些基本的元素和组件,来生成复杂的图形的。
5.1 雨量数据管理的实现
在雨量数据管理页面中进行雨量数据录入时,必须先选中要添加雨量数据的城市及日期,点击“确定”后系统首先查看是否有该城市这一天的数据,有的话就直接显示,没有的话会创建一条新的雨量数据记录,自动生成随机数作为这一天24小时的雨量数据,并将数据写入数据库中。这里创建新雨量数据记录是基于三层架构来做的,首先创建Model.SVGRAS_RainPerHour对象,然后将数据保存到其成员变量中,再调用BLL.SVGRAS_RainPerHour.Add方法来将此对象包含的数据写入到数据库中。其相关代码如下:
DataTable table1=null;
if(this.RecordID!=null)//如果是修改的话,则返回的有RecordID则显示被修改的雨量数据
table1=BLL.SVGRAS_RainPerHour.GetList("RecordID="+this.RecordID).Tables[0]; //获取已有条件的雨量数据
else if(this.RecordID==null || this.RecordID=="")
table1=BLL.SVGRAS_RainPerHour.GetList("CityID="+this.SelectedCity+" and Year="+this.Year+" and Month= "+this.Month+" and Day="+this.Day).Tables[0];
if (table1.Rows.Count>0)
{
this.dgData.DataSource=table1;
this.dgData.DataBind();
this.RecordID=table1.Rows[0]["RecordID"].ToString();
}
else if (table1.Rows.Count<1)
{
//string temp="0";
Random rand = new Random();
SVGRAS.Model.SVGRAS_RainPerHour model=new SVGRAS.Model.SVGRAS_RainPerHour();
model.CityID=this.SelectedCity;
model.Year=this.Year;
model.Month=this.Month;
model.Day=this.Day;
model.hour01=rand.Next(0,200).ToString ();
model.hour12=rand.Next(0,200).ToString ();
//model.hournn=…;
SVGRAS.BLL.SVGRAS_RainPerHour.Add(model);
DataTable table2=BLL.SVGRAS_RainPerHour.GetList( "CityID="+this.SelectedCity+" and Year="+this.Year+" and Month= "+this.Month+" and Day="+this.Day).Tables[0];
this.dgData.DataSource=table2;
this.dgData.DataBind();
this.RecordID=table2.Rows[0]["RecordID"].ToString();
}
页面效果如图10所示。
图10 雨量数据录入界面
在实际应用中,这里生成的数据全部为0,而具体的数据需要通过数据更新功能来输入。这里采用自动生成数据方式,是为了方便系统的测试与演示。用户要填入新的雨量数据,需要点击更新按钮进入数据更新页面,在其中填入新数据后点击提交按钮完成更新。
5.2 雨量数据分析与SVG图像的生成
1、获取用户设置的查询参数
用户在查询页面中设置相应的查询参数,如查询方式、查询日期等等,并点击确定按钮(即选择某一城市)后,程序首先会验证用户的参数设置是否正确,若不正确,则弹出错误提示;若通过验证,再按照用户设置的查询参数传到后续程序中。
这里的验证分为两部分,一部分是在浏览器端进行的,使用javascript代码,在向服务器发送数据前完成验证,这里的验证是测试用户输入的数据是否合法,如日期格式是否正确,参数是否设置完整等等,如果用户设置的是按多日查询,却只设置了起始日期,那么就不会通过验证。只有通过验证才会将参数数据发送到服务器端,这样可以在一定程度上减轻服务器端的压力。
图11 前台界面
另一部分验证是在服务器端进行的,它主要验证用户是否拥有操作权限,以及数据库中是否存在数据。只有通过验证后,才能在数据库中查询相应的雨量数据。
2、从数据库中查询数据
按照用户设置的查询模式,转到相应模式的查询代码中。然后再根据查询参数,从数据库中获取相应的数据。如:用户设置的查询模式为按天查询,查询城市为成都,日期为2007-5-27,然后调用strWhere()方法来生成查询参数,再传入三层架构中的业务逻辑层中的getList()方法,就得到了查询的结果,代码如下:
DataTable table1=BLL.SVGRAS_RainPerHour.GetList(strWhere("days")).Tables[0];
3、对数据进行分析处理,并组织为适合显示的形式
前面查询得到的是一个DataTable表,里面的数据是与数据库中对应起来的,但这样的数据却不便于生成图像,因此要对它进行重组,转换为雨量数据和相关文字信息。在这里定义了一个类RainfallData来辅助,这个类包含了城市信息、时间信息、相应的雨量信息等等,具体代码如下:
public class RainfallData
{
public string cityId;
public string cityName;
public int max = 0;
public int min = 1000000;
public double average;
public string startY;
public string startM;
public string startD;
public string endY;
public string endM;
public string endD;
//计算出最大最小值
public void calMaxMin ()
{
double tmp = 0;
for (int i=0; i < data.Length; ++i)
{
if ( data[i] > max )
max = data[i];
else if ( data[i] < min )
min = data[i];
tmp += data[i];
}
average = (tmp / data.Length);
}
public int[] data;
}
然后将每一组雨量数据都存到该类的对象中,并将这些对象传给SVG显示模块。
此外,若查询模式是多日查询或多月查询,还需要将数据按日或月累加起来。
4、使用XML对象来生成SVG文档
项目中定义了一个SVG文档类SVGDocument,它继承自XMLDocument,在它内部封装了加载SVG文档元素的操作,以后创建好文档中的元素后就直接插入到该文档中即可。另外定义了一个辅助类SVGHelper,里面定义了一些向某个结点添加基本SVG元素的操作,以方便向文档中添加SVG图形。现在,创建一个SVG文档,并且添加一条线、一个圆、一个矩形和一行文本的代码如下:
SVGDocument document = new SVGDocument(800,700);
SVGHelper.InsertLine (document.DocumentElement, 1,1,300,350, Color.BlueViolet, 5);
SVGHelper.InsertCircle (document.DocumentElement,100,100,50,Color.Red,Color.Gold,2.5);
SVGHelper.InsertRect (document.DocumentElement,300,400,80,70,Color.Gray,Color.Honeydew,3);
SVGHelper.InsertText (document.DocumentElement,"网络工程",10,100,15,"楷体",Color.Blue);
5、向SVG文档中添加坐标系
为了方便坐标系的创建,定义了坐标系类CoordinateFrame,在它里面封装了坐标系的细节,并提供创建坐标系、向坐标系中添加点、添加线等接口操作,相应的也定义了坐标类Coordinate,来对坐标信息进行封装。现在,向SVG文档中添加坐标系,并向坐标系中添加一系列点和线的代码如下:
CoordinateFrame frame = new CoordinateFrame (10,10,600,500,5,9,document.DocumentElement);
Coordinate point = new Coordinate(50,40);
frame.InsertPoint(point);
Coordinate []points = new Coordinate [5];
//... 在此获取坐标数据 ...
frame.InsertLine (points,"成都",Color.Chocolate);
6、将数据转换为坐标点的数组
处理按照用户参数查询获得的数据,并将其转换为对应于坐标系中的坐标点的数组。这里需要求出所有雨量数据的最大值和最小值,并计算出合理的纵坐标的坐标点数,然后将每一个雨量数据除以一个纵坐标点代表的雨量数据,以转换为坐标位置。然后将坐标点添加到坐标系上,并连成曲线。
7、添加相应的文字标签及均值线
在点上以及线上面,加上说明文字。不同的线会用不同的颜色显示,并标注相应的说明文字。同时,将求出的每组数据的均值以均值线的方式画到坐标系上。
8、修改响应类型为SVG文档类型(image/svg+xml)
将要返回的响应类型改为image/svg+xml,这样浏览器才会将页面作为SVG图形来解析。然后将SVG文档(以XML对象表示)的内容发送到客户端。具体代码如下:
Response.ContentType="image/svg+xml";
document.Save( Response.OutputStream );
Response.Flush();
Response.End();
现在客户端就可以看到如图12所示的SVG格式的图形了。
图12 SVG图形生成界面
5.3 使用Web Service方式提供开放的外部接口
5.3.1 Web Service介绍
Web Service是建立在HTTP协议、SOAP协议和UDDI等标准以及XML等技术之上的,其主要目标就是在现有的各种异构平台的基础上构建一个通用的,与平台和语言无关的接口层,各种不同平台之上的应用通过这个接口层来集成已有的服务。
Web Service具有以下一些特征:
1、完好的封装性:Web Service既然是一种部署在Web上的对象,自然具备对象的良好封装性。对使用者而言,只能看到该对象提供的功能列表。
2、松散耦合:当一个Web Service的实现发生变化时,调用者完全不会感觉到。对调用者来说,只要调用的接口不变,其内部实现的任何变化对用户来说都是透明的。
3、高度可集成能力:由于Web Service采用简单的、易于理解的XML作为接口描述,完全屏蔽了不同平台和系统的差异性,因此,任何符合协议的应用都可以集成已有的Web Service。
5.3.2 使用Web Service的意义
使用Web Service可以引入很高的开放性,使得系统可以方便的集成到其它应用中,同时,也为系统的二次开发预留了很好的接口。此外,作为雨量数据分析系统,必然会涉及到大量的雨量数据,而这些雨量数据是从全国各地的设备终端采集汇总而来的,一旦有了这一开放的接口,所有的数据都可以通过它来写入到数据库中。另外,这些雨量数据的采集是相当不容易的,一般的科研机构和学校是不可能获取如此大量的真实数据的,例如本套系统就无法获得到这些真实数据,只能通过随机数来生成假的数据。这样就限制了这些数据的科研作用。然而,通过Web Service来提供开放的接口后,所有的用户都可以通过它来很容易的获取这些雨量数据,还可以通过接口使用系统中已经做好的各种功能,避免了重复开发的浪费。因此,使用Web Service来提供开放的接口是有很大的积极意义的。
5.3.3 Web Service接口的实现
在系统中只提供简单功能的实现,主要接口有:
1、获取城市ID
通过该接口可以查询指定城市在系统中分配的ID值,其参数为城市名称。在查询城市数据前,首先要通过此接口获得城市的ID值。
2、获取雨量数据
通过输入查询条件,来获得雨量数据。这里的查询条件就是SQL查询语句中的where子句,用户可以指定某一天、某几天或某几个月的等条件。例如最简单的查询“江油”的所有雨量数据的参数为“CityId = ‘0000000013’”。
接口实现代码如下:
[WebMethod]
public string getCityId (string city)
{
return SVGRAS.BLL.SVGRAS_City.GetList ("CityName='" + city + "'").Tables[0].Rows[0]["CityId"].ToString ();
}
[WebMethod]
public DataSet getRainData (string sql)
{
return SVGRAS.BLL.SVGRAS_RainPerHour.GetList (sql);
}