OpenLayers源码学习18:图层Layer.Grid_1 Posted on 2015-03-18 | In OpenLayers学习 | 再往后一个子类就是Layer.Grid, 这个不知道会不会用上tile瓦片类… 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { // <OpenLayers.Size> tileSize: null, // 瓦片最开始的角落: 继承于layer's <maxExtent>. 默认是左下角 //"tl" (top left), "tr" (top right), "bl" (bottom left), and "br" (bottom right) tileOriginCorner: "bl", // <OpenLayers.LonLat>如果提供, 就按这个坐标对齐瓦片 tileOrigin: null, // 瓦片设置 tileOptions: null, //指定使用瓦片的类型 tileClass: OpenLayers.Tile.Image, //二维数组 表示行列 存储瓦片, Array(Array(<OpenLayers.Tile>)). grid: null, // 是否设置图层到single-tile模式(不知道干嘛的...) singleTile: false, // 仅用在single-tile模式, 瓦片/map的比率 ratio: 1.5, //仅用在 gridded mode, 拖动时瓦片缓存 buffer: 0, // 变换效果( "resize" "map-resize" null) transitionEffect: "resize", //加载瓦片数量 numLoadingTiles: 0, // 服务器分辨率 serverResolutions: null, //正在加载标志 loading: false, // {DOMElement}背景缓存 backBuffer: null, // 每次grid重新初始化更新 gridResolution: null, // back buffer is created新建时设置 backBufferResolution: null, // 左上角坐标缓存 backBufferLonLat: null, // 背景缓存的计时器 backBufferTimerId: null, // 删除动画延迟 removeBackBufferDelay: null, //瓦片类名 , 在style.css className: null, /** * 事件 * layer.events.register(type, obj, listener); * 支持事件类型: * addtile ,tileloadstart ,tileloaded ,tileerror ,retile */ // 对象包含以下属性: tilelon, tilelat, startcol,startrow gridLayout: null, // 1是从顶部开始, -1是从底部开始 rowSign: null, //变换事件 transitionendEvents: [ 'transitionend', 'webkitTransitionEnd', 'otransitionend', 'oTransitionEnd' ], //构造 initialize: function(name, url, params, options) { //先使用父类构造 OpenLayers.Layer.HTTPRequest.prototype.initialize.apply(this, arguments); //处理本类属性 this.grid = []; this._removeBackBuffer = OpenLayers.Function.bind(this.removeBackBuffer, this); this.initProperties(); this.rowSign = this.tileOriginCorner.substr(0, 1) === "t" ? 1 : -1; }, // 初始化 initProperties: function() { //单瓦片模式就没有清除buffer延迟, 否则就2500 if (this.options.removeBackBufferDelay === undefined) { this.removeBackBufferDelay = this.singleTile ? 0 : 2500; } //css类名 if (this.options.className === undefined) { this.className = this.singleTile ? 'olLayerGridSingleTile' : 'olLayerGrid'; } }, //把map对象的引用写在父类里, 更新样式 setMap: function(map) { OpenLayers.Layer.HTTPRequest.prototype.setMap.call(this, map); OpenLayers.Element.addClass(this.div, this.className); }, // removeMap: function(map) { this.removeBackBuffer(); }, //销毁, 先销毁本类, 再销毁父类 destroy: function() { this.removeBackBuffer(); this.clearGrid(); this.grid = null; this.tileSize = null; OpenLayers.Layer.HTTPRequest.prototype.destroy.apply(this, arguments); }, /** * APIMethod: mergeNewParams * 这个方法在父类里, 这会继承来 */ // 删除网格, clearGrid:function() { if (this.grid) { for(var iRow=0, len=this.grid.length; iRow<len; iRow++) { var row = this.grid[iRow]; for(var iCol=0, clen=row.length; iCol<clen; iCol++) { var tile = row[iCol]; this.destroyTile(tile);//删除二维数组的各个title } } this.grid = [];//各种置空 this.gridResolution = null; this.gridLayout = null; } }, //添加配置项 addOptions: function (newOptions, reinitialize) { var singleTileChanged = newOptions.singleTile !== undefined && newOptions.singleTile !== this.singleTile; //父类的addOptions OpenLayers.Layer.HTTPRequest.prototype.addOptions.apply(this, arguments); //几乎是重新初始化 if (this.map && singleTileChanged) { this.initProperties(); this.clearGrid(); this.tileSize = this.options.tileSize; this.setTileSize(); //init完 移动一次 this.moveTo(null, true); } }, //克隆 clone: function (obj) { if (obj == null) { obj = new OpenLayers.Layer.Grid(this.name, this.url, this.params, this.getOptions()); } //扩展父类 obj = OpenLayers.Layer.HTTPRequest.prototype.clone.apply(this, [obj]); // 瓦片的克隆 if (this.tileSize != null) { obj.tileSize = this.tileSize.clone(); } // 这些东西不拷贝, 而是用新的 空的 obj.grid = []; obj.gridResolution = null; obj.backBuffer = null; obj.backBufferTimerId = null; obj.loading = false; obj.numLoadingTiles = 0; return obj; }, // 地图移动时触发. 用于调整bounds // 参数 bounds - {<OpenLayers.Bounds>}, zoomChanged - {Boolean}, dragging - {Boolean} moveTo:function(bounds, zoomChanged, dragging) { //父级moveTo OpenLayers.Layer.HTTPRequest.prototype.moveTo.apply(this, arguments); //不传bounds, 就按map的当前extent bounds = bounds || this.map.getExtent(); if (bounds != null) { // 有grid或zoom改变了, 就必须forceReTile var forceReTile = !this.grid.length || zoomChanged; // 瓦片Bounds var tilesBounds = this.getTilesBounds(); // 当前 map 分辨率 var resolution = this.map.getResolution(); // 服务端支持的map resolution var serverResolution = this.getServerResolution(resolution); if (this.singleTile) { // 单瓦片模式 if ( forceReTile || (!dragging && !tilesBounds.containsBounds(bounds))) { if(zoomChanged && this.transitionEffect !== 'resize') { this.removeBackBuffer(); } if(!zoomChanged || this.transitionEffect === 'resize') { this.applyBackBuffer(resolution); } this.initSingleTile(bounds); } } else { // 为了减少循环次数, 有时需要 forceReTile forceReTile = forceReTile || !tilesBounds.intersectsBounds(bounds, { worldBounds: this.map.baseLayer.wrapDateLine && this.map.getMaxExtent() }); if(forceReTile) { if(zoomChanged && (this.transitionEffect === 'resize' || this.gridResolution === resolution)) { this.applyBackBuffer(resolution); } this.initGriddedTiles(bounds); } else { //正常move this.moveGriddedTiles(); } } } }, // 获得瓦片 // 传入一个瓦片在地图上的位置{<OpenLayers.LonLat>}, 计算出瓦片和像素偏移量. 没有返回null //返回结果的数据结构: tile ({<OpenLayers.Tile>}),i ({Number} x-pixel offset from top left), and j ({Integer} y-pixel offset from top left). getTileData: function(loc) { var data = null, x = loc.lon,//传入的经纬度 y = loc.lat, numRows = this.grid.length;//行数 if (this.map && numRows) { var res = this.map.getResolution(),//分辨率 tileWidth = this.tileSize.w, tileHeight = this.tileSize.h,//瓦片长宽 bounds = this.grid[0][0].bounds,//第一张瓦片的bounds left = bounds.left,//第一张瓦片的最左 top = bounds.top;//第一张瓦片的最顶 if (x < left) { // 处理视野内多个世界world地图 if (this.map.baseLayer.wrapDateLine) { var worldWidth = this.map.getMaxExtent().getWidth();//最大extent的宽度 var worldsAway = Math.ceil((left - x) / worldWidth);//距离world的比率 x += worldWidth * worldsAway;//乘一下 计算横向距离 } } // 瓦片距离给定坐标的偏移个数 // (给定坐标的经纬度 - 第一张瓦片的最左经纬度) / (分辨率 x 瓦片宽度) var dtx = (x - left) / (res * tileWidth); var dty = (top - y) / (res * tileHeight); // 二维数组的行列号 var col = Math.floor(dtx); var row = Math.floor(dty); if (row >= 0 && row < numRows) { var tile = this.grid[row][col];//放入二维数组进行缓存 if (tile) { data = { tile: tile, //计算瓦片的像素偏移 i: Math.floor((dtx - col) * tileWidth), j: Math.floor((dty - row) * tileHeight) }; } } } return data; }, //销毁瓦片 destroyTile: function(tile) { this.removeTileMonitoringHooks(tile); tile.destroy(); }, // 返回最接近的 服务端支持的分辨率 getServerResolution: function(resolution) { var distance = Number.POSITIVE_INFINITY;//近似值 resolution = resolution || this.map.getResolution();//分辨率 if(this.serverResolutions && OpenLayers.Util.indexOf(this.serverResolutions, resolution) === -1) { var i, newDistance, newResolution, serverResolution; for(i=this.serverResolutions.length-1; i>= 0; i--) { newResolution = this.serverResolutions[i]; newDistance = Math.abs(newResolution - resolution);//冒泡去找近似值最小的值 if (newDistance > distance) { break; } distance = newDistance; serverResolution = newResolution; } resolution = serverResolution; } return resolution; }, //取到服务器支持的最合适的zoom值 getServerZoom: function() { var resolution = this.getServerResolution(); return this.serverResolutions ? OpenLayers.Util.indexOf(this.serverResolutions, resolution) ://如果有列表 去数组里查 this.map.getZoomForResolution(resolution) + (this.zoomOffset || 0);//没有列表, 从分辨率算, 再加zoom偏移 },