Rotate map canvas after composition

This commit is contained in:
Andreas Hocevar
2016-02-13 21:55:09 +01:00
parent 98b823c5fc
commit a109062b1f
12 changed files with 171 additions and 79 deletions
+18 -12
View File
@@ -575,18 +575,24 @@ ol.extent.getForViewAndSize = function(center, resolution, rotation, size, opt_e
var dy = resolution * size[1] / 2;
var cosRotation = Math.cos(rotation);
var sinRotation = Math.sin(rotation);
/** @type {Array.<number>} */
var xs = [-dx, -dx, dx, dx];
/** @type {Array.<number>} */
var ys = [-dy, dy, -dy, dy];
var i, x, y;
for (i = 0; i < 4; ++i) {
x = xs[i];
y = ys[i];
xs[i] = center[0] + x * cosRotation - y * sinRotation;
ys[i] = center[1] + x * sinRotation + y * cosRotation;
}
return ol.extent.boundingExtentXYs_(xs, ys, opt_extent);
var xCos = dx * cosRotation;
var xSin = dx * sinRotation;
var yCos = dy * cosRotation;
var ySin = dy * sinRotation;
var x = center[0];
var y = center[1];
var x0 = x - xCos + ySin;
var x1 = x - xCos - ySin;
var x2 = x + xCos - ySin;
var x3 = x + xCos + ySin;
var y0 = y - xSin - yCos;
var y1 = y - xSin + yCos;
var y2 = y + xSin + yCos;
var y3 = y + xSin - yCos;
return ol.extent.createOrUpdate(
Math.min(x0, x1, x2, x3), Math.min(y0, y1, y2, y3),
Math.max(x0, x1, x2, x3), Math.max(y0, y1, y2, y3),
opt_extent);
};
@@ -147,7 +147,6 @@ ol.renderer.canvas.ImageLayer.prototype.prepareFrame = function(frameState, laye
var viewState = frameState.viewState;
var viewCenter = viewState.center;
var viewResolution = viewState.resolution;
var viewRotation = viewState.rotation;
var image;
var imageLayer = this.getLayer();
@@ -195,7 +194,7 @@ ol.renderer.canvas.ImageLayer.prototype.prepareFrame = function(frameState, laye
pixelRatio * frameState.size[0] / 2,
pixelRatio * frameState.size[1] / 2,
scale, scale,
viewRotation,
0,
imagePixelRatio * (imageExtent[0] - viewCenter[0]) / imageResolution,
imagePixelRatio * (viewCenter[1] - imageExtent[3]) / imageResolution);
this.imageTransformInv_ = null;
+22 -18
View File
@@ -51,6 +51,8 @@ ol.renderer.canvas.Layer.prototype.composeFrame = function(frameState, layerStat
goog.asserts.assert(extent !== undefined,
'layerState extent is defined');
var pixelRatio = frameState.pixelRatio;
var width = frameState.size[0] * pixelRatio;
var height = frameState.size[1] * pixelRatio;
var topLeft = ol.extent.getTopLeft(extent);
var topRight = ol.extent.getTopRight(extent);
var bottomRight = ol.extent.getBottomRight(extent);
@@ -66,12 +68,18 @@ ol.renderer.canvas.Layer.prototype.composeFrame = function(frameState, layerStat
bottomLeft, bottomLeft);
context.save();
context.translate(width / 2, height / 2);
context.rotate(-frameState.viewState.rotation);
context.translate(-width / 2, -height / 2);
context.beginPath();
context.moveTo(topLeft[0] * pixelRatio, topLeft[1] * pixelRatio);
context.lineTo(topRight[0] * pixelRatio, topRight[1] * pixelRatio);
context.lineTo(bottomRight[0] * pixelRatio, bottomRight[1] * pixelRatio);
context.lineTo(bottomLeft[0] * pixelRatio, bottomLeft[1] * pixelRatio);
context.clip();
context.translate(width / 2, height / 2);
context.rotate(frameState.viewState.rotation);
context.translate(-width / 2, -height / 2);
}
var imageTransform = this.getImageTransform();
@@ -83,24 +91,12 @@ ol.renderer.canvas.Layer.prototype.composeFrame = function(frameState, layerStat
// for performance reasons, context.setTransform is only used
// when the view is rotated. see http://jsperf.com/canvas-transform
if (frameState.viewState.rotation === 0) {
var dx = goog.vec.Mat4.getElement(imageTransform, 0, 3);
var dy = goog.vec.Mat4.getElement(imageTransform, 1, 3);
var dw = image.width * goog.vec.Mat4.getElement(imageTransform, 0, 0);
var dh = image.height * goog.vec.Mat4.getElement(imageTransform, 1, 1);
context.drawImage(image, 0, 0, +image.width, +image.height,
Math.round(dx), Math.round(dy), Math.round(dw), Math.round(dh));
} else {
context.setTransform(
goog.vec.Mat4.getElement(imageTransform, 0, 0),
goog.vec.Mat4.getElement(imageTransform, 1, 0),
goog.vec.Mat4.getElement(imageTransform, 0, 1),
goog.vec.Mat4.getElement(imageTransform, 1, 1),
goog.vec.Mat4.getElement(imageTransform, 0, 3),
goog.vec.Mat4.getElement(imageTransform, 1, 3));
context.drawImage(image, 0, 0);
context.setTransform(1, 0, 0, 1, 0, 0);
}
var dx = goog.vec.Mat4.getElement(imageTransform, 0, 3);
var dy = goog.vec.Mat4.getElement(imageTransform, 1, 3);
var dw = image.width * goog.vec.Mat4.getElement(imageTransform, 0, 0);
var dh = image.height * goog.vec.Mat4.getElement(imageTransform, 1, 1);
context.drawImage(image, 0, 0, +image.width, +image.height,
Math.round(dx), Math.round(dy), Math.round(dw), Math.round(dh));
context.globalAlpha = alpha;
if (clipped) {
@@ -123,6 +119,11 @@ ol.renderer.canvas.Layer.prototype.composeFrame = function(frameState, layerStat
ol.renderer.canvas.Layer.prototype.dispatchComposeEvent_ = function(type, context, frameState, opt_transform) {
var layer = this.getLayer();
if (layer.hasListener(type)) {
var width = frameState.size[0] * frameState.pixelRatio;
var height = frameState.size[1] * frameState.pixelRatio;
context.translate(width / 2, height / 2);
context.rotate(-frameState.viewState.rotation);
context.translate(-width / 2, -height / 2);
var transform = opt_transform !== undefined ?
opt_transform : this.getTransform(frameState, 0);
var render = new ol.render.canvas.Immediate(
@@ -132,6 +133,9 @@ ol.renderer.canvas.Layer.prototype.dispatchComposeEvent_ = function(type, contex
context, null);
layer.dispatchEvent(composeEvent);
render.flush();
context.translate(width / 2, height / 2);
context.rotate(frameState.viewState.rotation);
context.translate(-width / 2, -height / 2);
}
};
+54 -7
View File
@@ -11,6 +11,7 @@ goog.require('ol.RendererType');
goog.require('ol.array');
goog.require('ol.css');
goog.require('ol.dom');
goog.require('ol.extent');
goog.require('ol.layer.Image');
goog.require('ol.layer.Layer');
goog.require('ol.layer.Tile');
@@ -45,6 +46,12 @@ ol.renderer.canvas.Map = function(container, map) {
*/
this.context_ = ol.dom.createCanvasContext2D();
/**
* @private
* @type {CanvasRenderingContext2D}
*/
this.renderContext_ = ol.dom.createCanvasContext2D();
/**
* @private
* @type {HTMLCanvasElement}
@@ -56,6 +63,24 @@ ol.renderer.canvas.Map = function(container, map) {
this.canvas_.className = ol.css.CLASS_UNSELECTABLE;
goog.dom.insertChildAt(container, this.canvas_, 0);
/**
* @private
* @type {HTMLCanvasElement}
*/
this.renderCanvas_ = this.renderContext_.canvas;
/**
* @private
* @type {ol.Coordinate}
*/
this.pixelCenter_ = [0, 0];
/**
* @private
* @type {ol.Extent}
*/
this.pixelExtent_ = ol.extent.createEmpty();
/**
* @private
* @type {boolean}
@@ -156,14 +181,27 @@ ol.renderer.canvas.Map.prototype.renderFrame = function(frameState) {
return;
}
var context = this.context_;
var width = frameState.size[0] * frameState.pixelRatio;
var height = frameState.size[1] * frameState.pixelRatio;
if (this.canvas_.width != width || this.canvas_.height != height) {
this.canvas_.width = width;
this.canvas_.height = height;
var context;
var pixelRatio = frameState.pixelRatio;
var width = frameState.size[0] * pixelRatio;
var height = frameState.size[1] * pixelRatio;
this.canvas_.width = width;
this.canvas_.height = height;
var rotation = frameState.viewState.rotation;
var pixelExtent;
if (rotation) {
context = this.renderContext_;
pixelExtent = ol.extent.getForViewAndSize(this.pixelCenter_, pixelRatio,
rotation, frameState.size, this.pixelExtent_);
var renderWidth = ol.extent.getWidth(pixelExtent);
var renderHeight = ol.extent.getHeight(pixelExtent);
this.renderCanvas_.width = renderWidth + 0.5;
this.renderCanvas_.height = renderHeight + 0.5;
this.renderContext_.translate(Math.round((renderWidth - width) / 2),
Math.round((renderHeight - height) / 2));
} else {
context.clearRect(0, 0, this.canvas_.width, this.canvas_.height);
context = this.context_;
}
this.calculateMatrices2D(frameState);
@@ -190,6 +228,15 @@ ol.renderer.canvas.Map.prototype.renderFrame = function(frameState) {
}
}
if (rotation) {
this.context_.translate(width / 2, height / 2);
this.context_.rotate(rotation);
this.context_.drawImage(this.renderCanvas_,
Math.round(pixelExtent[0]), Math.round(pixelExtent[1]));
this.context_.rotate(-rotation);
this.context_.translate(-width / 2, -height / 2);
}
this.dispatchComposeEvent_(
ol.render.EventType.POSTCOMPOSE, frameState);
@@ -61,7 +61,6 @@ ol.renderer.canvas.TileLayer.prototype.composeFrame = function(
var center = viewState.center;
var projection = viewState.projection;
var resolution = viewState.resolution;
var rotation = viewState.rotation;
var size = frameState.size;
var pixelScale = pixelRatio / resolution;
var layer = this.getLayer();
@@ -86,12 +85,6 @@ ol.renderer.canvas.TileLayer.prototype.composeFrame = function(
}
var offsetX = Math.round(pixelRatio * size[0] / 2);
var offsetY = Math.round(pixelRatio * size[1] / 2);
// Sub-pixel overlap between tiles to avoid gaps
var overlap = (rotation * 180 / Math.PI) % 90 === 0 ? 0 :
opaque ? 0.25 : 0.125;
renderContext.translate(offsetX, offsetY);
renderContext.rotate(rotation);
// for performance reasons, context.save / context.restore is not used
// to save and restore the transformation matrix and the opacity.
@@ -115,25 +108,25 @@ ol.renderer.canvas.TileLayer.prototype.composeFrame = function(
// filled by a higher resolution tile
renderContext.save();
renderContext.beginPath();
renderContext.moveTo((tileExtent[0] - center[0]) * pixelScale,
(center[1] - tileExtent[1]) * pixelScale);
renderContext.lineTo((tileExtent[2] - center[0]) * pixelScale,
(center[1] - tileExtent[1]) * pixelScale);
renderContext.lineTo((tileExtent[2] - center[0]) * pixelScale,
(center[1] - tileExtent[3]) * pixelScale);
renderContext.lineTo((tileExtent[0] - center[0]) * pixelScale,
(center[1] - tileExtent[3]) * pixelScale);
renderContext.moveTo((tileExtent[0] - center[0]) * pixelScale + offsetX,
(center[1] - tileExtent[1]) * pixelScale + offsetY);
renderContext.lineTo((tileExtent[2] - center[0]) * pixelScale + offsetX,
(center[1] - tileExtent[1]) * pixelScale + offsetY);
renderContext.lineTo((tileExtent[2] - center[0]) * pixelScale + offsetX,
(center[1] - tileExtent[3]) * pixelScale + offsetY);
renderContext.lineTo((tileExtent[0] - center[0]) * pixelScale + offsetX,
(center[1] - tileExtent[3]) * pixelScale + offsetY);
renderContext.closePath();
for (j = 0, jj = clipExtents.length; j < jj; ++j) {
clipExtent = clipExtents[j];
renderContext.moveTo((clipExtent[0] - center[0]) * pixelScale,
(center[1] - clipExtent[1]) * pixelScale);
renderContext.lineTo((clipExtent[0] - center[0]) * pixelScale,
(center[1] - clipExtent[3]) * pixelScale);
renderContext.lineTo((clipExtent[2] - center[0]) * pixelScale,
(center[1] - clipExtent[3]) * pixelScale);
renderContext.lineTo((clipExtent[2] - center[0]) * pixelScale,
(center[1] - clipExtent[1]) * pixelScale);
renderContext.moveTo((clipExtent[0] - center[0]) * pixelScale + offsetX,
(center[1] - clipExtent[1]) * pixelScale + offsetY);
renderContext.lineTo((clipExtent[0] - center[0]) * pixelScale + offsetX,
(center[1] - clipExtent[3]) * pixelScale + offsetY);
renderContext.lineTo((clipExtent[2] - center[0]) * pixelScale + offsetX,
(center[1] - clipExtent[3]) * pixelScale + offsetY);
renderContext.lineTo((clipExtent[2] - center[0]) * pixelScale + offsetX,
(center[1] - clipExtent[1]) * pixelScale + offsetY);
renderContext.closePath();
}
renderContext.clip();
@@ -147,23 +140,19 @@ ol.renderer.canvas.TileLayer.prototype.composeFrame = function(
// gaps caused by rounding
origin = ol.extent.getBottomLeft(tileGrid.getTileCoordExtent(
tileGrid.getTileCoordForCoordAndZ(center, currentZ)));
tileOffsetX = Math.round((origin[0] - center[0]) * pixelScale);
tileOffsetY = Math.round((center[1] - origin[1]) * pixelScale);
tileOffsetX = offsetX + Math.round((origin[0] - center[0]) * pixelScale);
tileOffsetY = offsetY + Math.round((center[1] - origin[1]) * pixelScale);
renderContext.drawImage(tile.getImage(), tileGutter, tileGutter,
tilePixelSize[0], tilePixelSize[1],
Math.round((insertPoint[0] - origin[0]) * pixelScale / tileWidth) *
tileWidth + tileOffsetX - overlap,
tileWidth + tileOffsetX,
Math.round((origin[1] - insertPoint[1]) * pixelScale / tileHeight) *
tileHeight + tileOffsetY - overlap,
tileWidth + 2 * overlap, tileHeight + 2 * overlap);
tileHeight + tileOffsetY, tileWidth, tileHeight);
if (clipExtents) {
renderContext.restore();
}
}
renderContext.rotate(-rotation);
renderContext.translate(-offsetX, -offsetY);
if (renderContext != context) {
this.dispatchRenderEvent(renderContext, frameState, transform);
context.drawImage(renderContext.canvas, 0, 0);
@@ -106,6 +106,11 @@ ol.renderer.canvas.VectorLayer.prototype.composeFrame = function(frameState, lay
var alpha = replayContext.globalAlpha;
replayContext.globalAlpha = layerState.opacity;
var width = frameState.size[0] * pixelRatio;
var height = frameState.size[1] * pixelRatio;
replayContext.translate(width / 2, height / 2);
replayContext.rotate(-rotation);
replayContext.translate(-width / 2, -height / 2);
replayGroup.replay(replayContext, pixelRatio, transform, rotation,
skippedFeatureUids);
if (vectorSource.getWrapX() && projection.canWrapX() &&
@@ -135,6 +140,9 @@ ol.renderer.canvas.VectorLayer.prototype.composeFrame = function(frameState, lay
// restore original transform for render and compose events
transform = this.getTransform(frameState, 0);
}
replayContext.translate(width / 2, height / 2);
replayContext.rotate(rotation);
replayContext.translate(-width / 2, -height / 2);
if (replayContext != context) {
this.dispatchRenderEvent(replayContext, frameState, transform);
@@ -183,12 +183,9 @@ ol.renderer.canvas.VectorTileLayer.prototype.composeFrame = function(frameState,
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);
Math.round(insertPoint[0] + offsetX),
Math.round(insertPoint[1]) + offsetY);
}
}