WMS 是OGC制定的标准 WEB GIS 协议,现在众多的图形提供商都提供了自己的WEB图形服务,例如:ArcIMS、GoogleMaps、KaMap等等、要使用这些服务并制作自己的WEB客户端,使用 OpenLayers 是很方便的事情,其中 WMS 是比较通用的协议,尤其适合服务器端矢量图形的生成,但是在我们自己的项目中发现由于WMS每次发送给服务器的都是几何坐标的格式化字符串来表达视野,这导致服务器端在提供瓦片时无法很好的进行高效的服务,几乎总是需要对瓦片进行拼接和剪裁,通过分析 GOOGLE 和 TMS 协议,发现很多服务都不采用几何坐标的字符串来表达视野,而是直接提供瓦片的行列号,这样服务器端甚至可以直接使用一个简单的HTTP服务器就可以了,基于以上考虑决定扩展OpenLayers来提供一个自己的瓦片服务的客户端;

原理很简单,就是在构造 WMS请求的URL时,采用自己的方式进行构造,代码如下:

 




1 
   /* 
   *
 
    2 
    * Class: ShineEnergy.Layer.TileImage
 
    3 
    * 
 
    4 
    * Inherits from:
 
    5 
    * - <OpenLayers.Layer.WMS>
 
    6 
     
   */ 
   
 
    7 
   ShineEnergy.Layer.TileImage  
   = 
    OpenLayers.Class(OpenLayers.Layer.WMS, {
 
    8 
   
 
    9 
     
   /* 
   *
 
   10 
    * Constructor: ShineEnergy.Layer.TileImage
 
   11 
    * 
 
   12 
    * Parameters:
 
   13 
    * name - {String} A name for the layer
 
   14 
    * url - {String} Base url for the TileImage
 
   15 
    * params - {Object} An object with key/value pairs representing the
 
   16 
    * GetMap query string parameters and parameter values.
 
   17 
    * options - {Object} Hashtable of extra options to tag onto the layer
 
   18 
     
   */ 
   
 
   19 
    initialize:  
   function 
   (name, url, params, options) {
 
   20 
    OpenLayers.Layer.WMS.prototype.initialize.apply( 
   this 
   , arguments);
 
   21 
    }, 
 
   22 
   
 
   23 
     
   /* 
   *
 
   24 
    * APIMethod:destroy
 
   25 
     
   */ 
   
 
   26 
    destroy:  
   function 
   () {
 
   27 
     
   // 
    for now, nothing special to do here.  
   
 
   28 
     
    OpenLayers.Layer.WMS.prototype.destroy.apply( 
   this 
   , arguments); 
 
   29 
    },
 
   30 
    
 
   31 
     
   /* 
   *
 
   32 
    * APIMethod: clone
 
   33 
    * 
 
   34 
    * Parameters:
 
   35 
    * obj - {Object}
 
   36 
    * 
 
   37 
    * Returns:
 
   38 
    * {<ShineEnergy.Layer.TileImage>} An exact clone of this <ShineEnergy.Layer.TileImage>
 
   39 
     
   */ 
   
 
   40 
    clone:  
   function 
    (obj) {
 
   41 
    
 
   42 
     
   if 
    (obj  
   == 
     
   null 
   ) {
 
   43 
    obj  
   = 
     
   new 
    ShineEnergy.Layer.TileImage( 
   this 
   .name,
 
   44 
     
   this 
   .url,
 
   45 
     
   this 
   .options);
 
   46 
    }
 
   47 
   
 
   48 
     
   // 
   get all additions from superclasses 
   
 
   49 
     
    obj  
   = 
    OpenLayers.Layer.WMS.prototype.clone.apply( 
   this 
   , [obj]);
 
   50 
   
 
   51 
     
   // 
    copy/set any non-init, non-simple values here 
   
 
   52 
     
   
 
   53 
     
   return 
    obj;
 
   54 
    }, 
 
   55 
    
 
   56 
     
   /* 
   *
 
   57 
    * Method: getURL
 
   58 
    * 
 
   59 
    * Parameters:
 
   60 
    * bounds - {<OpenLayers.Bounds>}
 
   61 
    * 
 
   62 
    * Returns:
 
   63 
    * {String} A string with the layer's url and parameters and also the 
 
   64 
    * passed-in bounds and appropriate tile size specified as 
 
   65 
    * parameters
 
   66 
     
   */ 
   
 
   67 
    getURL:  
   function 
    (bounds) {
 
   68 
    bounds  
   = 
     
   this 
   .adjustBounds(bounds);
 
   69 
     
   var 
    res  
   = 
     
   this 
   .map.getResolution();
 
   70 
     
   var 
    tileOriginY  
   = 
     
   this 
   .options.maxExtent.top;
 
   71 
     
   var 
    tileOriginX  
   = 
     
   this 
   .options.maxExtent.left;
 
   72 
     
   var 
    x  
   = 
    Math.round((bounds.left  
   - 
    tileOriginX)  
   / 
    (res  
   * 
     
   this 
   .tileSize.w));
 
   73 
     
   var 
    y  
   = 
    Math.round((tileOriginY  
   - 
    bounds.bottom)  
   / 
    (res  
   * 
     
   this 
   .tileSize.h));
 
   74 
     
   var 
    z  
   = 
     
   this 
   .map.getZoom();
 
   75 
     
   var 
    path  
   = 
     
   " 
   ?LAYER= 
   " 
     
   + 
     
   this 
   .params.LAYERS  
   + 
     
   " 
   &X= 
   " 
     
   + 
    x  
   + 
     
   " 
   &Y= 
   " 
     
   + 
    y  
   + 
     
   " 
   &Z= 
   " 
     
   + 
    z  
   + 
     
   " 
   &S=Map 
   " 
   ; 
 
   76 
     
   var 
    url  
   = 
     
   this 
   .url;
 
   77 
     
   if 
    (url  
   instanceof 
    Array) {
 
   78 
    url  
   = 
     
   this 
   .selectUrl(path, url);
 
   79 
    }
 
   80 
     
   return 
    url  
   + 
    path;
 
   81 
    },
 
   82 
   
 
   83 
    CLASS_NAME:  
   " 
   ShineEnergy.Layer.TileImage 
   " 
   
 
   84 
   });
 
   85


 经过如上简单的进行扩展,就可以使用实现自定义的 WEB GIS 协议,服务器端只需要根据 LAYER/X/Y/Z参数可以确定唯一的一张瓦片图片,返回给客户端就可以了,同时也方便服务器端采用缓存优化处理;

在上面的例子中还有一个参数“S”,这个参数是备用参数,你也可以当做是一个展示如何增加自定义参数的例子来修改,例如增加控制客户端的缓存行为的功能就可以根据时间产生不同的参数来实现;

最后补充一点,WMS协议在根据视野填充瓦片的时候,是根据左下角的地理坐标开始进行填充的,而ARCGIS等工具则是根据左上角进行行列号进行编排的,所以要想能够和其他的图层完全配准,那么必须根据DPI和比例尺计算出一个确定的视野高度,这个高度要求能够正好在最大的视野情况下正好有整数个瓦片进行平铺;