openlayers3瓦片加载的源码浅析与小结

本文适用于对ol3的使用有一定了解,目的是为了对ol3瓦片加载部分有更深入的了解。ol3源码极其庞大,本文仅仅只包括瓦片图层加载的这一部分逻辑。

一、类图与逻辑

openlayers3瓦片加载的源码浅析与小结_第1张图片
ol-tilerender.png

上图中列了关于瓦片图层加载相关的重要方法。
1)Map对象初始化时根据options.renderer创建ol.renderer.Map的实例,默认是ol.renderer.canvas.Map;
2)ol.render.canvas.Map实现了抽象方法createLayerRenderer,这是一个简单工厂,根据不同的图层创建对应的ol.renderer.Layer。其中ol.layer.Tile对应的就是ol.renderer.canvas.TileLayer;
3)ol.renderer.canvas.TileLayer.prepareFrame调用source对应的
TileGrid.getTileRangeForExtentAndResolution获取可视范围内的瓦片范围,并循环遍历加载瓦片;
4)TileGrid在初始化时就计算出了对应layer的所有瓦片范围:
i)calculateTileRanges_-》循环遍历resolutions_,调用
getTileRangeForExtentAndZ,根据extent计算瓦片范围;
ii)getTileRangeForExtentAndResolution计算瓦片的范围:

ol.tilegrid.TileGrid.prototype.getTileRangeForExtentAndResolution = function(extent, resolution, opt_tileRange) {
  var tileCoord = ol.tilegrid.TileGrid.tmpTileCoord_;
  //根据extent的左下角的计算瓦片坐标;
  this.getTileCoordForXYAndResolution_(
      extent[0], extent[1], resolution, false, tileCoord);
  var minX = tileCoord[1];
  var minY = tileCoord[2];
    //根据extent的右上角的计算瓦片坐标;
   this.getTileCoordForXYAndResolution_(
      extent[2], extent[3], resolution, true, tileCoord);
  //得到某个resolution级别下的瓦片范围(左下角瓦片坐标 - 右上角瓦片坐标)
  return ol.TileRange.createOrUpdate(
      minX, tileCoord[1], minY, tileCoord[2], opt_tileRange);
 };

//根据extent左下角及右上角的坐标-origin后得到地图的长宽 / resolution得到像素值;然后 / tileSize 得到需要多少张瓦片;
//当计算extent右上角的瓦片坐标时,因为瓦片坐标是从0开始计算,当瓦片数量为例如1.5此类小数时,
//应该是2张瓦片,从0开始计算,那么XY就应该向下取整,取1;0,1两张瓦片;
ol.tilegrid.TileGrid.prototype.getTileCoordForXYAndResolution_ = function(  
        x, y, resolution, reverseIntersectionPolicy, opt_tileCoord) {
  var z = this.getZForResolution(resolution);
  var scale = resolution / this.getResolution(z);
  var origin = this.getOrigin(z);
  var tileSize = ol.size.toSize(this.getTileSize(z), this.tmpSize_);

  var adjustX = reverseIntersectionPolicy ? 0.5 : 0;
  var adjustY = reverseIntersectionPolicy ? 0 : 0.5;
  var xFromOrigin = Math.floor((x - origin[0]) / resolution + adjustX);
  var yFromOrigin = Math.floor((y - origin[1]) / resolution + adjustY);
  var tileCoordX = scale * xFromOrigin / tileSize[0];
  var tileCoordY = scale * yFromOrigin / tileSize[1];

  if (reverseIntersectionPolicy) {
    tileCoordX = Math.ceil(tileCoordX) - 1;
    tileCoordY = Math.ceil(tileCoordY) - 1;
  } else {
    tileCoordX = Math.floor(tileCoordX);
    tileCoordY = Math.floor(tileCoordY);
  }

  return ol.tilecoord.createOrUpdate(z, tileCoordX, tileCoordY, opt_tileCoord);
};

二、各种瓦片加载的小结

通过上述分析后,应该能较好的理解瓦片的坐标是如何计算的,当应用到不同的地图瓦片加载时就可以得心应手。以下通过不同的几种类型继续说明瓦片计算的方式:

1、TMS瓦片加载

先看看TMS瓦片的规则,origin在左下角,X轴从左至右递增,Y轴从下往上递增(先计算左下角,然后计算右上角)。


openlayers3瓦片加载的源码浅析与小结_第2张图片
TMS瓦片规则

而TileGrid设置origin为ol.extent.getBottomLeft(extent)后,规则也是从左下角到右上角,X轴从左至右递增,Y轴从下往上递增,与TMS规则是完全一致的,参考代码与参考效果如下:

   var resolutions = [];
        var tileSize = 256;
        var extent = [12665080.52765571, 2550703.6338763316, 12725465.780000998, 2601457.820657688];//深圳地区
        var projection = new ol.proj.get("EPSG:3857");
        var projectionExtent = projection.getExtent();

        for (var i = 0; i < 19; i++) {
            resolutions[i] = Math.pow(2, 18 - i);
        }            

        var tilegrid = new ol.tilegrid.TileGrid({
            origin: ol.extent.getBottomLeft(projectionExtent),
            resolutions: resolutions,
            extent: projectionExtent,//extent,
            tileSize: [256, 256],
        });         

        var map = new ol.Map({
            target: "map",
            layers: [
          ////调试瓦片
            new ol.layer.Tile({
                source: new ol.source.TileDebug({
                    projection: projection,
                    tileGrid: tilegrid,
                    tileSize: [256, 256],
                    extent :  projectionExtent,
                    wrapX: false
                }),
            })
            ],
            view: new ol.View({
                projection: projection,
                center: [12697184.079535482, 2563239.3065151004],//深圳
                resolutions: resolutions,
            }),
        });
        map.getView().setZoom(1);
