OpenLayers项目分析——项目介绍

Posted 疯子加天才

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenLayers项目分析——项目介绍相关的知识,希望对你有一定的参考价值。

OpenLayers 是由MetaCarta公司开发的,用于WebGIS客户端的javascript包,目前的最高版本是2.7 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文件为例。 

  

[javascript] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. <script src="../lib/OpenLayers.js"></script>  
  2. <script type="text/javascript">  
  3.       var lon = 5;    //x-axis coodinate in map units  
  4.       var lat = 40;   //y-axis coordinate in map units  
  5.       var zoom = 5;   //number of zoom levels  
  6.       var map, layer;   
  7.   //声明变量map、layer;等同于 var map = null; var layer = null;  
  8.       map = new OpenLayers.Map(\'map\');  
  9.       //实例化一个地图类OpenLayers.Map  
  10.       layer = new OpenLayers.Layer.WMS( "OpenLayers WMS",   
  11.                   "http://labs.metacarta.com/wms/vmap0", {layers: \'basic\'} );  
  12.       //以WMS的格式实例化图层类OpenLayers.Layer  
  13.       map.addLayer(layer);  
  14.       map.zoomToExtent(new  OpenLayers.Bounds(-3.922119,44.335327,  
  15.       4.866943,49.553833));  
  16.   //在Map对象上加载Layer对象,并用map.zoomToExtent函数使地图合适地显示  
  17.   map.addLayer(new OpenLayers.Layer.GML("GML", "gml/polygon.xml"));  

 

 

    //再在刚加载的WMS文件上,加载一GML文件

 

  剩下的工作就是,加上一些控件OpenLayers.Control之类的东西,比如LayerSwitcher等。它们会在地图浏览的“窗口”上增加一些工具栏或是“按钮”,增加互动性和功能性。

   例如:

   map.addControl(new 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等等。加载控件的例子 : 

[代码]js代码:

1 class = new OpenLayers.Map(\'map\', { controls: [] });
2 map.addControl(new OpenLayers.Control.PanZoomBar());
3 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 被激活,处理事件的方法就会被注册到浏览器 监  ting 器listener ,以响应相应的事件;当一个handler被取消,这些方法在事件 监  ting 器中也会相应的被取消注册。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:地图上一个小巧的层,实现地图“开关”功能。使用例子:

[代码]js代码:

1 Class = new OpenLayers.Popup("chicken",
2        new OpenLayers.LonLat(5,40),
3          new OpenLayers.Size(200,200),
4                  "example popup",
5                  true);
6     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的代码如下:

[代码]js代码:

01 /**
02    * APIMethod: toString
03    *
04    * Returns:
05    * {String} String representation of bounds object.
06    *          (ex.<i>"left-bottom=(5,42) right-top=(10,45)"</i>)
07    */
08   toString:function() {
09       return "left-bottom=(" this.left + "," this.bottom + ")"
10                " right-top=(" this.right + "," this.top + ")" );
11   }
结果类似于"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为例,看看源码。

[代码]js代码:

01 extend:function(object) {
02         var bounds = null;
03         if (object) {
04             switch(object.CLASS_NAME) {
05                 case "OpenLayers.LonLat":   
06                     bounds = new OpenLayers.Bounds(object.lon, object.lat, object.lon, object.lat);
07                     break;
08                 case "OpenLayers.Geometry.Point":
09                     bounds = new OpenLayers.Bounds(object.x, object.y,object.x, object.y);
10                     break;                
11                 case "OpenLayers.Bounds":  
12                     bounds = object;
13                     break;
14             }
15             if (bounds) {
16                 if ( (this.left == null) || (bounds.left < this.left)) {
17                      this.left = bounds.left;}
18                 if ( (this.bottom == null) || (bounds.bottom <this.bottom) ) {
19                     this.bottom = bounds.bottom;}
20                 if ( (this.right == null) || (bounds.right > this.right) ) {
21                     this.right = bounds.right;}
22                 if ( (this.top == null) || (bounds.top > this.top) ) {
23                     this.top = bounds.top;}
24             }
25         }
26     }

可以看出,对Bounds的扩展可以有三种形式:point, lonlat, 或者bounds,计算的条件是零坐标是在屏幕的左上角。
  OpenLayers. Class:这个类是OpenLayers 中的“大红人”,只要创建其他类就得用它,同时也实现了多重继承。用法如下:
  单继承创建:class = OpenLayers.Class(prototype);
  多继承创建:class = OpenLayers.Class(Class1, Class2, prototype);
    净说底层类了,对js内置类的扩展下回写。
 
(三)BaseTypes: OpenLayers中定制JavaScript内置类
  OpenLayers不仅“自己”写了一些底层的类,像上回说的那些都是。同时也定制了一些JS的一些内置类,即对JS内置类的扩展。这个扩展主要包含3类:String,Number,Function,存在于BaseTypes.js文件中。
  String:
OpenLayers对string类型定制了8个方法,分别是startsWith、contains、trim和camelize;还有另外4个方法:String. startsWith、String. contains、String.trim和String. Camelize,它们将会在3.0Version中被删除,可能是以前版本遗留下来的,这里就不说它们了。

[代码]js代码:

01 //Test whether a string starts with another string.
02 startsWith: function(str, sub) {
03   return (str.indexOf(sub) == 0);
04   }
05  
06 //Test whether a string contains another string.
07   contains: function(str, sub) {
08       return (str.indexOf(sub) != -1);
09   }
10  
11   //Removes leading and trailing whitespace characters from a string.
12   trim: function(str) {
13       return str.replace(/^\\s*(.*?)\\s*$/, "$1");   
14   }
15  
16  //Camel-case a hyphenated string.
17 //Ex."chicken-head"becomes"chickenHead",
18  //and"-chicken-head"becomes"ChickenHead".
19  // “骆驼”化带有连字符的字符串。
20  camelize: function(str) {
21       var oStringList = str.split(\'-\');
22       var camelizedString = oStringList[0];
23       for (var i = 1; i < oStringList.length; i++) {
24           var s = oStringList[i];
25           camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
26       }
27       return camelizedString;
28   }

Number:
项目仅对number类型扩展了一个方法OpenLayers. Number. limitSigDigs(还有一个方法Number. limitSigDigs,同样在3.0中会删除)。

[代码]js代码:

01 //Limit the number of significant digits on an integer.
02     limitSigDigs: function(num, sig) {
03         var fig;
04         if(sig > 0) {
05             fig = parseFloat(num.toPrecision(sig));
06         else {
07             fig = 0;
08         }
09         return fig;
10     }

Function:
扩展了两个方法bind 和bindAsEventListener(同样存在Function.bind和Function. bindAsEventListener两个被“遗弃”的函数)。

[代码]js代码:

01 //Bind a function to an object. 
02  //Method to easily create closures with\'this\' altered.
03  bind: function(func, object) {
04      // create a reference to all arguments past the second one
05      var args = Array.prototype.slice.apply(arguments, [2]);
06      return function() {
07          // Push on any additional arguments from the actual function call.
08          // These will come after those sent to the bind call.
09          var newArgs = args.concat(
10              Array.prototype.slice.apply(arguments, [0])
11          );
12          return func.apply(object, newArgs);
13      };
14  }
15  
16  //Bind a function to an object, and configure it to receive the event
17  //object as first parameter when called.
18  bindAsEventListener: function(func, object) {
19      return function(event) {
20          return func.call(object, event || window.event);
21      };
22  }

里说说这两个方法。
首先看看bind方法,这是一个能够被Function的实例得到的方法,如下所示:

[代码]js代码:

01 Function.prototype.bind = function() {
02 var _method = this, args = [], object = arguments[0];
03 for (var i = 1; i < arguments.length; i++)
04 args.push(arguments[i]);
05 return function(moreargs) {
06 for (var i = 0; i < arguments.length; i++)
07 args.push(arguments[i]);
08 return  _method.apply(object, args);
09 }
10 };

_method 代表Function实例自身,bind可接收多个参数,不过它绑定是是第一个参数,该参数是一个function或者是调用环境,后面的都是执行函数的参数。

[代码]js代码:

1 Function.prototype.bindAsEventListener = function(object) {
2 var  _method = this;
3 return function(event) {
4 return  _method.call(object, event || window.event);
5 }
6 };

这里只是将object作为_method 引用的环境,就是说现在可以在object对象中这样使用,
object. _method (event||window.event)。
也许你注意到了Funtion扩展的两个方法一个用到了call而另一个用的是apply,其实这两个并没有什么太大的区别,只是参数传递的形式不同,如若没有参数要传递,那么这两个是一样的:
apply(obj[,argumentsArray]),call(obj[,arg1[,arg2…]])。
GIS,核心是什么?数据?平台?服务?  
  空间数据的特征、表达方式?
  地理数据的模型(结构)?
  在OpenLayers空间数据的实现主要存在OpenLayers. Geometry类及其子类中。我们先看下面的两个图片,表现了这些类的继承关系。从图上可以清楚的看出MultiPoint、Polygon和MultiLineString 这三个类实现了多重继承,即直接继承于Geometry类,又继承于Collection类(为什么要这样实现?)。
  OpenLyers对于Geometry对象的组织是这样的,其实最基础的就是点,然后MultiPoint由点构成,继承自Openlayers.Geometry.Collection,而LinearRing,LineString均由Point构成,
Polygon由OpenLayers.Geometry.LinearRing构成。OpenLyers在解析数据时候,将所有的面、线包含的点全部都对象化为Openlayers.Geometry.Point。有人测试这里面存在问题:解析矢量数据慢,甚至在点数多的情况下,会使浏览器“崩溃”掉。想想是有道理的:OpenLyers在解析数据时候,将所有的面、线包含的点全部都对象化为点对象t,并首先将所有的对象读取到内存,得到一个Feature的集合,然后将这个集合提交给渲染器进行渲染。这样渲染起来当然慢了。至于为什么要这样,可能是OpenLayers项目本身在标准上,在框架结构上做的比较好,更细部的东西还得优化呀。可话又说回来,OpenLayers作为一个优秀的开源JS框架,学习借鉴的意义要比应用的意义大吧。 


  下面以Point和Collection为例来说明其内部实现过程,先看Point。
  我们知道一个点就是一个坐标对(x,y)嘛,当然它得有两个属性x,y。在point类里,提供了六个成员函数,分别是clone、distanceTo、equals、move、rotate和resize。看看计算两点距离的函数是怎么写的:

[代码]js代码:

01 distanceTo: function(point) {
02         var distance = 0.0;
03         if ( (this.x != null) && (this.y != null) &&
04              (point != null) && (point.x != null) && (point.y != null) ) {            
05              var dx2 = Math.pow(this.x - point.x, 2);
06              var dy2 = Math.pow(this.y - point.y, 2);
07              distance = Math.sqrt( dx2 + dy2 );
08         }
09         return distance;
10     }
11   在collection集合对象中,可以存放同一类型的地理对象,也可以放不同的地理对象。定义了一个属性component ,以数组对象的形式存储组成collection对象的“组件”。别的不说了,看一个获取集合大小的函数getLength:
12     getLength: function() {
13         var length = 0.0;
14         for (var i = 0; i < this.components.length; i++) {
15             length += this.components[i].getLength();
以上是关于OpenLayers项目分析——项目介绍的主要内容,如果未能解决你的问题,请参考以下文章

OpenLayers缓冲分析—重难点

openlayers应用:加载百度离线瓦片

基于 Openlayers 实现的地图常用功能工具集合

openlayers3应用:加载百度离线瓦片地图

openlayers和cesium实现地图二三维切换

openlayers5-webpack 入门开发系列一初探篇(附源码下载)

(c)2006-2024 SYSTEM All Rights Reserved IT常识