Merge pull request #4557 from ahocevar/vectortile-canvas

Conditionally render tiles to a separate tile canvas
This commit is contained in:
Andreas Hocevar
2015-12-18 10:43:52 +01:00
3 changed files with 136 additions and 45 deletions

View File

@@ -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;
@@ -1995,32 +2016,35 @@ ol.render.canvas.ReplayGroup.prototype.isEmpty = function() {
* @param {number} viewRotation View rotation.
* @param {Object.<string, boolean>} 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.<number>} */
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) {

View File

@@ -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');
@@ -87,10 +88,14 @@ 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,
'Source is an ol.source.VectorTile');
var tilePixelRatio = source.getTilePixelRatio();
var maxScale = tilePixelRatio / pixelRatio;
var transform = this.getTransform(frameState, 0);
@@ -114,35 +119,81 @@ ol.renderer.canvas.VectorTileLayer.prototype.composeFrame =
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, offsetX, offsetY;
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();
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;
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);
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 || scale > maxScale) {
if (pixelSpace) {
origin = ol.extent.getTopLeft(tileExtent);
tileTransform = ol.vec.Mat4.makeTransform2D(this.tmpTransform_,
offsetX, offsetY,
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 {
tilePixelSize = source.getTilePixelSize(currentZ, pixelRatio, projection);
if (pixelSpace) {
tileTransform = ol.vec.Mat4.makeTransform2D(this.tmpTransform_,
0, 0,
pixelScale * tilePixelResolution, pixelScale * tilePixelResolution,
rotation,
-tilePixelSize[0] / 2, -tilePixelSize[1] / 2);
} else {
tileCenter = ol.extent.getCenter(tileExtent);
tileTransform = ol.vec.Mat4.makeTransform2D(this.tmpTransform_,
0, 0,
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;
tileContext.translate(width / 2, height / 2);
tileContext.rotate(-rotation);
replayState.replayGroup.replay(tileContext, pixelRatio,
tileTransform, rotation, skippedFeatureUids, false);
}
insertTransform = ol.vec.Mat4.makeTransform2D(this.tmpTransform_,
0, 0, pixelScale, -pixelScale, 0, -center[0], -center[1]);
insertPoint = ol.geom.flat.transform.transform2D(
ol.extent.getTopLeft(tileExtent), 0, 1, 2, insertTransform);
replayContext.translate(offsetX, offsetY);
replayContext.rotate(rotation);
replayContext.drawImage(tileContext.canvas,
Math.round(insertPoint[0]), Math.round(insertPoint[1]));
replayContext.rotate(-rotation);
replayContext.translate(-offsetX, -offsetY);
}
tile.getReplayState().replayGroup.replay(replayContext, pixelRatio,
transform, rotation, skippedFeatureUids);
}
transform = this.getTransform(frameState, 0);
if (replayContext != context) {
this.dispatchRenderEvent(replayContext, frameState, transform);
context.drawImage(replayContext.canvas, 0, 0);
@@ -234,6 +285,7 @@ ol.renderer.canvas.VectorTileLayer.prototype.createReplayGroup = function(tile,
replayState.renderedRevision = revision;
replayState.renderedRenderOrder = renderOrder;
replayState.replayGroup = replayGroup;
replayState.resolution = NaN;
};

View File

@@ -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
*/