canvas变换操作在应用当中非常常用,下面我们来讨论canvas当中用于变换的api。

平移,context.translate(x,y)

参数解析:

  • x:坐标系向左或向右移动的距离。
  • y:坐标系向上或向下移动的距离。

这个方法主要用于平移,平移什么?平移坐标原点。它的平移是相对于当前原点的,就是说,之前原点在(0,0),现在translate(5,5)之后,坐标原点移动到(5,5)。如果继续调用translate(10,10),现在的坐标原点不是(10,10),而是(15,15)。就是累加坐标值。

canvas translate

代码:

<!DOCTYPE HTML>
<html>
  <head>
    <style>
      body {
        margin: 0px;
        padding: 0px;
      }
      #myCanvas{border:1px solid blue;margin-left:auto;margin-right:auto;display: block;margin-top:20px;}
    </style>
  </head>
  <body>
    <canvas id="myCanvas" width="500" height="300"></canvas>
    <script>
      var canvas = document.getElementById('myCanvas');
      var context = canvas.getContext('2d');
      context.fillStyle = "#ff0000"; 
      context.fillRect(20, 20, 150, 100); 

      context.translate(50, 50); 
      context.fillStyle = "rgba(00,255,00,0.7)"; 
      context.fillRect(20, 20, 150, 100); 

      context.translate(15, 15);
      context.fillStyle = "rgba(00,00,256,0.7)";
      context.fillRect(20, 20, 150, 100); 
    </script>
  </body>
</html>    

效果:

canvas translate

注意第三个矩形,这个时候的坐标原点应该是(50+15,50+15)。

旋转,context.rotate(angle)

angle是旋转的角度(弧度单位),沿着坐标原点旋转angle弧度。旋转的是坐标系而不是已经画出来的图形,这一点要和ps这些软件当中的旋转操作区别开来。调用rotate之后,只影响后面的绘图操作,绘制的所有形状都将围绕画布上的(0,0)点旋转(没有平移坐标的情况之下)。

旋转之后的坐标系:

canvas旋转

下面是一个在设置旋转前后绘制相同矩形的示例:

      var canvas = document.getElementById('myCanvas');
      var context = canvas.getContext('2d');
      context.fillStyle = "#ff0000";
      context.fillRect(10,10, 100, 100);

      context.rotate( (Math.PI / 180) * 30);  //旋转30度.

      context.fillStyle = "#0000ff";
      context.fillRect(10,10, 100, 100);

效果:

canvas旋转

上面 图形,旋转到画布外面去了,若要围绕形状自身的中心旋转形状,必须首先将画布平移到形状的中心,然后旋转画布,然后将画布平移回上一步的原点位置。

代码如下:

<!DOCTYPE HTML>
<html>
  <head>
    <style>
      body {
        margin: 0px;
        padding: 0px;
      }
      #myCanvas{border:1px solid blue;margin-left:auto;margin-right:auto;display: block;margin-top:20px;}
    </style>
  </head>
  <body>
    <canvas id="myCanvas" width="500" height="300"></canvas>
    <script>
      var canvas = document.getElementById('myCanvas');
      var context = canvas.getContext('2d');
      var x      = 20;
      var y      = 20;
      var width  = 100;
      var height = 100
      //计算矩形中点坐标
      var cx     = x + 0.5 * width;   
      var cy     = y + 0.5 * height;  

      context.fillStyle = "purple";
      context.fillRect(x, y, width, height);  

      context.translate(cx, cy);              //平移坐标原点
      context.rotate( (Math.PI / 180) * 45);  //旋转45度
      context.translate(-cx, -cy);            //复位上一步的坐标原点,实际上可以通过状态栈来操作

      context.fillStyle = "#0000ff";
      context.fillRect(x, y, width, height);
    </script>
  </body>
</html>    

效果如下:

canvas书籍

注意上面的这一行代码context.translate(-cx, -cy);,如果少了这一行就直接绘制,那么就不是原位旋转了,而是平移之后的旋转,图形会绘制到下方去。

缩放,context.scale(scaleX, scaleY)

参数解析:

  • scaleX:水平缩放因子。
  • scaleY:垂直缩放因子。

scale() 方法为画布的当前变换矩阵添加一个缩放变换。缩放通过独立的水平和垂直缩放因子来完成。例如,传递一个值 2.0 和 0.5 将会导致绘图路径宽度变为原来的两倍,而高度变为原来的 1/2。指定一个负的 sx 值,会导致 X 坐标沿 Y 轴对折,而指定一个负的sy 会导致 Y 坐标沿着 X 轴对折实现翻转效果。

