OpenLayers介绍
网址:http://www.openlayers.org/
OpenLayers?是由MetaCarta公司开发的,用于WebGIS客户端的 JavaScript包,目前的最高版本是2.5?V,通过BSD?License?发行。它实现访问地理空间数据的方法都符合行业标准,比如 OpenGIS的WMS和WFS规范,?OpenLayers采用纯面向对象的JavaScript方式开发,同时借用了Prototype框架和 Rico库的一些组件。
采用OpenLayers作为客户端不存在浏览器依赖性。由于OpenLayers采用JavaScript语言实现,而应用于Web浏览器中的DOM(文档对象模型)由JavaScript实现,同时,Web浏览器(比如IE,FF等)都支持DOM?。
OpenLayers?APIs采用动态类型脚本语言JavaScript编写,实现了类似与Ajax功能的无刷新更新页面,能够带给用户丰富的桌面体验(它本身就有一个Ajax类,用于实现Ajax功能)。
目前,OpenLayers所能够支持的Format有:XML、GML、 GeoJSON、GeoRSS、JSON、KML、WFS、WKT(Well-Known?Text)。在OPenlayers.Format名称空间下 的各个类里,实现了具体读/写这些Format的解析器。
OpenLayers所能够利用的地图数据资源“丰富多彩”,在这方面提供给拥护较多的选择,比如WMS、WFS、GoogleMap、KaMap、MSVirtualEarth、WorldWind等等。当然,也可以用简单的图片作为源。
第一次使用OpenLayers:
先到它的官方网站http://www.openlayers.org/下 载他的压缩包,解压后可以看到其中的一些目录和文件,拷贝目录下的OpenLayer.js、根目录下的lib目录、根目录下的img目录到你网站的 Scripts目录下(当然,这个只是例子,您网站的目录结构您自己说得算,只要保证OpenLayers.js,/lib,/img在同一目录中即 可)。?然后,创建一个index.html作为查看地图的页面,导入OpenLayers.js和你将要创建的js。
我们以加载WMS和GML文件为例。
????<script?src="../lib/OpenLayers.js"></script>
<script?type="text/javascript">
????????var?lon?=?5;????//x-axis?coodinate?in?map?units
????????var?lat?=?40;???//y-axis?coordinate?in?map?units
????????var?zoom?=?5;???//number?of?zoom?levels
????????var?map,?layer;?
//声明变量map、layer;等同于?var?map?=?null;?var?layer?=?null;
????????map?=?new?OpenLayers.Map('map');
????????//实例化一个地图类OpenLayers.Map
????????layer?=?new?OpenLayers.Layer.WMS(?"OpenLayers?WMS",?
????????????????????"http://labs.metacarta.com/wms/vmap0",?{layers:?'basic'}?);
????????//以WMS的格式实例化图层类OpenLayers.Layer
????????map.addLayer(layer);
????????map.zoomToExtent(newOpenLayers.Bounds(-3.922119,44.335327,
????????4.866943,49.553833));
//在Map对象上加载Layer对象,并用map.zoomToExtent函数使地图合适地显示
map.addLayer(new?OpenLayers.Layer.GML("GML",?"gml/polygon.xml"));
//再在刚加载的WMS文件上,加载一GML文件
剩下的工作就是,加上一些控件OpenLayers.Control之类的东西,比如LayerSwitcher等。它们会在地图浏览的“窗口”上增加一些工具栏或是“按钮”,增加互动性和功能性。
当然,Openlayers中的东西远不止这些,至于它的框架分析、APIs实现机制,会在后续文章中说出。写这个的过程,也是一个学习的过程,其中难免有不妥之处,热烈欢迎大家批评指正,相互交流。
?
通过前面的项目介绍,我们大概已经知道Openlayers是什么,能够做什么,有什么意义。接下来我们分析它怎么样,以及怎样实现的等问题。
?
这个图是从它的文档上截取的,旨在从感官上认识一下OpenLayers的类。下面分别介绍(文档中的类是按字母顺序排列的,也按这个顺序说吧):
我们看到在类的顶层“高高在上”的是OpenLayers,它为整个项目实现提供名称空间(JavaScript语言没有名称空间一说,但是它确实有自己的机制实现类似的功能,后面会说明),它直接拥有一常量?VERSION_NUMBER,以标识版本。
Ajax:顾名思义,用于实现Ajax功能,只是OpenLayers的开发者们把它单独写到一个类里了,其中用到了Prototype.js框架里的一些东西。同时,设计的时候也考虑了跨浏览器的问题。
BaseTypes:这里定制了OpenLayers中用到的string, number?和?function。比如,OpenLayers.?String.?startsWith,用于测试一个字符串是否一以另一个字符串开 头;OpenLayers.?Number.?limitSigDigs,用于限制整数的有效数位; OpenLayers.?Function.bind,用于把某一函数绑定于对象等等。
Console:OpenLayers.Console,此名称空间用于调试和把错误等输出到“控制台”上,需要结合使用../Firebug/firebug.js。
Control:我们通常所说的控件类,它提供各种各样的控件,比如上节中说的图层开关LayerSwitcher,编辑工具条EditingToolbar等等。加载控件的例子:
????????class?=?new?OpenLayers.Map('map',?{?controls:?[]?});
map.addControl(new?OpenLayers.Control.PanZoomBar());
map.addControl(new?OpenLayers.Control.MouseToolbar());
Events:用于实现OpenLayers的事件机制。具体来说, OpenLayers中的事件分为两种,一种是浏览器事件,例如mouseup,mousedown之类的;另外一种是自定义的,如addLayer之类 的。OpenLayers中的事件机制是非常值得我们学习的,后面将具体讨论。
Feature:我们知道:Feature是geography?和attributes的集合。在OpenLayers中,特别地OpenLayers.Feature?类由一个marker?和一个lonla组成。
?
OpenLayers.?Feature.WFS与OpenLayers.?Feature.?Vector继承于它。
Format:此类用于读/写各种格式的数据,它的子类都分别创建了各个格式的解析器。这些格式有:XML、GML、GeoJSON、GeoRSS、JSON、KML、WFS、WKT(Well-Known?Text)。
Geometry:怎么翻译呢,几何?是对地理对象的描述。它的子类有 Collection、Curve、LinearRing、LineString、MultiLineString、MultiPoint、 MultiPolygon、Point、Polygon、Rectangle、Surface,正是这些类的实例,构成了我们看到的地图。需要说明的是, Surface?类暂时还没有实现。
Handler:这个类用于处理序列事件,可被激活和取消。同时,它也有命名类似于浏览 器事件的方法。当一个handler?被激活,处理事件的方法就会被注册到浏览器监听器listener?,以响应相应的事件;当一个handler被取 消,这些方法在事件监听器中也会相应的被取消注册。Handler通过控件control被创建,而control通过icon表现。
Icon:在计算机屏幕上以图标的形式呈现,有url、尺寸size和位置position3个属性。一般情况,它与?OpenLayers.Marker结合应用,表现为一个Marker。
Layer:图层。
Map:网业中动态地图。它就像容器,可向里面添加图层Layer和控件Control。实际上,单个Map是毫无意义的,正是Layer和Control成就了它。
Marker:它的实例是OpenLayers.LonLat?和OpenLayers.Icon的集合。通俗一点儿说,Icon附上一定的经纬度就是Marker。
它们的组合关系是:
Popup:地图上一个小巧的层,实现地图“开关”功能。使用例子:
Class?=?new?OpenLayers.Popup("chicken",
???????????????????new?OpenLayers.LonLat(5,40),
???????????????????new?OpenLayers.Size(200,200),
???????????????????"example?popup",
???????????????????true);
map.addPopup(popup);
Renderer:渲染类。在OpenLayers中,渲染功能是作为矢量图层的一个属性存在的,我们称之为渲染器,矢量图层就是通过这个渲染器提供的方法将矢量数据显示出来。以SVG和VML为例,继承关系是这样的:
至于OpenLayers.?Renderer.?Elements为什么要存在,以及它的渲染机制,后面会说。
Tile:设计这个类用于指明单个“瓦片”Tile,或者更小的分辨率。Tiles存储它们自身的信息,比如url和size等。它的类继承关系如下:
????
Util:“跑龙套”的类。
写到这里,可以看到OpenLayers?的类缠绕的挺麻烦的,接下来的文章将从代码部分分析更细部的东西。
(三)BaseTypes?:定义底层类与定制JS内置类
??? 先说基类型BaseTypes下,OpenLyers构建的“自己”的类。它们分别是:OpenLayers.?LonLat、 OpenLayers.?Pixel、OpenLayers.Size、OpenLayers.?Element、OpenLayers.?Bounds 和OpenLayers.?Class。下面分别介绍:
OpenLayers.?LonLat:经纬度类,其实例为地图提供一经度、纬度对,即 位置。有两个属性lon(x-axis?coodinate?)和lat(y-axis?coordinate?)。这里说明一下,怎么经纬度又与x轴坐 标、y轴坐标纠缠在一起?是这样:当地图是在地理坐标投影下,它就是经纬度;不然就是地图上的x/y轴坐标。除构造函数外,实现了五个函数:
toShortString:function() 把坐标转换为字符串;
clone:function() 复制一个LonLat对象;
Add:function(lon,lat) 改变现有地图的位置;
return?new?OpenLayers.LonLat(this.lon?+?lon,?this.lat?+?lat);
equals:function(ll) 判断传入的lon,lat对是否与当前的相等;
wrapDateLine:function(maxExtent) 复制下(lon,lat),指定为边界的最大范围。
OpenLayers.?Pixel:像素类,在显示器上以(x,y)坐标的的形式呈现像素位置。有两个属性x坐标、y坐标,提供四个成员函数:
clone:function()?拷贝像素;
equals:function(px)??判断两像素是否相等;
add:function(x,y)? 改变(x,y)使其成为新像素;
return?new?OpenLayers.Pixel(this.x?+?x,?this.y?+?y);
offset:function(px) 调用add()使像素位置发生偏移。
newPx?=?this.add(px.x,?px.y);
OpenLayers.Size:也有两个属性,宽度width、高度height。实现了两个成员函数:clone:function()和equals:function(sz)不多说了。
OpenLayers.?Element:在这个名称空间下,开发者写了好多API,有 visible、toggle、hide、show、remove、getHeight、getDimensions和getStyle,以实现元素的显 示、隐藏、删除、取得高度,取得范围等功能。以getHeight函数为例我们看看它的代码:
/**
?????*?APIFunction:?getHeight
?????*??
?????*?Parameters:
?????*?element?-?{DOMElement}
?????*?
?????*?Returns:
?????*?{Integer}?The?offset?height?of?the?element?passed?in
?????*/
????getHeight:?function(element)?{
????????element?=?OpenLayers.Util.getElement(element);
????????return?element.offsetHeight;
????}
这里涉及到文档对象模型DOM的一些东西,函数本身很简单,最后返回元素的高度。
OpenLayers.?Bounds:在这个类中,数据以四个浮点型数left, ?bottom,?right,?top?的格式存储,它是一个像盒子一样的范围。它实现了三个描述一个Bound的函数:toString、 toArray和toBBOX。其中,toString的代码如下:
/**?
?????*?APIMethod:?toString
?????*?
?????*?Returns:
?????*?{String}?String?representation?of?bounds?object.?
?????*??????????(ex.<i>"left-bottom=(5,42)?right-top=(10,45)"</i>)
?????*/
????toString:function()?{
????????return?(?"left-bottom=("?+?this.left?+?","?+?this.bottom?+?")"
?????????????????+?"?right-top=("?+?this.right?+?","?+?this.top?+?")"?);
????}
结果类似于"left-bottom=(5,42)?right-top=(10,45)"
三个Bound数据来源函数:fromString、fromArray和fromSize;
五个获取对象属性的函数:getWidth、getHeight、getSize、getCenterPixel、getCenterLonLat;
余下还有:add:function(x,y),extend:function (object),containsLonLat,containsPixel,contains,intersectsBounds, containsBounds,determineQuadrant,wrapDateLine。以函数extend为例,看看源码。
extend:function(object)?{
????????var?bounds?=?null;
????????if?(object)?{
????????????switch(object.CLASS_NAME)?{
????????????????case?"OpenLayers.LonLat":????
????????????????????bounds?=?new?OpenLayers.Bounds??? (object.lon,?object.lat,?object.lon,?object.lat);
????????????????????break;
????????????????case?"OpenLayers.Geometry.Point":
????????????????????bounds?=?new?OpenLayers.Bounds(object.x,?object.y,object.x,?object.y);
????????????????????break;?????????????????
????????????????case?"OpenLayers.Bounds":???
????????????????????bounds?=?object;
????????????????????break;
????????????}
????????????if?(bounds)?{
????????????????if?(?(this.left?==?null)?||?(bounds.left?<?thi???????????????????? s.left))?{
?? ??????????????? ? this.left?=?bounds.left;}
????????????????if?(?(this.bottom?==?null)?||?(bounds.bottom?<???????????????????? this.bottom)?)?{
????????????????????this.bottom?=?bounds.bottom;}?
????????????????if?(?(this.right?==?null)?||?(bounds.right?>?t??????????????????? his.right)?)?{
????????????????????this.right?=?bounds.right;}
????????????????if?(?(this.top?==?null)?||?(bounds.top?>?this.??????????????????? top)?)?{?
????????????????????this.top?=?bounds.top;}
????????????}
????????}
????}
可以看出,对Bounds的扩展可以有三种形式:point,?lonlat,?或者bounds,计算的条件是零坐标是在屏幕的左上角。
OpenLayers.?Class:这个类是OpenLayers?中的“大红人”,只要创建其他类就得用它,同时也实现了多重继承。用法如下:
单继承创建:class?=?OpenLayers.Class(prototype);
多继承创建:class?=?OpenLayers.Class(Class1,?Class2,?prototype);
??? 净说底层类了,对js内置类的扩展下回写。