在Canvas上绘制CSS变换(缩放,旋转,左,右)

时间:2016-01-02 13:40:46

标签: javascript css html5 canvas

我正在从用户的网络摄像头拍照并在Canvas上绘图。我使用CSS构建视频控件,如缩放视频,旋转,左/右移动。它正在应用于实时流,但是当我在Canvas上拍照并绘制时,这些功能(旋转,缩放)不适用。 我知道,因为我没有改变Canvas,这就是为什么它没有应用。

所以,任何想法如何使用相同的CSS代码在画布上绘制[旋转,缩放,左/右移动]。 (或者可能是特定于Canvas上下文的代码。)

2 个答案:

答案 0 :(得分:1)

转型变得轻松。

不幸的是,给定的答案无法描述缩放,平移和旋转功能的正确用法。这些函数乘以现有的变换,因此结果是相对的而不是绝对的。例如,来自默认转换

ctx.setTransform(1, 0, 0, 1, 0, 0);  // set the transformation to the default identity matrix
ctx.scale(2, 2);  // scale the transform. Objects are now drawn 2 time larger
ctx.scale(2, 2);  // This is applied to the existing scale
                  // objects are now draw 4 times as large not 2 times
ctx.rotate(Math.PI / 2); // rotate the transformation 90 deg clockwise
                         // objects are drawn with the x axis down the screen
ctx.rotate(Math.PI / 2); // Rotate a further 90 deg clockwise
                         // objects are drawn with the x axis from right to left
                         // and the y axis moves up

ctx.translate(x, y)函数也是相对的,并且由于您提供的坐标由现有转换转换,因此更难处理。因此,如果在上面的代码之后应用给出100乘100的平移,则首先缩放并旋转4度和180度。结果位置将位于画布坐标x:-400和y:-400处。要转换为所需的坐标(100,100),首先需要应用逆变换,这将导致ctx.translate(-25, -25)

因为没有办法确切知道当前的变换,所以很难计算逆变换并应用它,这样你就可以在画布坐标中工作。

<强>的setTransform

并非所有内容都丢失了画布2D API提供了一个函数ctx.setTransform(),它用一个新的替换当前的转换。它不是相对的,而是绝对的。这使您可以确切地知道当前的转换并大大简化了转换图像(或任何正在绘制的内容)的过程

通用功能。

要旋转缩放和定位图像,这是一个通用功能,可以帮助您完成此操作。

参数

  • ctx :要绘制的2D画布上下文。
  • 图片:要绘制的图像。
  • x,y :绝对画布坐标放置中心 坐标at,以画布左上角的像素为单位。
  • centerX,centerY :图像原点的坐标(以像素为单位)相对于协调的图像。如果图像是100乘100然后设置centerX,则centerY到50,50将缩放并围绕图像的中心旋转,并将该中心绘制在由参数x和y给定的坐标处。如果将centerX,centerY设为0,0,则图像将旋转并围绕左上角缩放。
  • 比例:绘制图像的比例。值1表示无刻度,2表示 0.5倍是大小的一半。负数反转图像 在x和y方向
  • 旋转:以弧度为单位的旋转量,0表示否 旋转,然后顺时针旋转90度,Math.PI / 2Math.PIMath.PI * 1.5,并回到起点Math.PI * 2

它的作用

该函数使用所需的比例和平移设置绝对变换。将旋转应用于该变换,然后绘制图像偏移以将centerX,centerY放置在所需的坐标处。最后,该函数将转换设置回默认值。如果您对所有转换使用函数或setTransform,则严格不需要这样做,但我已将其添加到不会使80%的现有代码陷入混乱,这些代码将依赖于默认转换为当前代码。

功能源代码。

function drawImage(ctx, image, x, y, centerX, centerY, scale, rotate){
    ctx.setTransform(scale, 0, 0, scale, x, y);  // resets transform and 
                                                 // set scale and position
    ctx.rotate(rotate);  // apply the rotation to the above transformation
    ctx.drawImage(image, -centerX, -centerY);  // draw the image offset to its center
    ctx.setTransform(1, 0, 0, 1, 0, 0); // restore the transformation to default.
}

或者更简单的版本不会将不需要的重置重置为默认转换

function drawImage(ctx, image, x, y, centerX, centerY, scale, rotate){
    ctx.setTransform(scale, 0, 0, scale, x, y);  // resets transform and 
                                                 // set scale and position
    ctx.rotate(rotate);  // apply the rotation to the above transformation
    ctx.drawImage(image, -centerX, -centerY);  // draw the image offset to its center
}

或者假设您始终使用图像中心

function drawImageCentered(ctx, image, x, y, scale, rotate){
    ctx.setTransform(scale, 0, 0, scale, x, y);  // resets transform and 
                                                 // set scale and position
    ctx.rotate(rotate);  // apply the rotation to the above transformation
    ctx.drawImage(image, -image.width / 2, -image.height / 2);  // draw the image offset to its center
}

<强>用法

// image; is a 200 by 200 pixel image
// ctx; is the canvas 2D context
// canvas; is the canvas element

// call the function
drawImage(
    ctx,          // the context
    image,        // the image to draw
    canvas.width / 2, canvas.height / 2,  //draw it at the center of the canvas
    image.width / 2, image.height / 2,    // at the image center
    2,            // scale to twice its size
    Math.PI / 4   // and rotated clockwise 45 deg
); 

答案 1 :(得分:0)

你不能通过CSS来做,但在绘制到画布时使用一些javascript。对于缩放,您需要使用drawImage上下文中canvas.getContext()的参数半手动处理它。基本上,参数2-5是(按顺序),x,y,宽度和高度的区域,您从中提取图像,参数6-9与它放入图像的方式相同。

例如,如果您的基本图像是2000x2000,并且您将其成像为1000x1000的画布:

以下内容只是将整个图像绘制成较小的图像。

var ctx = canvas.getContext("2d");
ctx.drawImage(img,0,0,2000,2000,0,0,1000,1000);

虽然这会将基本图像的中间1000x1000绘制到画布中(即2倍变焦):

var ctx = canvas.getContext("2d");
ctx.drawImage(img,500,500,1000,1000,0,0,1000,1000);

在上面,它说,从(500,500)到(1500,1500)提取区域并将其“打印”到画布中。

旋转更复杂,因为如果您只是rotate图像并从画布的原点(0,0)绘制,则图像将在画布外结束。您还需要在画布上执行translate

var ctx = canvas.getContext("2d");
ctx.rotate(90 * Math.PI/180);    //rotate 90 degrees
ctx.translate(0, -canvas.height); //translate down the height of the canvas

OR

var ctx = canvas.getContext("2d");
ctx.rotate(180 * Math.PI/180);    //rotate 180 degrees
ctx.translate(-canvas.width,-canvas.height);  // translate down and over

OR

var ctx = canvas.getContext("2d");
ctx.rotate(270 * Math.PI/180);    //rotate 270 degrees
ctx.translate(-canvas.width,0);  // translate down and over

请注意,旋转发生在左上角附近。如果你想支持自由轮换,这一切都会变得更复杂。

编辑:正如Blindman67在他的评论中正确指出的那样,变换适用于基于应用的任何先前变换的上下文的变换状态。我更新了代码示例,以阐明当应用于之前未应用转换的干净上下文时,这是转换的效果。