openlayers源码阅读笔记(四)—— 图层渲染器 ol.renderer.canvas.TileLayer
renderFrame()
完整代码+注释
renderFrame ( frameState, target ) {
const layerState = frameState. layerStatesArray[ frameState. layerIndex] ;
const viewState = frameState. viewState;
const projection = viewState. projection;
const viewResolution = viewState. resolution;
const viewCenter = viewState. center;
const rotation = viewState. rotation;
const pixelRatio = frameState. pixelRatio;
const tileLayer = this . getLayer ( ) ;
const tileSource = tileLayer. getSource ( ) ;
const sourceRevision = tileSource. getRevision ( ) ;
const tileGrid = tileSource. getTileGridForProjection ( projection) ;
const z = tileGrid. getZForResolution ( viewResolution, tileSource. zDirection) ;
const tileResolution = tileGrid. getResolution ( z) ;
let extent = frameState. extent;
const layerExtent =
layerState. extent && fromUserExtent ( layerState. extent, projection) ;
if ( layerExtent) {
extent = getIntersection (
extent,
fromUserExtent ( layerState. extent, projection)
) ;
}
const tilePixelRatio = tileSource. getTilePixelRatio ( pixelRatio) ;
let width = Math. round ( frameState. size[ 0 ] * tilePixelRatio) ;
let height = Math. round ( frameState. size[ 1 ] * tilePixelRatio) ;
if ( rotation) {
const size = Math. round ( Math. sqrt ( width * width + height * height) ) ;
width = size;
height = size;
}
const dx = ( tileResolution * width) / 2 / tilePixelRatio;
const dy = ( tileResolution * height) / 2 / tilePixelRatio;
const canvasExtent = [
viewCenter[ 0 ] - dx,
viewCenter[ 1 ] - dy,
viewCenter[ 0 ] + dx,
viewCenter[ 1 ] + dy,
] ;
const tileRange = tileGrid. getTileRangeForExtentAndZ ( extent, z) ;
const tilesToDrawByZ = { } ;
tilesToDrawByZ[ z] = { } ;
const findLoadedTiles = this . createLoadedTileFinder (
tileSource,
projection,
tilesToDrawByZ
) ;
const tmpExtent = this . tmpExtent;
const tmpTileRange = this . tmpTileRange_;
this . newTiles_ = false ;
for ( let x = tileRange. minX; x <= tileRange. maxX; ++ x) {
for ( let y = tileRange. minY; y <= tileRange. maxY; ++ y) {
const tile = this . getTile ( z, x, y, frameState) ;
if ( this . isDrawableTile ( tile) ) {
const uid = getUid ( this ) ;
if ( tile. getState ( ) == TileState. LOADED ) {
tilesToDrawByZ[ z] [ tile. tileCoord. toString ( ) ] = tile;
const inTransition = tile. inTransition ( uid) ;
if (
! this . newTiles_ &&
( inTransition || this . renderedTiles. indexOf ( tile) === - 1 )
) {
this . newTiles_ = true ;
}
}
if ( tile. getAlpha ( uid, frameState. time) === 1 ) {
continue ;
}
}
const childTileRange = tileGrid. getTileCoordChildTileRange (
tile. tileCoord,
tmpTileRange,
tmpExtent
) ;
let covered = false ;
if ( childTileRange) {
covered = findLoadedTiles ( z + 1 , childTileRange) ;
}
if ( ! covered) {
tileGrid. forEachTileCoordParentTileRange (
tile. tileCoord,
findLoadedTiles,
tmpTileRange,
tmpExtent
) ;
}
}
}
const canvasScale = tileResolution / viewResolution;
composeTransform (
this . pixelTransform,
frameState. size[ 0 ] / 2 ,
frameState. size[ 1 ] / 2 ,
1 / tilePixelRatio,
1 / tilePixelRatio,
rotation,
- width / 2 ,
- height / 2
) ;
const canvasTransform = toTransformString ( this . pixelTransform) ;
this . useContainer (
target,
canvasTransform,
layerState. opacity,
this . getBackground ( frameState)
) ;
const context = this . context;
const canvas = context. canvas;
makeInverse ( this . inversePixelTransform, this . pixelTransform) ;
composeTransform (
this . tempTransform,
width / 2 ,
height / 2 ,
canvasScale,
canvasScale,
0 ,
- width / 2 ,
- height / 2
) ;
if ( canvas. width != width || canvas. height != height) {
canvas. width = width;
canvas. height = height;
} else if ( ! this . containerReused) {
context. clearRect ( 0 , 0 , width, height) ;
}
if ( layerExtent) {
this . clipUnrotated ( context, frameState, layerExtent) ;
}
if ( ! tileSource. getInterpolate ( ) ) {
assign ( context, IMAGE_SMOOTHING_DISABLED ) ;
}
this . preRender ( context, frameState) ;
this . renderedTiles. length = 0 ;
let zs = Object. keys ( tilesToDrawByZ) . map ( Number) ;
zs. sort ( numberSafeCompareFunction) ;
let clips, clipZs, currentClip;
if (
layerState. opacity === 1 &&
( ! this . containerReused ||
tileSource. getOpaque ( frameState. viewState. projection) )
) {
zs = zs. reverse ( ) ;
} else {
clips = [ ] ;
clipZs = [ ] ;
}
for ( let i = zs. length - 1 ; i >= 0 ; -- i) {
const currentZ = zs[ i] ;
const currentTilePixelSize = tileSource. getTilePixelSize (
currentZ,
pixelRatio,
projection
) ;
const currentResolution = tileGrid. getResolution ( currentZ) ;
const currentScale = currentResolution / tileResolution;
const dx = currentTilePixelSize[ 0 ] * currentScale * canvasScale;
const dy = currentTilePixelSize[ 1 ] * currentScale * canvasScale;
const originTileCoord = tileGrid. getTileCoordForCoordAndZ (
getTopLeft ( canvasExtent) ,
currentZ
) ;
const originTileExtent = tileGrid. getTileCoordExtent ( originTileCoord) ;
const origin = applyTransform ( this . tempTransform, [
( tilePixelRatio * ( originTileExtent[ 0 ] - canvasExtent[ 0 ] ) ) /
tileResolution,
( tilePixelRatio * ( canvasExtent[ 3 ] - originTileExtent[ 3 ] ) ) /
tileResolution,
] ) ;
const tileGutter =
tilePixelRatio * tileSource. getGutterForProjection ( projection) ;
const tilesToDraw = tilesToDrawByZ[ currentZ] ;
for ( const tileCoordKey in tilesToDraw) {
const tile = (
tilesToDraw[ tileCoordKey]
) ;
const tileCoord = tile. tileCoord;
const xIndex = originTileCoord[ 1 ] - tileCoord[ 1 ] ;
const nextX = Math. round ( origin[ 0 ] - ( xIndex - 1 ) * dx) ;
const yIndex = originTileCoord[ 2 ] - tileCoord[ 2 ] ;
const nextY = Math. round ( origin[ 1 ] - ( yIndex - 1 ) * dy) ;
const x = Math. round ( origin[ 0 ] - xIndex * dx) ;
const y = Math. round ( origin[ 1 ] - yIndex * dy) ;
const w = nextX - x;
const h = nextY - y;
const transition = z === currentZ;
const inTransition =
transition && tile. getAlpha ( getUid ( this ) , frameState. time) !== 1 ;
if ( ! inTransition) {
if ( clips) {
context. save ( ) ;
currentClip = [ x, y, x + w, y, x + w, y + h, x, y + h] ;
for ( let i = 0 , ii = clips. length; i < ii; ++ i) {
if ( z !== currentZ && currentZ < clipZs[ i] ) {
const clip = clips[ i] ;
context. beginPath ( ) ;
context. moveTo ( currentClip[ 0 ] , currentClip[ 1 ] ) ;
context. lineTo ( currentClip[ 2 ] , currentClip[ 3 ] ) ;
context. lineTo ( currentClip[ 4 ] , currentClip[ 5 ] ) ;
context. lineTo ( currentClip[ 6 ] , currentClip[ 7 ] ) ;
context. moveTo ( clip[ 6 ] , clip[ 7 ] ) ;
context. lineTo ( clip[ 4 ] , clip[ 5 ] ) ;
context. lineTo ( clip[ 2 ] , clip[ 3 ] ) ;
context. lineTo ( clip[ 0 ] , clip[ 1 ] ) ;
context. clip ( ) ;
}
}
clips. push ( currentClip) ;
clipZs. push ( currentZ) ;
} else {
context. clearRect ( x, y, w, h) ;
}
}
this . drawTileImage (
tile,
frameState,
x,
y,
w,
h,
tileGutter,
transition
) ;
if ( clips && ! inTransition) {
context. restore ( ) ;
this . renderedTiles. unshift ( tile) ;
} else {
this . renderedTiles. push ( tile) ;
}
this . updateUsedTiles ( frameState. usedTiles, tileSource, tile) ;
}
}
this . renderedRevision = sourceRevision;
this . renderedResolution = tileResolution;
this . extentChanged =
! this . renderedExtent_ || ! equals ( this . renderedExtent_, canvasExtent) ;
this . renderedExtent_ = canvasExtent;
this . renderedPixelRatio = pixelRatio;
this . renderedProjection = projection;
this . manageTilePyramid (
frameState,
tileSource,
tileGrid,
pixelRatio,
projection,
extent,
z,
tileLayer. getPreload ( )
) ;
this . scheduleExpireCache ( frameState, tileSource) ;
this . postRender ( context, frameState) ;
if ( layerState. extent) {
context. restore ( ) ;
}
if ( canvasTransform !== canvas. style. transform) {
canvas. style. transform = canvasTransform;
}
const opacity = cssOpacity ( layerState. opacity) ;
const container = this . container;
if ( opacity !== container. style. opacity) {
container. style. opacity = opacity;
}
return this . container;
}
` ` `