openlayers3瓦片加载的源码浅析与小结_第3张图片
示意图

假如上面代码中,我想只显示深圳地区的瓦片,其余的瓦片不显示,这种场景是很普遍的,那么代码调整如下:

  var tilegrid = new ol.tilegrid.TileGrid({
            origin: ol.extent.getBottomLeft(projectionExtent),  //origin位置不能变!!!!!!
            resolutions: resolutions,
            extent:  extent,//projectionExtent //设置extent为深圳片区的extent;
            tileSize: [256, 256],
        });      
//..................
////调试瓦片
            new ol.layer.Tile({
                source: new ol.source.TileDebug({
                    projection: projection,
                    tileGrid: tilegrid,
                    extent: extent,//projectionExtent //设置extent为深圳片区的extent;
                    wrapX: false
                }),
            })

2、WMTS瓦片加载

WMTS规则如下图,origin在左上角,X轴从左至右递增,Y轴是从上往下递增(先计算左上角,然后计算右下角)

openlayers3瓦片加载的源码浅析与小结_第4张图片
WMTS规则

首先将tileGrid设置origin为左上角:ol.extent.getTopLeft(projectionExtent), 但是TileGrid始终都是先计算左下角的瓦片坐标,然后计算右上角的瓦片坐标,因此Y轴是相反的。那么修改Y轴坐标就可以得到正确瓦片坐标:

var tilegrid = new ol.tilegrid.TileGrid({
            origin: ol.extent.getTopLeft(projectionExtent),  //WMTS Origin在左上角,origin位置不能变;
            resolutions: resolutions,
            extent: extent,
            tileSize: [256, 256],
        });
//其余代码略.....
new ol.layer.Tile({
       source: new ol.source.TileImage({
       projection: projection,
        tileGrid: tilegrid(),
        tileUrlFunction: function (tileCoord, pixelRatio, proj) {
              if (!tileCoord) {
                  return "";
               }
              var z = tileCoord[0];
              var x = tileCoord[1];
              var y = -tileCoord[2] - 1; //y轴取反,-1目的是为了从0开始计数;

              return ''; //自行设置URL ,请注意 WMTS中用TileRow标识Y,用TileCol表示X;
            }
        }),
  })

3、百度地图瓦片加载

百度瓦片片规则遵从TMS规则,如下图:Origin在[0,0],X轴从左至右递增,Y轴从下往上递增(从左下角到右上角)。

openlayers3瓦片加载的源码浅析与小结_第5张图片
百度地图

从百度的瓦片规则看出来,与TileGrid的规则是完全一致,将origin设置为[0,0]即可。参考代码如下:

 var tilegrid = new ol.tilegrid.TileGrid({
            origin: [0, 0],
            resolutions: resolutions,
            extent: extent,//projectionExtent,
            tileSize: [256, 256],
        });

 var tilesource = new ol.source.TileImage({
            projection: projection,
            tileGrid: tilegrid,
            tileUrlFunction: function (xyz, obj1, obj2) {
                if (!xyz) {
                    return "";
                }
                var z = xyz[0]+ 11; //从第11级开始加载;深圳地区;
                var x = xyz[1];
                var y = xyz[2];
                if (x < 0) {
                    x = "M" + (-x);
                }
                if (y < 0) {
                    y = "M" + (-y);
                }                    
                return "http://online3.map.bdimg.com/tile/?qt=tile&x=" + x + "&y=" + y + "&z=" + z + "&styles=pl&udt=20141119&scaler=1";                   
            }
        });

4、腾讯地图瓦片加载

腾讯地图完全遵守TMS规则,地图投影坐标系采用Web Mercator投影,最小缩放级别为第4级。参考代码如下:

//QQ地图完全遵守TMS规则;
    var tileGrid = new ol.tilegrid.TileGrid({
        resolutions: resolutions3857,
        tileSize: [256, 256],
        extent: projection3857Extent,
        origin: ol.extent.getBottomLeft(projection3857Extent), //Origin左下角
    });

    var tilesource = new ol.source.TileImage({
        tileUrlFunction: function (xyz, obj1, obj2) {
            if (!xyz) {
                return "";
            }
            var z = xyz[0];
            var x = xyz[1];
            var y = xyz[2];
            return "http://rt1.map.gtimg.com/realtimerender?z=" + z + "&x=" + x + "&y=" + y + "&type=vector&style=0&v=1.1.2"
        },
        projection: projection3857,
        tileGrid : tileGrid
    });

5 高德地图瓦片加载

高德地图瓦片遵从WMTS规则,如下图:


openlayers3瓦片加载的源码浅析与小结_第6张图片
高德地图
  var layerMap = new ol.layer.Tile({
    source: new ol.source.XYZ({
        tileUrlFunction: function (tileCoord) {
            var z = tileCoord[0];
            var x = tileCoord[1];
             var y = tileCoord[2];
             y = -y - 1;            
            return "http://webrd01.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x=" + x + "&y=" + y + "&z=" + z ;
        },
        tileGrid: tilegrid,
        extent: extent
    })
});

你可能感兴趣的:(openlayers3瓦片加载的源码浅析与小结)