要旋转图像并缩放它,使得图像的边缘在画布范围内任何位置都不会超出边界,您需要计算从画布中心到一个角的距离。
var dist = Math.sqrt(Math.pow(canvas.width/2,2)+Math.pow(canvas.height/2,2));
现在您需要找到图像中心点到其最近边缘的距离。
var imgDist = Math.min(image.width,image.height)/2
现在我们有了所需的信息,可以确定图像的最小比例,以便在绘制在画布中心时始终适合画布。
var minScale = dist / imgDist;
现在需要以图像中心为轴心进行旋转、缩放并将其定位于画布中心。
首先计算一个像素顶部边缘(X轴)的方向和大小。
// ang is the rotation in radians
var dx = Math.cos(ang) * minScale;
var dy = Math.sin(ang) * minScale;
创建转换矩阵,其中前两个数字是X轴,后两个数字是Y轴,这是从X轴顺时针旋转90度的,最后两个数字是画布像素坐标系中距离画布原点(左上角)的原点。
// ctx is the canvas 2D context
ctx.setTransform(dx, dy, -dy, dx, canvas.width / 2, canvas.height / 2);
现在将图像偏移其高度和宽度的一半。
ctx.drawImage(image,-image.width / 2, - image.height / 2);
最后一件事就是恢复默认变换。
ctx.setTransform(1,0,0,1,0,0);
完成了。
作为一个函数
function drawToFitRotated(ctx, angle, image){
var dist = Math.sqrt(Math.pow(ctx.canvas.width /2, 2 ) + Math.pow(ctx.canvas.height / 2, 2));
var imgDist = Math.min(image.width, image.height) / 2;
var minScale = dist / imgDist;
var dx = Math.cos(angle) * minScale;
var dy = Math.sin(angle) * minScale;
ctx.setTransform(dx, dy, -dy, dx, ctx.canvas.width / 2, ctx.canvas.height / 2);
ctx.drawImage(image, -image.width / 2, - image.height / 2);
ctx.setTransform(1, 0, 0, 1, 0, 0);
}
更新
由于这是一个有趣的问题,我看了看是否能够找出如何最好地适应旋转图像,以确保图像始终填充画布,同时尽可能多地显示图像。解决方案意味着随着图像旋转,比例会改变,因为边缘会到角落,比例在4个点上突然停止缩小并重新开始增长。尽管如此,这对于需要填充画布但又需要旋转的静态图像是很有用的。
最好的方法是用图片来描述
图像是绿色的,画布是红色的,图像的旋转角度是R。我们需要找到线段CE和CF的长度。Ih和Iw分别是图像高度和宽度的一半。
从画布中,我们计算出线段CB的长度,即画布高度(ch)和宽度(cw)的一半平方根之和。
然后我们需要角度A,它是C-B直线长度的acos (ch) / length line C-B
现在我们有了角度A,可以计算出角度A1和A2。现在我们有了长度C-B和角度A1,A2,我们可以解决直角三角形CEB和CFB,以获得CE和CF的长度。
即C-E =线段C-B * cos(A1)和C-F =线段C-B * cos(A2)
然后得到图像高度的比例,即长度C-E除以Ih,以及C-E除以Iw的比例。由于图像纵横比可能与需要适应的矩形不匹配,因此我们需要保持两个比例中较大的那个。
所以最终得到了一个符合要求的比例。
还有一个问题。该数学公式适用于0-90度之间的角度,但对其它角度无效。幸运的是,每个象限的问题都是对称的。对于大于180度的角度,我们进行镜像并旋转回来180度;对于90度至180度之间的角度,我们进行反转并旋转回90度。在演示中,我使用弧度值。我们还确保给定的角度始终在0-360范围内(即0到Math.PI * 2)。
接下来只需创建矩阵并绘制图像。
在演示中,我添加了两个方框。蓝色的是画布轮廓的一半大小副本,红色的是图像的半大小副本。我这样做是为了让您看到图像旋转时比例不平滑的原因。
我也会保留这个函数,因为它很方便。
请查看演示代码以获取新函数。
demo = function(){
var canvas = (function(){
var canvas = document.getElementById("canv");
if(canvas !== null){
document.body.removeChild(canvas);
}
canvas = document.createElement("canvas");
canvas.id = "canv";
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.style.position = "absolute";
canvas.style.top = "0px";
canvas.style.left = "0px";
canvas.style.zIndex = 1000;
canvas.ctx = canvas.getContext("2d");
document.body.appendChild(canvas);
return canvas;
})();
var ctx = canvas.ctx;
var image = new Image();
image.src = "http://i.imgur.com/gwlPu.jpg";
var w = canvas.width;
var h = canvas.height;
var cw = w / 2;
var ch = h / 2;
function drawBestFit(ctx, angle, image){
var iw = image.width / 2;
var ih = image.height / 2;
var dist = Math.sqrt(Math.pow(cw,2) + Math.pow(ch,2));
var diagAngle = Math.asin(ch/dist);
a1 = ((angle % (Math.PI *2))+ Math.PI*4) % (Math.PI * 2);
if(a1 > Math.PI){
a1 -= Math.PI;
}
if(a1 > Math.PI/2 && a1 <= Math.PI){
a1 = (Math.PI/2) - (a1-(Math.PI/2));
}
var ang1 = Math.PI/2 - diagAngle - Math.abs(a1);
var ang2 = Math.abs(diagAngle - Math.abs(a1));
var dist1 = Math.cos(ang1) * dist;
var dist2 = Math.cos(ang2) * dist;
var scale = Math.max(dist2/(iw),dist1/(ih));
var dx = Math.cos(angle) * scale;
var dy = Math.sin(angle) * scale;
ctx.setTransform(dx, dy, -dy, dx, cw, ch);
ctx.drawImage(image, -iw, - ih);
ctx.strokeStyle = "red";
ctx.lineWidth = 2 * (1/scale);
ctx.strokeRect(-iw / 2, -ih / 2, iw, ih)
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.strokeStyle = "blue";
ctx.lineWidth = 2;
ctx.strokeRect(cw - cw / 2, ch - ch / 2, cw, ch)
}
function drawToFitRotated(ctx, angle, image){
var dist = Math.sqrt(Math.pow(cw,2) + Math.pow(ch,2));
var imgDist = Math.min(image.width, image.height) / 2;
var minScale = dist / imgDist;
var dx = Math.cos(angle) * minScale;
var dy = Math.sin(angle) * minScale;
ctx.setTransform(dx, dy, -dy, dx, cw, ch);
ctx.drawImage(image, -image.width / 2, - image.height / 2);
ctx.setTransform(1, 0, 0, 1, 0, 0);
}
var angle = 0;
function update(){
if(image.complete){
angle += 0.01;
drawBestFit(ctx,angle,image);
}
if(!STOP){
requestAnimationFrame(update);
}else{
STOP = false;
var canv = document.getElementById("canv");
if(canv !== null){
document.body.removeChild(canv);
}
}
}
update();
}
var STOP = false;
function resizeEvent(){
var waitForStopped = function(){
if(!STOP){
demo();
return;
}
setTimeout(waitForStopped,200);
}
STOP = true;
setTimeout(waitForStopped,100);
}
window.addEventListener("resize",resizeEvent);
demo();
rotate()
函数。你正在使用的是ctx.rotate()
。 - John Bupit