javascript – HTML5画布在缩放和旋转后转换回来
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了javascript – HTML5画布在缩放和旋转后转换回来,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含7820字,纯文字阅读大概需要12分钟。
内容图文
![javascript – HTML5画布在缩放和旋转后转换回来](/upload/InfoBanner/zyjiaocheng/750/1627c18e9d734ca086a6832b06a92e86.jpg)
我正在尝试用帆布做一些事情.首先我有一个用户上传图像,如果图像比我想要的大,我需要缩小它.那部分工作正常.最近我们遇到了iPhone用户上传图片的问题.这些都有方向问题.我已经弄清楚如何提取方向,我的问题是当我在画布中操作图像时会发生什么.
这就是我需要做的:获取图像,translate(),scale(),rotate(),translate()< - 将其恢复到原始位置drawImage().
当我这样做时,部分图像在深渊中消失.
if (dimensions[0] > 480 || dimensions[1] > 853) {
// Scale the image.
var horizontal = width > height;
if (horizontal) {
scaledHeight = 480;
scaleRatio = scaledHeight / height;
scaledWidth = width * scaleRatio;
} else {
scaledWidth = 640;
scaleRatio = scaledWidth / width;
scaledHeight = height * scaleRatio;
}
canvas['width'] = scaledWidth;
canvas['height'] = scaledHeight;
ctx['drawImage'](image, 0, 0, width, height, 0, 0, scaledWidth, scaledHeight);
/* Rotate Image */
orientation = 8; //manual orientation -> on the site we use loadImage to get the orientation
if(orientation != 1){
switch(orientation){
case 8:
case 6:
canvas.width = scaledHeight;
canvas.height = scaledWidth;
break;
}
var halfScaledWidth = scaledWidth/2;
var halfScaledheight = scaledHeight/2;
ctx.save(); //<- SAVE
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.translate(halfScaledWidth,halfScaledheight);
switch(orientation){
case 8: //rotate left
ctx.scale(scaleRatio,scaleRatio);
ctx.rotate(-90*Math.PI/180);
ctx.translate(-1380,-1055); // <-Manuial numbers
break;
case 3: //Flip upside down
ctx.scale(scaleRatio,scaleRatio);
ctx.rotate(180*Math.PI/180);
ctx.translate(-925,-595); //<-Manuial numbers
break;
case 6: //rotate right
ctx.scale(scaleRatio,scaleRatio);
ctx.rotate(90*Math.PI/180);
ctx.translate(-462,-130); //<-Manuial numbers
break;
}
//re-translate and draw image
//ctx.translate(-halfScaledWidth,-halfScaledheight);
ctx.drawImage(image,-halfScaledWidth, -halfScaledheight);
ctx.restore(); //<- RESTORE
}
/* Rotate Image */
}
我手动定位,所以我可以看到它在每个位置看起来如何担心.如果是纵向,我翻转画布.
我尝试过save()和restore().我试过翻译(x,y)然后翻译(-x,-y)..我的猜测是因为网格关闭的比例,x和y需要相乘.我尝试对scaleRatio这样做,但仍然无法正常工作.
正如你所看到的,我手动设置了翻译,但这只适用于我正在使用的图像尺寸,所以根本不是一个好的解决方案!
这是代码:
JSFiddle如果我正常旋转,它一切正常.
谢谢!
解决方法:
转换
如果您对如何跳到底部不感兴趣,您可以找到替代问题的替代方案,以获得简单的答案.这是评论.我对你想要的东西做了一些猜测.
如果您对我认为使用2D转换函数的更简单方法感兴趣,请阅读其余部分.
矩阵数学
当您通过画布2D API使用平移,缩放和旋转时,您正在做的是将现有矩阵与使用每个函数创建的矩阵相乘.
基本上当你这样做
ctx.rotate(Math.PI); // rotate 180 deg
API创建一个新的旋转矩阵,并将现有矩阵与其相乘.
与普通的数学乘法矩阵乘法不同,它会根据您乘以的顺序改变结果.在正常的数学乘法中,A * B = B * A,但这不适用于矩阵mA * mB!= mB * mA(注意不等于)
当您需要应用多个不同的转换时,这会变得更成问题.
ctx.scale(2,2);
ctx.rotate(Math.PI/2);
ctx.translate(100,100);
不会给出相同的结果
ctx.scale(2,2);
ctx.translate(100,100);
ctx.rotate(Math.PI/2);
应用变换所需的顺序取决于您要实现的目标.使用API??这种方式对于复杂的链接动画非常方便.不幸的是,如果你不了解矩阵数学,它也是无尽挫折的根源.它还迫使许多人使用保存和恢复功能来恢复默认转换,在某些情况下,GPU性能可能非常昂贵.
一个setTransform()
我们很幸运,因为2D API也有函数ctx.setTransform(a,b,c,d,e,f),这是你真正需要的.此函数将使用提供的变换替换现有变换.大多数文档对于a,b,c,d,e,f的含义相当模糊,但其中包含的是旋转,缩放和平移.
该函数的一个方便用途是设置默认转换,而不是使用保存和恢复.
我经常看到这种类型的东西. (示例1,进一步参考)
// transform for image 1
ctx.save(); // save state
ctx.scale(2,2);
ctx.rotate(Math.PI/2);
ctx.translate(100,100);
// draw the image
ctx.drawImage(img1, -img1.width / 2, -img1.height / 2);
ctx.restore(); // restore saved state
// transform for image 2
ctx.save(); // save state agian
ctx.scale(1,1);
ctx.rotate(Math.PI);
ctx.translate(100,100);
// draw the image
ctx.drawImage(img2, -img2.width / 2, -img2.height / 2);
ctx.restore(); // restore saved state
更简单的方法是通过将其设置为Identity矩阵来删除保存并恢复并手动重置变换
ctx.scale(2,2);
ctx.rotate(Math.PI/2);
ctx.translate(100,100);
// draw the image
ctx.drawImage(img1, -img1.width / 2, -img1.height / 2);
ctx.setTransform(1,0,0,1,0,0); // restore default transform
// transform for image 2
ctx.scale(1,1);
ctx.rotate(Math.PI);
ctx.translate(100,100);
// draw the image
ctx.drawImage(img2, -img2.width / 2, -img2.height / 2);
ctx.setTransform(1,0,0,1,0,0); // restore default transform
现在我确定你仍然想知道这些数字传递给setTransform是什么,它们是什么意思?
记住它们的最简单方法是2个向量和1个坐标.这两个向量描述了单个像素的方向和比例,坐标只是原点的x,y像素位置(绘制在0,0的位置将在画布上).
像素及其轴
想象一个像素,这是可以通过当前变换进行缩放和旋转的抽象变换像素.它有两个轴,X和Y.为了描述每个轴,我们需要两个数字(一个矢量),它们描述了像素顶部和左侧的屏幕(未变换)方向和比例.因此,对于与屏幕像素匹配的普通像素,X轴从左到右跨越顶部并且是一个像素长.向量是(1,0)一个像素,没有像素向下.对于沿着屏幕下行的Y轴,向量是(0,1)没有像素,一个像素向下.原点是右上角的屏幕像素,它位于坐标(0,0)处.
因此,我们得到了身份矩阵,2D API(和许多其他API)的默认矩阵X轴(1,0),Y轴(0,1)和原点(0,0)匹配六个参数的setTransform(1,0,0,1,0,0).
现在说我们想要缩放像素.我们所做的只是增加X和Y轴的大小setTransform(2,0,0,2,0,0)与scale(2,2)相同(来自默认变换)我们的像素顶部现在是两个像素长的顶部和两个像素长的左侧.为了缩小setTransform(0.5,0,0,0.5,0,0),我们的像素现在是横向和向下的半个像素.
这两个轴向量(a,b)& (c,d)可以指向任何方向,完全相互独立,它们不必相互成90度,因此可以使像素倾斜,也不要求它们长度相同,这样你就可以改变像素方面.原点也是独立的,只是原点像素的画布绝对坐标,可以设置为画布上或画布外的任何位置.
现在说我们想要顺时针旋转变换90度,将两个轴向上放大2并将原点定位在画布的中心.我们希望像素的X轴(顶部)长2像素,并指向屏幕.向量为(0,2)0横向和向下两个.我们希望像素的左侧长2并指向屏幕的左侧(-2,0)负两个横向并且没有向下.并且中心的原点是(canvas.width / 2,canvas.height / 2)以获得最终矩阵,即setTransform(0,2,-2,0,canvas.width / 2,canvas.height / 2)
旋转另一种方式是setTransform(0,-2,2,0,canvas.width / 2,canvas.height / 2)
轻松旋转90度
您可能会注意到旋转90度只是交换向量并更改符号.
>顺时针旋转90度的矢量(x,y)为(-y,x).
>逆时针旋转90度的矢量(x,y)是(y,-x).
交换x和y并顺时针取消y或取消逆时针旋转的x.
对于180,它从0度向量(1,0)开始
// input vector
var x = 1;
var y = 0;
// rotated vector
var rx90 = -y; // swap y to x and make it negative
var ry90 = x; // x to y as is
// rotate again same thing
var rx180 = -ry90;
var rx180 = rx90;
// Now for 270
var rx270 = -ry180; // swap y to x and make it negative
var rx270 = rx180;
或者仅仅是x和y
> 0度(x,y)
> 90deg(-y,x)
> 180deg(-x,-y)
> 270deg(y,-x)
>并回到360(x,y).
这是一个非常方便的向量属性,我们可以利用它来简化转换矩阵的创建.在大多数情况下,我们不希望扭曲图像,因此我们知道Y轴始终是从x轴顺时针90度.现在我们只需要描述x轴,并通过将90deg旋转应用于该向量,我们就有了y轴.
因此,变量x和y是像素顶部的比例和方向(x轴),ox,oy是画布上原点的位置(平移).
var x = 1; // one pixel across
var y = 0; // none down
var ox = canvas.width / 2; // center of canvas
var oy = canvas.height / 2;
现在要创建转换了
ctx.setTransform(x, y, -y, x, ox, oy);
注意,y轴相对于x轴为90度.
Trig和单位矢量
当轴与顶部和侧面对齐时,一切都很顺利,如何获得任意角度的轴矢量,例如ctx.rotate(angle)的参数所提供的为此我们需要一点点TRIG. Math函数Math.cos(angle)返回角度的x分量,角度和Math.sin(角度)给出Y分量.对于零度cos(0)= 1且sin(0)= 0表示90度(Math.PI / 2弧度)cos(PI / 2)= 0且sin(PI / 2)= 1.
使用sin和cos的美妙之处在于,我们为向量得到的两个数字总是给出一个长度为1个单位(像素)的向量(这称为归一化向量或单位向量)因此cos(a)2 sin (a)2 = 1
为什么这很重要?因为它使缩放非常容易.假设我们始终保持方面平方,我们只需要一个数字用于比例.要缩放矢量,只需将其乘以比例即可
var scale = 2; // scale of 2
var ang = Math.random() * 100; // any random angle
var x = Math.cos(ang); // get the x axis as a unit vector.
var y = Math.sin(ang);
// scale the axis
x *= scale;
y *= scale;
向量x,y现在是两个单位长.
比使用保存,恢复,旋转,缩放,翻译更好…
内容总结
以上是互联网集市为您收集整理的javascript – HTML5画布在缩放和旋转后转换回来全部内容,希望文章能够帮你解决javascript – HTML5画布在缩放和旋转后转换回来所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。