Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/459.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/html/71.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript HTML5画布在缩放和旋转后向后平移_Javascript_Html_Canvas - Fatal编程技术网

Javascript HTML5画布在缩放和旋转后向后平移

Javascript HTML5画布在缩放和旋转后向后平移,javascript,html,canvas,Javascript,Html,Canvas,我正试着用画布做一些事情。首先,我让一个用户上传一个图像,如果图像比我想要的大,我需要缩小它。那部分很好用。最近我们遇到了iPhone用户上传图像的问题。这些都有定位问题。我已经知道了如何提取方向,我的问题是当我在画布中操纵图像时会发生什么 这就是我需要做的:获取图像,平移(),缩放(),旋转(),平移()480 | |尺寸[1]>853){ //缩放图像。 水平变量=宽度>高度; 如果(水平){ 标度高度=480; scaleRatio=缩放高度/高度; scaledWidth=宽度*比例;

我正试着用画布做一些事情。首先,我让一个用户上传一个图像,如果图像比我想要的大,我需要缩小它。那部分很好用。最近我们遇到了iPhone用户上传图像的问题。这些都有定位问题。我已经知道了如何提取方向,我的问题是当我在画布中操纵图像时会发生什么

这就是我需要做的:获取图像,平移(),缩放(),旋转(),平移()480 | |尺寸[1]>853){ //缩放图像。 水平变量=宽度>高度; 如果(水平){ 标度高度=480; scaleRatio=缩放高度/高度; scaledWidth=宽度*比例; }否则{ 标度宽度=640; scaleRatio=缩放宽度/宽度; 缩放高度=高度*缩放比例; } 画布['width']=缩放宽度; 画布['height']=缩放高度; ctx['drawImage'](图像,0,0,宽度,高度,0,0,缩放宽度,缩放高度); /*旋转图像*/ 方向=8;//手动方向->在站点上,我们使用loadImage获取方向 如果(方向!=1){ 开关(方向){ 案例8: 案例6: canvas.width=缩放高度; canvas.height=缩放宽度; 打破 } var halfScaledWidth=scaledWidth/2; var halfScaledheight=缩放高度/2;
ctx.save();//试试这个。你的代码是正确的,但是当你尝试旋转和缩放图像时(如果你想得到它),你必须改变方向变量。

变换

对于简单的答案,如果你对如何跳到底部,你会找到一个替代方法来解决你的问题。这都是评论。我已经做了一些猜测,你想要什么

如果你感兴趣的是我认为使用2D变换函数的简单方法,请阅读其余部分。

矩阵数学

通过canvas 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这种方式对于复杂的链接动画非常方便。不幸的是,如果您不了解矩阵数学,这也会导致无尽的挫折。它还迫使许多人使用
save
restore
函数进行还原默认转换,即在某些情况下,GPU性能可能非常昂贵

setTransform()

不过我们很幸运,因为2D API也有函数
ctx.setTransform(a、b、c、d、e、f)
这是您真正需要的功能。此功能将现有转换替换为提供的转换。大多数文档对
a、b、c、d、e、f
的含义相当模糊,但其中包含旋转、缩放和平移

该函数的一个方便用法是设置默认转换,而不是使用保存和恢复

我经常看到这种类型的东西。(下面引用的示例1)

一种更简单的方法是直接删除保存,通过将变换设置为单位矩阵手动恢复和重置变换

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.5,0,0)
我们的像素现在是半个像素

这两个轴向量(a,b)和(c,d)可以指向任何方向,彼此完全独立,它们不必彼此成90度角,因此可以使像素倾斜,也不要求它们具有相同的长度,以便可以更改p
// 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
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
// 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;
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);
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;
// ctx is the 2D context, 
// originX, and originY is the origin, same as ctx.translate(originX,originY)
// rotation is the angle in radians same as ctx.rotate(rotation)
// scale is the scale of x and y axis same as ctx.scale(scale,scale)
function createTransform(ctx,originX,originY,rotation,scale){
    var x, y;
    x = Math.cos(rotation) * scale;
    y = Math.sin(rotation) * scale;
    ctx.setTransform(x, y, -y, x, originX, originY);
}
// dont need ctx.save();  // save state
// dont need ctx.scale(2,2);
// dont need ctx.rotate(Math.PI/2);
// dont need ctx.translate(100,100);
createMatrix(ctx, 100, 100, Math.PI/2, 2)
// draw the image normally
ctx.drawImage(img1, -img1.width / 2, -img1.height / 2);
// dont need ctx.restore(); // restore saved state

// transform for image 2
// dont need ctx.save();  // save state agian
// dont need ctx.scale(1,1);
// dont need ctx.rotate(Math.PI);
// dont need ctx.translate(100,100);
// we don't have to reset the default transform because 
// ctx.setTransform completely replaces the current transform
createMatrix(ctx, 100, 100, Math.PI/2, 2)
// draw the image
ctx.drawImage(img2, -img2.width / 2, -img2.height / 2);
// dont need ctx.restore(); // restore saved state
    // this is in set up code
    const MAX_SIZE_WIDTH = 640;
    const MAX_SIZE_HEIGHT = 480;
    orientationData = [];
    orientationData[6] = Math.PI/2; // xAxis pointing down
    orientationData[8] = -Math.PI/2; // xAxis pointing up
    orientationData[3] = Math.PI; //xAxis pointing to left


    // in your code
    var orient,w,h,iw,ih,scale,ax,ay; // w and h are canvas size

    // assume image is the loaded image
    iw = image.width;  // get the image width and height so I dont have to type as much.
    ih = image.height;

    if(orientation != 1){
        var orient = orientationData[orientation];
        if(orient === undefined){
             return; // bad data so return
        }

        // get scale  and resize canvas to suit

        // is the image on the side 
        if(orientation === 6 || orientation === 8){
             // on side so swap width and height
             // get the height and width scales for the image, dont scale 
             // if the image is smaller than the dimension
             scale = Math.min(1,
                  MAX_SIZE_WIDTH / ih, 
                  MAX_SIZE_HEIGHT  / iw
             );
             w = canvas.width = scale * ih;  
             h = canvas.height = scale * iw;
        }else{
             // for normal orientation
             scale = Math.min(1,
                  MAX_SIZE_WIDTH / iw, 
                  MAX_SIZE_HEIGHT  / ih
             );
             h = canvas.height = scale * ih;  
             w = canvas.width = scale * iw;
        }


        // Do you really need to clear the canvas if the image is filling it??
        // ensure that the default transform is set
        ctx.setTransform(1, 0, 0, 1, 0, 0);
        // clear the canvas 
        ctx.clearRect(0, 0, w, h);

        // now create the transformation matrix to 
        // position the image in the center of the screen

        // first get the xAxis and scale it
        ax = Math.cos(orient) * scale;
        ay = Math.sin(orient) * scale;
        // now set the transform, the origin is always the canvas center
        // and the Y axis is 90 deg clockwise from the xAxis and same scale
        ctx.setTransform(ax, ay, -ay, ax, w / 2, h / 2);

        // now draw the image offset by half its width and height 
        // so that it is centered on the canvas

        ctx.drawImage(image,-iw / 2, -ih / 2);

        // restore the default transform
        ctx.setTransform(1, 0, 0, 1, 0, 0);
  } // done.