代码:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>scale</title>
</head>

<body>
    <canvas id='myCanvas' width='800' height='600'>
        your browser does not support canvas
    </canvas>
    <script type="text/javascript">
    var c = document.getElementById('myCanvas');
    var ctx = c.getContext('2d');
    ctx.beginPath();
    ctx.strokeStyle = '#ff0000';
    ctx.strokeRect(10, 10, 150, 100);
    //放大3倍
    ctx.scale(3, 3);
    ctx.beginPath();
    ctx.strokeStyle = 'purple';
    ctx.strokeRect(10, 10, 150, 100);
    //缩小到0.5
    ctx.scale(0.5,0.5);
    ctx.beginPath();
    ctx.strokeStyle = 'blue';
    ctx.strokeRect(10,10,150,100);

    </script>
</body>

</html>

效果:

canvas缩放

可以看到缩放之后的绘图原点发生了变化,不再重合了。


scale可以实现翻转效果:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>翻转</title>
</head>

<body>
    <canvas id='myCanvas' width='800' height='600'>
        your browser does not support canvas
    </canvas>
    <script type="text/javascript">
    var c = document.getElementById('myCanvas');
    var ctx = c.getContext('2d');
    var img = new Image();
    img.src = 'https://www.md86.net/resource/upload/20200828/5f48cfed796d019076.jpg';
    img.onload = function() {
        ctx.scale(1, -1);
        ctx.drawImage(img, 20,-450);
        ctx.arc(20, -450, 20, 0, 2 * Math.PI, true);
        ctx.stroke();
    };
    </script>
</body>

</html>

翻转效果:

canvas翻转

上面垂直缩放因子设置为了-1,实际上是把y轴倒过来,我们知道默认的y轴向下延伸,设置为-1之后,y轴就向上延伸了,所以:

ctx.drawImage(img, 20,-450);这行代码我们设置为-450,如果是正的450,那么就把图片绘制到画布外面了。

X轴也是类似的。

Canvas变换矩阵

前面讲了一些canvas变换的方法,现在我们来研究变换矩阵,抛开矩阵具体的数学知识,我们只研究怎么运用这个矩阵来达到之前变换方法相同的目的。当然,如果你熟悉线性代数,那么你可以更加深刻的理解变换矩阵。

transmation matrix

translate()、scale()和rotate()的操作可以使用transform(a、b、c、d、e、f)一次执行。画布上的所有对象都有一个与当前状态相关联的矩阵。将当前矩阵与变换矩阵相乘以产生整体效果。矩阵有9个数,最后一行始终保持[0 0 1],其他参数如下:

  • a:沿X轴缩放对象
  • b:使对象水平倾斜(即水平斜切)。
  • c:使对象垂直倾斜(即垂直斜切)。
  • d:沿Y轴缩放对象。
  • e:沿X轴平移对象。
  • f:沿Y轴平移对象。

你可以忽略变换矩阵最下面一行!你永远不会改变它的值。重要的行是第一行和第二行!分别对应transform(a、b、c、d、e、f)中的6个参数。

单位矩阵

现在,在我们学习如何手动操作变换矩阵之前,我应该知道默认情况下变换矩阵初始值是多少。刚创建的2d渲染上下文将包含一个新的变换矩阵,这个矩阵是单位矩阵。

identity matrix

这个特殊矩阵除了主对角线上的值为1,其他值都设置为0。为什么要这样设置?后面的数学理论暂时不去关注,我们只需要知道,这种状态表示不执行任何变换操作。我们只是运用,暂时不需要了解后面的原理。

核心的三个矩阵操作的方法

context.transform(a, b, c, d, e, f)、context.setTransform(a, b, c, d, e, f)、context.resetTransform()。

context.transform方法我们前面已经说了,注意这个方法是累积的,就是说他改变的是变换矩阵当前的值,将当前变换矩阵与由其参数描述的矩阵相乘。

context.setTransform将当前变换重置为单位矩阵,然后使用相同的参数调用transform()方法。这基本上撤消当前的转换,然后设置指定的转换。transform是累积,setTransform则不是累积的,setTransform是一步到位。

context.resetTransform 将当前变换重置为单位矩阵。这与调用context.setTransform(1,0,0,1,0,0)是一样的效果。

变换矩阵的操作效果,跟上面具体的相关变换操作方法(translate、rotate、scale)效果一样。

渝ICP备20006974号-2