Rotate map canvas after composition
This commit is contained in:
+18
-12
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user