OpenLayers源码学习18:图层Layer.Grid_2 Posted on 2015-03-18 | In OpenLayers学习 | 然后grid的第二部分 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553 // 调整背景缓存(back buffer), applyBackBuffer: function(resolution) { if(this.backBufferTimerId !== null) { this.removeBackBuffer(); } var backBuffer = this.backBuffer; if(!backBuffer) { backBuffer = this.createBackBuffer(); if(!backBuffer) { return; } if (resolution === this.gridResolution) { //分辨率相等 this.div.insertBefore(backBuffer, this.div.firstChild);//将backbuffer插到div最前边 } else { //分辨率不等的话, 插到baseLayer前边 this.map.baseLayer.div.parentNode.insertBefore(backBuffer, this.map.baseLayer.div); } this.backBuffer = backBuffer; // 缓存第一张瓦片的left/top var topLeftTileBounds = this.grid[0][0].bounds; this.backBufferLonLat = { lon: topLeftTileBounds.left, lat: topLeftTileBounds.top }; this.backBufferResolution = this.gridResolution; } var ratio = this.backBufferResolution / resolution; // 调整backBuffer里所有瓦片的偏移 var tiles = backBuffer.childNodes, tile; for (var i=tiles.length-1; i>=0; --i) { tile = tiles[i]; tile.style.top = ((ratio * tile._i * tile._h) | 0) + 'px'; tile.style.left = ((ratio * tile._j * tile._w) | 0) + 'px'; tile.style.width = Math.round(ratio * tile._w) + 'px'; tile.style.height = Math.round(ratio * tile._h) + 'px'; } // 调整backBuffer的位置 var position = this.getViewPortPxFromLonLat( this.backBufferLonLat, resolution); var leftOffset = this.map.layerContainerOriginPx.x; var topOffset = this.map.layerContainerOriginPx.y; backBuffer.style.left = Math.round(position.x - leftOffset) + 'px'; backBuffer.style.top = Math.round(position.y - topOffset) + 'px'; }, // 创建背景画布 createBackBuffer: function() { var backBuffer; if(this.grid.length > 0) { backBuffer = document.createElement('div'); backBuffer.id = this.div.id + '_bb';//backBuffer backBuffer.className = 'olBackBuffer'; backBuffer.style.position = 'absolute'; var map = this.map; backBuffer.style.zIndex = this.transitionEffect === 'resize' ? this.getZIndex() - 1 : // 'map-resize': map.Z_INDEX_BASE.BaseLayer - (map.getNumLayers() - map.getLayerIndex(this));//各种情况的z-index for(var i=0, lenI=this.grid.length; i<lenI; i++) { for(var j=0, lenJ=this.grid[i].length; j<lenJ; j++) { var tile = this.grid[i][j], markup = this.grid[i][j].createBackBuffer();//瓦片的createBackBuffer if (markup) { markup._i = i;//单张瓦片的各个属性 markup._j = j; markup._w = tile.size.w; markup._h = tile.size.h; markup.id = tile.id + '_bb'; backBuffer.appendChild(markup); } } } } return backBuffer; }, // 从dom里删除bb removeBackBuffer: function() { if (this._transitionElement) {//不知道这个是什么变换 for (var i=this.transitionendEvents.length-1; i>=0; --i) { OpenLayers.Event.stopObserving(this._transitionElement, this.transitionendEvents[i], this._removeBackBuffer); } delete this._transitionElement; } if(this.backBuffer) { if (this.backBuffer.parentNode) { this.backBuffer.parentNode.removeChild(this.backBuffer);//删除dom } this.backBuffer = null; this.backBufferResolution = null; if(this.backBufferTimerId !== null) { window.clearTimeout(this.backBufferTimerId);//timer也得清掉 this.backBufferTimerId = null; } } }, // 移动图层 moveByPx: function(dx, dy) { if (!this.singleTile) { this.moveGriddedTiles(); } }, setTileSize: function(size) { if (this.singleTile) { size = this.map.getSize(); size.h = parseInt(size.h * this.ratio, 10); size.w = parseInt(size.w * this.ratio, 10); } OpenLayers.Layer.HTTPRequest.prototype.setTileSize.apply(this, [size]); }, // 获得瓦片边界 getTilesBounds: function() { var bounds = null; var length = this.grid.length; if (length) { var bottomLeftTileBounds = this.grid[length - 1][0].bounds,//角落的bounds width = this.grid[0].length * bottomLeftTileBounds.getWidth(),//行的瓦片数 height = this.grid.length * bottomLeftTileBounds.getHeight();//列内瓦片数 bounds = new OpenLayers.Bounds(bottomLeftTileBounds.left, bottomLeftTileBounds.bottom, bottomLeftTileBounds.left + width, bottomLeftTileBounds.bottom + height);//最大值 } return bounds; }, //初始化单瓦片模式 initSingleTile: function(bounds) { //触发事件 this.events.triggerEvent("retile"); //创建新的bound var center = bounds.getCenterLonLat(); var tileWidth = bounds.getWidth() * this.ratio; var tileHeight = bounds.getHeight() * this.ratio; var tileBounds = new OpenLayers.Bounds(center.lon - (tileWidth/2), center.lat - (tileHeight/2), center.lon + (tileWidth/2), center.lat + (tileHeight/2));//从中心点计算瓦片边界 //转换到像素坐标 var px = this.map.getLayerPxFromLonLat({ lon: tileBounds.left, lat: tileBounds.top }); if (!this.grid.length) { this.grid[0] = []; } var tile = this.grid[0][0];//第一张 if (!tile) { tile = this.addTile(tileBounds, px);//添加瓦片 this.addTileMonitoringHooks(tile); tile.draw();//绘制瓦片 this.grid[0][0] = tile; } else { tile.moveTo(tileBounds, px);//之前有就移动瓦片 } //remove all but our single tile this.removeExcessTiles(1,1); // 缓存分辨率 this.gridResolution = this.getServerResolution(); }, // 计算grid的布局 calculateGridLayout: function(bounds, origin, resolution) { //单张瓦片对应的经纬跨度 var tilelon = resolution * this.tileSize.w; var tilelat = resolution * this.tileSize.h; //经度 全局偏移 var offsetlon = bounds.left - origin.lon; //行号 var tilecol = Math.floor(offsetlon/tilelon) - this.buffer; // var rowSign = this.rowSign; //纬度 全局偏移 var offsetlat = rowSign * (origin.lat - bounds.top + tilelat); //列号 var tilerow = Math[~rowSign ? 'floor' : 'ceil'](offsetlat/tilelat) - this.buffer * rowSign; return { tilelon: tilelon, tilelat: tilelat, startcol: tilecol, startrow: tilerow }; }, // 获得瓦片的原始位置 getTileOrigin: function() { var origin = this.tileOrigin; if (!origin) { var extent = this.getMaxExtent(); var edges = ({ "tl": ["left", "top"], "tr": ["right", "top"], "bl": ["left", "bottom"], "br": ["right", "bottom"] })[this.tileOriginCorner]; origin = new OpenLayers.LonLat(extent[edges[0]], extent[edges[1]]); } return origin; }, // 根据行列号去计算瓦片的bounds getTileBoundsForGridIndex: function(row, col) { var origin = this.getTileOrigin(); var tileLayout = this.gridLayout; var tilelon = tileLayout.tilelon; var tilelat = tileLayout.tilelat; var startcol = tileLayout.startcol; var startrow = tileLayout.startrow; var rowSign = this.rowSign; return new OpenLayers.Bounds( origin.lon + (startcol + col) * tilelon,//原始经度 + 行号x瓦片经度 origin.lat - (startrow + row * rowSign) * tilelat * rowSign, origin.lon + (startcol + col + 1) * tilelon, origin.lat - (startrow + (row - 1) * rowSign) * tilelat * rowSign ); }, // 初始化排列好的瓦片 initGriddedTiles:function(bounds) { this.events.triggerEvent("retile"); //size var viewSize = this.map.getSize(); //瓦片原点 var origin = this.getTileOrigin(); var resolution = this.map.getResolution(), serverResolution = this.getServerResolution(), ratio = resolution / serverResolution, tileSize = { w: this.tileSize.w / ratio, h: this.tileSize.h / ratio }; //最小行列号 var minRows = Math.ceil(viewSize.h/tileSize.h) + 2 * this.buffer + 1; var minCols = Math.ceil(viewSize.w/tileSize.w) + 2 * this.buffer + 1; var tileLayout = this.calculateGridLayout(bounds, origin, serverResolution); this.gridLayout = tileLayout; var tilelon = tileLayout.tilelon; var tilelat = tileLayout.tilelat; //图层容器的原始坐标 var layerContainerDivLeft = this.map.layerContainerOriginPx.x; var layerContainerDivTop = this.map.layerContainerOriginPx.y; var tileBounds = this.getTileBoundsForGridIndex(0, 0); var startPx = this.map.getViewPortPxFromLonLat( new OpenLayers.LonLat(tileBounds.left, tileBounds.top) ); //计算起始px startPx.x = Math.round(startPx.x) - layerContainerDivLeft; startPx.y = Math.round(startPx.y) - layerContainerDivTop; var tileData = [], center = this.map.getCenter(); var rowidx = 0; do { var row = this.grid[rowidx]; if (!row) {//新的一行 row = []; this.grid.push(row); } var colidx = 0; do { tileBounds = this.getTileBoundsForGridIndex(rowidx, colidx); var px = startPx.clone(); px.x = px.x + colidx * Math.round(tileSize.w);//像素偏移 px.y = px.y + rowidx * Math.round(tileSize.h); var tile = row[colidx]; if (!tile) {//此位置上没瓦片就得新建一个 tile = this.addTile(tileBounds, px); this.addTileMonitoringHooks(tile); row.push(tile); } else { //原先就有的话, 移动到指定位置 tile.moveTo(tileBounds, px, false); } var tileCenter = tileBounds.getCenterLonLat(); tileData.push({ tile: tile, distance: Math.pow(tileCenter.lon - center.lon, 2) + Math.pow(tileCenter.lat - center.lat, 2)//缓存距离 }); colidx += 1; } while ((tileBounds.right <= bounds.right + tilelon * this.buffer)//超过距离 或 超过编号就结束 || colidx < minCols); rowidx += 1; } while((tileBounds.bottom >= bounds.bottom - tilelat * this.buffer) || rowidx < minRows);//超过距离 或 超过编号结束 //去掉已经不用的瓦片 this.removeExcessTiles(rowidx, colidx); var resolution = this.getServerResolution(); // 缓存grid的分辨率 this.gridResolution = resolution; //给缓存tileData排序, 准备绘制 tileData.sort(function(a, b) { return a.distance - b.distance; }); //重绘瓦片 for (var i=0, ii=tileData.length; i<ii; ++i) { tileData[i].tile.draw(); } }, getMaxExtent: function() { return this.maxExtent; }, // 添加瓦片, 调用事件 addTile: function(bounds, position) { var tile = new this.tileClass( this, position, bounds, null, this.tileSize, this.tileOptions ); this.events.triggerEvent("addtile", {tile: tile}); return tile; }, // 添加瓦片的回调钩子 addTileMonitoringHooks: function(tile) { var replacingCls = 'olTileReplacing'; tile.onLoadStart = function() { //首次加载 if (this.loading === false) { this.loading = true; this.events.triggerEvent("loadstart"); } this.events.triggerEvent("tileloadstart", {tile: tile}); this.numLoadingTiles++;//正在加载计数器 if (!this.singleTile && this.backBuffer && this.gridResolution === this.backBufferResolution) { OpenLayers.Element.addClass(tile.getTile(), replacingCls); } }; tile.onLoadEnd = function(evt) { this.numLoadingTiles--;//计数器递减 var aborted = evt.type === 'unload'; this.events.triggerEvent("tileloaded", { tile: tile, aborted: aborted }); if (!this.singleTile && !aborted && this.backBuffer && this.gridResolution === this.backBufferResolution) { var tileDiv = tile.getTile(); if (OpenLayers.Element.getStyle(tileDiv, 'display') === 'none') { var bufferTile = document.getElementById(tile.id + '_bb'); if (bufferTile) { bufferTile.parentNode.removeChild(bufferTile); } } OpenLayers.Element.removeClass(tileDiv, replacingCls); } //全都加载完了 if (this.numLoadingTiles === 0) { if (this.backBuffer) { if (this.backBuffer.childNodes.length === 0) { // bb没用了 删掉 this.removeBackBuffer(); } else { // 对动画的操作 this._transitionElement = aborted ? this.div.lastChild : tile.imgDiv; var transitionendEvents = this.transitionendEvents; for (var i=transitionendEvents.length-1; i>=0; --i) { OpenLayers.Event.observe(this._transitionElement, transitionendEvents[i], this._removeBackBuffer); } // 增加延迟 this.backBufferTimerId = window.setTimeout( this._removeBackBuffer, this.removeBackBufferDelay ); } } this.loading = false; this.events.triggerEvent("loadend"); } }; tile.onLoadError = function() { this.events.triggerEvent("tileerror", {tile: tile}); }; //初始化瓦片事件 tile.events.on({ "loadstart": tile.onLoadStart, "loadend": tile.onLoadEnd, "unload": tile.onLoadEnd, "loaderror": tile.onLoadError, scope: this }); }, // 解绑瓦片事件 removeTileMonitoringHooks: function(tile) { tile.unload(); tile.events.un({ "loadstart": tile.onLoadStart, "loadend": tile.onLoadEnd, "unload": tile.onLoadEnd, "loaderror": tile.onLoadError, scope: this }); }, // 移动组织好的瓦片 moveGriddedTiles: function() { var buffer = this.buffer + 1; while(true) { var tlTile = this.grid[0][0];//top-left的瓦片 var tlViewPort = { x: tlTile.position.x + this.map.layerContainerOriginPx.x,//计算左上角view port的x值 y: tlTile.position.y + this.map.layerContainerOriginPx.y }; var ratio = this.getServerResolution() / this.map.getResolution(); var tileSize = { w: Math.round(this.tileSize.w * ratio),//根据比率放大后的瓦片尺寸 h: Math.round(this.tileSize.h * ratio) }; //判断是横向 还是纵向移动 if (tlViewPort.x > -tileSize.w * (buffer - 1)) { this.shiftColumn(true, tileSize); } else if (tlViewPort.x < -tileSize.w * buffer) { this.shiftColumn(false, tileSize); } else if (tlViewPort.y > -tileSize.h * (buffer - 1)) { this.shiftRow(true, tileSize); } else if (tlViewPort.y < -tileSize.h * buffer) { this.shiftRow(false, tileSize); } else { break; } } }, //移动行 //prepend为真, 就是从0行开始 / 否则就是末行 shiftRow: function(prepend, tileSize) { var grid = this.grid; var rowIndex = prepend ? 0 : (grid.length - 1);//首行 / 末行 var sign = prepend ? -1 : 1;//向左是-1 , 向右是1 var rowSign = this.rowSign; var tileLayout = this.gridLayout; tileLayout.startrow += sign * rowSign;//向左 / 向右移动 var modelRow = grid[rowIndex];//共多少行 var row = grid[prepend ? 'pop' : 'shift'](); for (var i=0, len=row.length; i<len; i++) { var tile = row[i]; var position = modelRow[i].position.clone(); position.y += tileSize.h * sign;//y轴 偏移量 tile.moveTo(this.getTileBoundsForGridIndex(rowIndex, i), position);//y轴移动距离 } grid[prepend ? 'unshift' : 'push'](row);//调用grid[1/-1] }, //移动列 shiftColumn: function(prepend, tileSize) { var grid = this.grid; var colIndex = prepend ? 0 : (grid[0].length - 1);//true是第一列, false是末一列 var sign = prepend ? -1 : 1; var tileLayout = this.gridLayout; tileLayout.startcol += sign; for (var i=0, len=grid.length; i<len; i++) { var row = grid[i]; var position = row[colIndex].position.clone(); var tile = row[prepend ? 'pop' : 'shift'](); position.x += tileSize.w * sign; tile.moveTo(this.getTileBoundsForGridIndex(i, colIndex), position);//列移动 row[prepend ? 'unshift' : 'push'](tile); } }, //删掉多余瓦片 removeExcessTiles: function(rows, columns) { var i, l; //传入的r和l是保留的最大行列号 while (this.grid.length > rows) { var row = this.grid.pop(); for (i=0, l=row.length; i<l; i++) { var tile = row[i]; this.destroyTile(tile); } } for (i=0, l=this.grid.length; i<l; i++) { while (this.grid[i].length > columns) { var row = this.grid[i]; var tile = row.pop(); this.destroyTile(tile); } } }, // 单瓦片模式需要调整 onMapResize: function() { if (this.singleTile) { this.clearGrid(); this.setTileSize(); } }, //获得瓦片边界 getTileBounds: function(viewPortPx) { var maxExtent = this.maxExtent; var resolution = this.getResolution(); var tileMapWidth = resolution * this.tileSize.w; var tileMapHeight = resolution * this.tileSize.h; var mapPoint = this.getLonLatFromViewPortPx(viewPortPx);//viewport的像素位置 var tileLeft = maxExtent.left + (tileMapWidth * Math.floor((mapPoint.lon - maxExtent.left) / tileMapWidth)); var tileBottom = maxExtent.bottom + (tileMapHeight * Math.floor((mapPoint.lat - maxExtent.bottom) / tileMapHeight)); return new OpenLayers.Bounds(tileLeft, tileBottom, tileLeft + tileMapWidth, tileBottom + tileMapHeight); }, CLASS_NAME: "OpenLayers.Layer.Grid"});