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

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

一、类图与逻辑

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轴从下往上递增(先计算左下角,然后计算右上角)。


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);
示意图

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

  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轴是从上往下递增(先计算左上角,然后计算右下角)

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轴从下往上递增(从左下角到右上角)。

百度地图

从百度的瓦片规则看出来,与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规则,如下图:


高德地图
  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
    })
});
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容