From c1b16217f28f50d4585a2ffda603b83042cbd2cc Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Mon, 14 Dec 2015 09:41:58 +0100 Subject: [PATCH 1/6] Conditionally render tiles to a separate tile canvas Because clip geometries are anti-aliased in most browsers, there will be tiny gaps between tiles. If tiles are rendered to a tile canvas which is then drawn to the map canvas upon composition, these gaps can be avoided. For rotated views, it is stil necessary to clip the tile, but in this case a 1-pixel buffer is used. This change also brings a huge performance improvement for panning, because the fully rendered tiles can be reused. Because of the added cost of using drawImage in addition to replaying the tile replay group, we fall back to directly drawing to the map canvas when the tile canvas would be too large, or during interaction/animation when resolution or rotation change. --- src/ol/render/canvas/canvasreplay.js | 43 +++--- .../canvas/canvasvectortilelayerrenderer.js | 122 ++++++++++++++---- src/ol/vectortile.js | 15 +++ 3 files changed, 136 insertions(+), 44 deletions(-) diff --git a/src/ol/render/canvas/canvasreplay.js b/src/ol/render/canvas/canvasreplay.js index 6c6668ca75..c53ca842f8 100644 --- a/src/ol/render/canvas/canvasreplay.js +++ b/src/ol/render/canvas/canvasreplay.js @@ -1995,32 +1995,35 @@ ol.render.canvas.ReplayGroup.prototype.isEmpty = function() { * @param {number} viewRotation View rotation. * @param {Object.} skippedFeaturesHash Ids of features * to skip. + * @param {boolean=} opt_clip Clip at `maxExtent`. Default is true. */ -ol.render.canvas.ReplayGroup.prototype.replay = function( - context, pixelRatio, transform, viewRotation, skippedFeaturesHash) { +ol.render.canvas.ReplayGroup.prototype.replay = function(context, pixelRatio, + transform, viewRotation, skippedFeaturesHash, opt_clip) { /** @type {Array.} */ var zs = Object.keys(this.replaysByZIndex_).map(Number); zs.sort(ol.array.numberSafeCompareFunction); - // setup clipping so that the parts of over-simplified geometries are not - // visible outside the current extent when panning - var maxExtent = this.maxExtent_; - var minX = maxExtent[0]; - var minY = maxExtent[1]; - var maxX = maxExtent[2]; - var maxY = maxExtent[3]; - var flatClipCoords = [minX, minY, minX, maxY, maxX, maxY, maxX, minY]; - ol.geom.flat.transform.transform2D( - flatClipCoords, 0, 8, 2, transform, flatClipCoords); - context.save(); - context.beginPath(); - context.moveTo(flatClipCoords[0], flatClipCoords[1]); - context.lineTo(flatClipCoords[2], flatClipCoords[3]); - context.lineTo(flatClipCoords[4], flatClipCoords[5]); - context.lineTo(flatClipCoords[6], flatClipCoords[7]); - context.closePath(); - context.clip(); + if (opt_clip !== false) { + // setup clipping so that the parts of over-simplified geometries are not + // visible outside the current extent when panning + var maxExtent = this.maxExtent_; + var minX = maxExtent[0]; + var minY = maxExtent[1]; + var maxX = maxExtent[2]; + var maxY = maxExtent[3]; + var flatClipCoords = [minX, minY, minX, maxY, maxX, maxY, maxX, minY]; + ol.geom.flat.transform.transform2D( + flatClipCoords, 0, 8, 2, transform, flatClipCoords); + context.save(); + context.beginPath(); + context.moveTo(flatClipCoords[0], flatClipCoords[1]); + context.lineTo(flatClipCoords[2], flatClipCoords[3]); + context.lineTo(flatClipCoords[4], flatClipCoords[5]); + context.lineTo(flatClipCoords[6], flatClipCoords[7]); + context.closePath(); + context.clip(); + } var i, ii, j, jj, replays, replay; for (i = 0, ii = zs.length; i < ii; ++i) { diff --git a/src/ol/renderer/canvas/canvasvectortilelayerrenderer.js b/src/ol/renderer/canvas/canvasvectortilelayerrenderer.js index b299254f80..fe7109d3cc 100644 --- a/src/ol/renderer/canvas/canvasvectortilelayerrenderer.js +++ b/src/ol/renderer/canvas/canvasvectortilelayerrenderer.js @@ -11,6 +11,7 @@ goog.require('ol.ViewHint'); goog.require('ol.array'); goog.require('ol.dom'); goog.require('ol.extent'); +goog.require('ol.geom.flat.transform'); goog.require('ol.layer.VectorTile'); goog.require('ol.proj.Units'); goog.require('ol.render.EventType'); @@ -51,6 +52,18 @@ ol.renderer.canvas.VectorTileLayer = function(layer) { */ this.renderedTiles_ = []; + /** + * @private + * @type {number} + */ + this.resolution_ = NaN; + + /** + * @private + * @type {number} + */ + this.rotation_ = NaN; + /** * @private * @type {ol.Extent} @@ -110,44 +123,101 @@ ol.renderer.canvas.VectorTileLayer.prototype.composeFrame = // see http://jsperf.com/context-save-restore-versus-variable var alpha = replayContext.globalAlpha; replayContext.globalAlpha = layerState.opacity; + var imageSmoothingEnabled = replayContext.imageSmoothingEnabled; + replayContext.imageSmoothingEnabled = false; + var tilesToDraw = this.renderedTiles_; var tileGrid = source.getTileGrid(); - var currentZ, i, ii, origin, tile, tileSize; - var tilePixelRatio, tilePixelResolution, tilePixelSize, tileResolution; + var currentZ, height, i, ii, insertPoint, insertTransform, origin, pixelScale; + var pixelSpace, replayState, rotatedTileExtent, rotatedTileSize, size, tile; + var tileCenter, tileContext, tileExtent, tilePixelResolution, tilePixelSize; + var tileResolution, tileSize, tileTransform, width; for (i = 0, ii = tilesToDraw.length; i < ii; ++i) { tile = tilesToDraw[i]; + replayState = tile.getReplayState(); + tileExtent = tileGrid.getTileCoordExtent( + tile.getTileCoord(), this.tmpExtent_); currentZ = tile.getTileCoord()[0]; - tileSize = tileGrid.getTileSize(currentZ); - tilePixelSize = source.getTilePixelSize(currentZ, pixelRatio, projection); - tilePixelRatio = tilePixelSize[0] / - ol.size.toSize(tileSize, this.tmpSize_)[0]; + tileSize = ol.size.toSize(tileGrid.getTileSize(currentZ), this.tmpSize_); + pixelSpace = tile.getProjection().getUnits() == ol.proj.Units.TILE_PIXELS; + size = frameState.size; tileResolution = tileGrid.getResolution(currentZ); - tilePixelResolution = tileResolution / tilePixelRatio; - if (tile.getProjection().getUnits() == ol.proj.Units.TILE_PIXELS) { - origin = ol.extent.getTopLeft(tileGrid.getTileCoordExtent( - tile.getTileCoord(), this.tmpExtent_)); - transform = ol.vec.Mat4.makeTransform2D(this.tmpTransform_, - pixelRatio * frameState.size[0] / 2, - pixelRatio * frameState.size[1] / 2, - pixelRatio * tilePixelResolution / resolution, - pixelRatio * tilePixelResolution / resolution, - viewState.rotation, - (origin[0] - center[0]) / tilePixelResolution, - (center[1] - origin[1]) / tilePixelResolution); + tilePixelResolution = tileResolution / source.getTilePixelRatio(); + pixelScale = pixelRatio / resolution; + scale = tileResolution / resolution; + offsetX = Math.round(pixelRatio * size[0] / 2); + offsetY = Math.round(pixelRatio * size[1] / 2); + width = tileSize[0] * pixelRatio * scale; + height = tileSize[1] * pixelRatio * scale; + if (width < 1 || width > size[0]) { + if (pixelSpace) { + origin = ol.extent.getTopLeft(tileExtent); + tileTransform = ol.vec.Mat4.makeTransform2D(this.tmpTransform_, + pixelRatio * size[0] / 2, pixelRatio * size[1] / 2, + pixelScale * tilePixelResolution, + pixelScale * tilePixelResolution, + rotation, + (origin[0] - center[0]) / tilePixelResolution, + (center[1] - origin[1]) / tilePixelResolution); + } else { + tileTransform = transform; + } + replayState.replayGroup.replay(replayContext, pixelRatio, + tileTransform, rotation, skippedFeatureUids); + } else { + rotatedTileExtent = ol.extent.getForViewAndSize( + ol.extent.getCenter(tileExtent), tileResolution, rotation, tileSize); + rotatedTileSize = [ol.extent.getWidth(rotatedTileExtent), + ol.extent.getHeight(rotatedTileExtent)]; + tilePixelSize = source.getTilePixelSize(currentZ, pixelRatio, projection); + if (pixelSpace) { + tileTransform = ol.vec.Mat4.makeTransform2D(this.tmpTransform_, + width / 2, height / 2, + pixelScale * tilePixelResolution, pixelScale * tilePixelResolution, + rotation, + -tilePixelSize[0] / 2, -tilePixelSize[1] / 2); + } else { + tileCenter = ol.extent.getCenter(rotatedTileExtent); + tileTransform = ol.vec.Mat4.makeTransform2D(this.tmpTransform_, + width / 2, height / 2, + pixelScale, -pixelScale, + -rotation, + -tileCenter[0], -tileCenter[1]); + } + tileContext = tile.getContext(); + if (replayState.resolution !== resolution || + replayState.rotation !== rotation) { + replayState.resolution = resolution; + replayState.rotation = rotation; + tileContext.canvas.width = width + 0.5; + tileContext.canvas.height = height + 0.5; + replayState.replayGroup.replay(tileContext, pixelRatio, + tileTransform, rotation, skippedFeatureUids, rotation !== 0); + } + insertTransform = ol.vec.Mat4.makeTransform2D(this.tmpTransform_, + (pixelRatio * size[0] - width) / 2, + (pixelRatio * size[1] - height) / 2, + pixelScale, -pixelScale, + -rotation, + -center[0], -center[1]); + insertPoint = ol.geom.flat.transform.transform2D( + ol.extent.getCenter(rotatedTileExtent), 0, 1, 2, insertTransform); + replayContext.drawImage(tileContext.canvas, + insertPoint[0], insertPoint[1]); } - tile.getReplayState().replayGroup.replay(replayContext, pixelRatio, - transform, rotation, skippedFeatureUids); } - transform = this.getTransform(frameState, 0); + this.resolution_ = resolution; + this.rotation_ = rotation; if (replayContext != context) { this.dispatchRenderEvent(replayContext, frameState, transform); context.drawImage(replayContext.canvas, 0, 0); } replayContext.globalAlpha = alpha; + replayContext.imageSmoothingEnabled = imageSmoothingEnabled; this.dispatchPostComposeEvent(context, frameState, transform); }; @@ -179,16 +249,19 @@ ol.renderer.canvas.VectorTileLayer.prototype.createReplayGroup = function(tile, 'Source is an ol.source.VectorTile'); var tileGrid = source.getTileGrid(); var tileCoord = tile.getTileCoord(); + var buffer = 1; + var resolution = tileGrid.getResolution(tileCoord[0]); var pixelSpace = tile.getProjection().getUnits() == ol.proj.Units.TILE_PIXELS; var extent; if (pixelSpace) { var tilePixelSize = source.getTilePixelSize(tileCoord[0], pixelRatio, tile.getProjection()); - extent = [0, 0, tilePixelSize[0], tilePixelSize[1]]; + extent = [-buffer, -buffer, + tilePixelSize[0] + buffer, tilePixelSize[1] + buffer]; } else { - extent = tileGrid.getTileCoordExtent(tileCoord); + extent = ol.extent.buffer(tileGrid.getTileCoordExtent(tileCoord), + buffer * resolution); } - var resolution = tileGrid.getResolution(tileCoord[0]); var tileResolution = pixelSpace ? source.getTilePixelRatio() : resolution; replayState.dirty = false; var replayGroup = new ol.render.canvas.ReplayGroup(0, extent, @@ -234,6 +307,7 @@ ol.renderer.canvas.VectorTileLayer.prototype.createReplayGroup = function(tile, replayState.renderedRevision = revision; replayState.renderedRenderOrder = renderOrder; replayState.replayGroup = replayGroup; + replayState.resolution = NaN; }; diff --git a/src/ol/vectortile.js b/src/ol/vectortile.js index 5a5e1efe2c..55e22eb4cb 100644 --- a/src/ol/vectortile.js +++ b/src/ol/vectortile.js @@ -4,6 +4,7 @@ goog.require('ol.Tile'); goog.require('ol.TileCoord'); goog.require('ol.TileLoadFunctionType'); goog.require('ol.TileState'); +goog.require('ol.dom'); goog.require('ol.proj.Projection'); @@ -33,6 +34,12 @@ ol.VectorTile = goog.base(this, tileCoord, state); + /** + * @private + * @type {CanvasRenderingContext2D} + */ + this.context_ = ol.dom.createCanvasContext2D(); + /** * @private * @type {ol.format.Feature} @@ -84,6 +91,14 @@ ol.VectorTile = goog.inherits(ol.VectorTile, ol.Tile); +/** + * @return {CanvasRenderingContext2D} + */ +ol.VectorTile.prototype.getContext = function() { + return this.context_; +}; + + /** * @inheritDoc */ From 4f2df30f1dea8cfd8c26ae0c8bfbbef3deb532b6 Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Tue, 15 Dec 2015 23:24:09 +0100 Subject: [PATCH 2/6] Avoid clipping by rendering tiles with rotated labels This only works when the device pixel ratio is 1. Labels are incorrectly positioned and not at all rotated for other pixel ratios. I cannot find the cause for this problem. --- .../canvas/canvasvectortilelayerrenderer.js | 53 ++++++------------- 1 file changed, 16 insertions(+), 37 deletions(-) diff --git a/src/ol/renderer/canvas/canvasvectortilelayerrenderer.js b/src/ol/renderer/canvas/canvasvectortilelayerrenderer.js index fe7109d3cc..17931f812f 100644 --- a/src/ol/renderer/canvas/canvasvectortilelayerrenderer.js +++ b/src/ol/renderer/canvas/canvasvectortilelayerrenderer.js @@ -52,18 +52,6 @@ ol.renderer.canvas.VectorTileLayer = function(layer) { */ this.renderedTiles_ = []; - /** - * @private - * @type {number} - */ - this.resolution_ = NaN; - - /** - * @private - * @type {number} - */ - this.rotation_ = NaN; - /** * @private * @type {ol.Extent} @@ -123,15 +111,12 @@ ol.renderer.canvas.VectorTileLayer.prototype.composeFrame = // see http://jsperf.com/context-save-restore-versus-variable var alpha = replayContext.globalAlpha; replayContext.globalAlpha = layerState.opacity; - var imageSmoothingEnabled = replayContext.imageSmoothingEnabled; - replayContext.imageSmoothingEnabled = false; - var tilesToDraw = this.renderedTiles_; var tileGrid = source.getTileGrid(); - var currentZ, height, i, ii, insertPoint, insertTransform, origin, pixelScale; - var pixelSpace, replayState, rotatedTileExtent, rotatedTileSize, size, tile; + var currentZ, height, i, ii, insertPoint, insertTransform, offsetX, offsetY; + var origin, pixelScale, pixelSpace, replayState, scale, size, tile; var tileCenter, tileContext, tileExtent, tilePixelResolution, tilePixelSize; var tileResolution, tileSize, tileTransform, width; for (i = 0, ii = tilesToDraw.length; i < ii; ++i) { @@ -155,7 +140,7 @@ ol.renderer.canvas.VectorTileLayer.prototype.composeFrame = if (pixelSpace) { origin = ol.extent.getTopLeft(tileExtent); tileTransform = ol.vec.Mat4.makeTransform2D(this.tmpTransform_, - pixelRatio * size[0] / 2, pixelRatio * size[1] / 2, + offsetX, offsetY, pixelScale * tilePixelResolution, pixelScale * tilePixelResolution, rotation, @@ -167,21 +152,17 @@ ol.renderer.canvas.VectorTileLayer.prototype.composeFrame = replayState.replayGroup.replay(replayContext, pixelRatio, tileTransform, rotation, skippedFeatureUids); } else { - rotatedTileExtent = ol.extent.getForViewAndSize( - ol.extent.getCenter(tileExtent), tileResolution, rotation, tileSize); - rotatedTileSize = [ol.extent.getWidth(rotatedTileExtent), - ol.extent.getHeight(rotatedTileExtent)]; tilePixelSize = source.getTilePixelSize(currentZ, pixelRatio, projection); if (pixelSpace) { tileTransform = ol.vec.Mat4.makeTransform2D(this.tmpTransform_, - width / 2, height / 2, + 0, 0, pixelScale * tilePixelResolution, pixelScale * tilePixelResolution, rotation, -tilePixelSize[0] / 2, -tilePixelSize[1] / 2); } else { - tileCenter = ol.extent.getCenter(rotatedTileExtent); + tileCenter = ol.extent.getCenter(tileExtent); tileTransform = ol.vec.Mat4.makeTransform2D(this.tmpTransform_, - width / 2, height / 2, + 0, 0, pixelScale, -pixelScale, -rotation, -tileCenter[0], -tileCenter[1]); @@ -193,31 +174,29 @@ ol.renderer.canvas.VectorTileLayer.prototype.composeFrame = replayState.rotation = rotation; tileContext.canvas.width = width + 0.5; tileContext.canvas.height = height + 0.5; + tileContext.translate(width / 2, height / 2); + tileContext.rotate(-rotation); replayState.replayGroup.replay(tileContext, pixelRatio, - tileTransform, rotation, skippedFeatureUids, rotation !== 0); + tileTransform, rotation, skippedFeatureUids, false); } insertTransform = ol.vec.Mat4.makeTransform2D(this.tmpTransform_, - (pixelRatio * size[0] - width) / 2, - (pixelRatio * size[1] - height) / 2, - pixelScale, -pixelScale, - -rotation, - -center[0], -center[1]); + 0, 0, pixelScale, -pixelScale, 0, -center[0], -center[1]); insertPoint = ol.geom.flat.transform.transform2D( - ol.extent.getCenter(rotatedTileExtent), 0, 1, 2, insertTransform); + ol.extent.getTopLeft(tileExtent), 0, 1, 2, insertTransform); + replayContext.translate(offsetX, offsetY); + replayContext.rotate(rotation); replayContext.drawImage(tileContext.canvas, - insertPoint[0], insertPoint[1]); + Math.round(insertPoint[0]), Math.round(insertPoint[1])); + replayContext.rotate(-rotation); + replayContext.translate(-offsetX, -offsetY); } } - this.resolution_ = resolution; - this.rotation_ = rotation; - if (replayContext != context) { this.dispatchRenderEvent(replayContext, frameState, transform); context.drawImage(replayContext.canvas, 0, 0); } replayContext.globalAlpha = alpha; - replayContext.imageSmoothingEnabled = imageSmoothingEnabled; this.dispatchPostComposeEvent(context, frameState, transform); }; From 46a266fa5c30f661a3811e47a226a7dec06328fe Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Wed, 16 Dec 2015 23:47:51 +0100 Subject: [PATCH 3/6] Fix replays on transformed contexts --- src/ol/render/canvas/canvasreplay.js | 29 ++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/ol/render/canvas/canvasreplay.js b/src/ol/render/canvas/canvasreplay.js index c53ca842f8..3b676add9b 100644 --- a/src/ol/render/canvas/canvasreplay.js +++ b/src/ol/render/canvas/canvasreplay.js @@ -139,6 +139,12 @@ ol.render.canvas.Replay = function(tolerance, maxExtent, resolution) { * @type {!goog.vec.Mat4.Number} */ this.tmpLocalTransform_ = goog.vec.Mat4.createNumber(); + + /** + * @private + * @type {!goog.vec.Mat4.Number} + */ + this.tmpLocalTransformInv_ = goog.vec.Mat4.createNumber(); }; goog.inherits(ol.render.canvas.Replay, ol.render.VectorContext); @@ -252,6 +258,7 @@ ol.render.canvas.Replay.prototype.replay_ = function( var d = 0; // data index var dd; // end of per-instruction data var localTransform = this.tmpLocalTransform_; + var localTransformInv = this.tmpLocalTransformInv_; var prevX, prevY, roundX, roundY; while (i < ii) { var instruction = instructions[i]; @@ -331,7 +338,7 @@ ol.render.canvas.Replay.prototype.replay_ = function( ol.vec.Mat4.makeTransform2D( localTransform, centerX, centerY, scale, scale, rotation, -centerX, -centerY); - context.setTransform( + context.transform( goog.vec.Mat4.getElement(localTransform, 0, 0), goog.vec.Mat4.getElement(localTransform, 1, 0), goog.vec.Mat4.getElement(localTransform, 0, 1), @@ -351,7 +358,14 @@ ol.render.canvas.Replay.prototype.replay_ = function( context.globalAlpha = alpha; } if (scale != 1 || rotation !== 0) { - context.setTransform(1, 0, 0, 1, 0, 0); + goog.vec.Mat4.invert(localTransform, localTransformInv); + context.transform( + goog.vec.Mat4.getElement(localTransformInv, 0, 0), + goog.vec.Mat4.getElement(localTransformInv, 1, 0), + goog.vec.Mat4.getElement(localTransformInv, 0, 1), + goog.vec.Mat4.getElement(localTransformInv, 1, 1), + goog.vec.Mat4.getElement(localTransformInv, 0, 3), + goog.vec.Mat4.getElement(localTransformInv, 1, 3)); } } ++i; @@ -390,7 +404,7 @@ ol.render.canvas.Replay.prototype.replay_ = function( if (scale != 1 || rotation !== 0) { ol.vec.Mat4.makeTransform2D( localTransform, x, y, scale, scale, rotation, -x, -y); - context.setTransform( + context.transform( goog.vec.Mat4.getElement(localTransform, 0, 0), goog.vec.Mat4.getElement(localTransform, 1, 0), goog.vec.Mat4.getElement(localTransform, 0, 1), @@ -427,7 +441,14 @@ ol.render.canvas.Replay.prototype.replay_ = function( } if (scale != 1 || rotation !== 0) { - context.setTransform(1, 0, 0, 1, 0, 0); + goog.vec.Mat4.invert(localTransform, localTransformInv); + context.transform( + goog.vec.Mat4.getElement(localTransformInv, 0, 0), + goog.vec.Mat4.getElement(localTransformInv, 1, 0), + goog.vec.Mat4.getElement(localTransformInv, 0, 1), + goog.vec.Mat4.getElement(localTransformInv, 1, 1), + goog.vec.Mat4.getElement(localTransformInv, 0, 3), + goog.vec.Mat4.getElement(localTransformInv, 1, 3)); } } ++i; From 80f10ce824e42345648341d7fd3e73b3b75dbfec Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Thu, 17 Dec 2015 00:00:34 +0100 Subject: [PATCH 4/6] Avoid unnecessary calculation in loops --- .../renderer/canvas/canvasvectortilelayerrenderer.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ol/renderer/canvas/canvasvectortilelayerrenderer.js b/src/ol/renderer/canvas/canvasvectortilelayerrenderer.js index 17931f812f..2a59b20d1e 100644 --- a/src/ol/renderer/canvas/canvasvectortilelayerrenderer.js +++ b/src/ol/renderer/canvas/canvasvectortilelayerrenderer.js @@ -88,6 +88,8 @@ ol.renderer.canvas.VectorTileLayer.prototype.composeFrame = var projection = viewState.projection; var resolution = viewState.resolution; var rotation = viewState.rotation; + var size = frameState.size; + var pixelScale = pixelRatio / resolution; var layer = this.getLayer(); var source = layer.getSource(); goog.asserts.assertInstanceof(source, ol.source.VectorTile, @@ -116,9 +118,9 @@ ol.renderer.canvas.VectorTileLayer.prototype.composeFrame = var tileGrid = source.getTileGrid(); var currentZ, height, i, ii, insertPoint, insertTransform, offsetX, offsetY; - var origin, pixelScale, pixelSpace, replayState, scale, size, tile; - var tileCenter, tileContext, tileExtent, tilePixelResolution, tilePixelSize; - var tileResolution, tileSize, tileTransform, width; + var origin, pixelSpace, replayState, scale, tile, tileCenter, tileContext; + var tileExtent, tilePixelResolution, tilePixelSize, tileResolution, tileSize; + var tileTransform, width; for (i = 0, ii = tilesToDraw.length; i < ii; ++i) { tile = tilesToDraw[i]; replayState = tile.getReplayState(); @@ -127,10 +129,8 @@ ol.renderer.canvas.VectorTileLayer.prototype.composeFrame = currentZ = tile.getTileCoord()[0]; tileSize = ol.size.toSize(tileGrid.getTileSize(currentZ), this.tmpSize_); pixelSpace = tile.getProjection().getUnits() == ol.proj.Units.TILE_PIXELS; - size = frameState.size; tileResolution = tileGrid.getResolution(currentZ); tilePixelResolution = tileResolution / source.getTilePixelRatio(); - pixelScale = pixelRatio / resolution; scale = tileResolution / resolution; offsetX = Math.round(pixelRatio * size[0] / 2); offsetY = Math.round(pixelRatio * size[1] / 2); From 9affb998999fa66098104c71b67f0b68717a0c57 Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Thu, 17 Dec 2015 10:00:22 +0100 Subject: [PATCH 5/6] More sensible split between direct and canvas rendering --- src/ol/renderer/canvas/canvasvectortilelayerrenderer.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ol/renderer/canvas/canvasvectortilelayerrenderer.js b/src/ol/renderer/canvas/canvasvectortilelayerrenderer.js index 2a59b20d1e..f036e05617 100644 --- a/src/ol/renderer/canvas/canvasvectortilelayerrenderer.js +++ b/src/ol/renderer/canvas/canvasvectortilelayerrenderer.js @@ -94,6 +94,8 @@ ol.renderer.canvas.VectorTileLayer.prototype.composeFrame = var source = layer.getSource(); goog.asserts.assertInstanceof(source, ol.source.VectorTile, 'Source is an ol.source.VectorTile'); + var tilePixelRatio = source.getTilePixelRatio(); + var maxScale = tilePixelRatio / pixelRatio; var transform = this.getTransform(frameState, 0); @@ -130,13 +132,13 @@ ol.renderer.canvas.VectorTileLayer.prototype.composeFrame = tileSize = ol.size.toSize(tileGrid.getTileSize(currentZ), this.tmpSize_); pixelSpace = tile.getProjection().getUnits() == ol.proj.Units.TILE_PIXELS; tileResolution = tileGrid.getResolution(currentZ); - tilePixelResolution = tileResolution / source.getTilePixelRatio(); + tilePixelResolution = tileResolution / tilePixelRatio; scale = tileResolution / resolution; offsetX = Math.round(pixelRatio * size[0] / 2); offsetY = Math.round(pixelRatio * size[1] / 2); width = tileSize[0] * pixelRatio * scale; height = tileSize[1] * pixelRatio * scale; - if (width < 1 || width > size[0]) { + if (width < 1 || scale > maxScale) { if (pixelSpace) { origin = ol.extent.getTopLeft(tileExtent); tileTransform = ol.vec.Mat4.makeTransform2D(this.tmpTransform_, From 38bb1569aff306bc2488fb51e95d56034cf99fef Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Fri, 18 Dec 2015 00:14:09 +0100 Subject: [PATCH 6/6] Remove no longer needed buffer for direct rendering --- src/ol/renderer/canvas/canvasvectortilelayerrenderer.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/ol/renderer/canvas/canvasvectortilelayerrenderer.js b/src/ol/renderer/canvas/canvasvectortilelayerrenderer.js index f036e05617..3f53c28aa5 100644 --- a/src/ol/renderer/canvas/canvasvectortilelayerrenderer.js +++ b/src/ol/renderer/canvas/canvasvectortilelayerrenderer.js @@ -230,19 +230,16 @@ ol.renderer.canvas.VectorTileLayer.prototype.createReplayGroup = function(tile, 'Source is an ol.source.VectorTile'); var tileGrid = source.getTileGrid(); var tileCoord = tile.getTileCoord(); - var buffer = 1; - var resolution = tileGrid.getResolution(tileCoord[0]); var pixelSpace = tile.getProjection().getUnits() == ol.proj.Units.TILE_PIXELS; var extent; if (pixelSpace) { var tilePixelSize = source.getTilePixelSize(tileCoord[0], pixelRatio, tile.getProjection()); - extent = [-buffer, -buffer, - tilePixelSize[0] + buffer, tilePixelSize[1] + buffer]; + extent = [0, 0, tilePixelSize[0], tilePixelSize[1]]; } else { - extent = ol.extent.buffer(tileGrid.getTileCoordExtent(tileCoord), - buffer * resolution); + extent = tileGrid.getTileCoordExtent(tileCoord); } + var resolution = tileGrid.getResolution(tileCoord[0]); var tileResolution = pixelSpace ? source.getTilePixelRatio() : resolution; replayState.dirty = false; var replayGroup = new ol.render.canvas.ReplayGroup(0, extent,