HTML5 canvas变换

简介:

在上一篇博客中,我们介绍了canvas对图片的操作,在这一里我们将继续介绍canvas的变换方法,这些方法很类似于CSS,如果你对CSS比较了解,那么这些方法将十分轻松:旋转rotate,缩放scale,移动translate,矩阵变换transform,下面我们将介绍这些方法:

1.状态的保存和恢复save() 和restore()

状态

绘制复杂图形时涉及到状态的保存和恢复,在canvas中一个绘画状态是指:

  • 当前应用的变形(移动,旋转和缩放)
  • 填充,轮廓和线型:strokeStyle, fillStyle, globalAlpha, lineWidth, lineCap, lineJoin, miterLimit,
  • 阴影:shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor,
  • globalCompositeOperation 的值
  • 当前的裁切路径(clipping path)
    Canvas 的状态就是当前画面应用的所有样式和变形的一个快照。

save保存和restore恢复

  • save():保存画布(canvas)的所有状态
  • restore():恢复画布的状态

注意
(1)save 和 restore 方法是用来保存和恢复 canvas 状态的,都没有参数。
(2)Canvas状态存储在栈中,每当save()方法被调用后,当前的状态就被推送到栈中保存。
(3)调用 restore,状态栈中栈顶会弹出,并恢复至新的栈顶状态。

举例:

设置三种颜色,分别save和restore入栈退栈

function draw() 
{
	var canvas=document.getElementById("canvas");
	if(canvas.getContext)
	{
		var ctx=canvas.getContext('2d');
		var color=["green","blue","orange"];
		for(var i=0;i<3;i++)
		{
			ctx.save();//保存当前状态入栈
			ctx.fillStyle=color[i];
			ctx.fillRect(20,50*i,200,50);
		}

		for(var i=0;i<3;i++)
		{
			ctx.restore();//弹出栈顶元素,使用下一个栈顶元素
			ctx.fillRect(20,150+50*i,200,50);
		}

	}
}

在这里插入图片描述

translate(x,y)平移

  • translate(x,y)方法接受两个参数。x 是左右偏移量,y 是上下偏移量,它用来移动 canvas 和它的原点到一个不同的位置,这个偏移量是相对于当前的原点来说的。
  • 在做变形之前 先保存状态是一个良好的习惯。大多数情况下,调用 restore 方法比手动恢复原先的状态要简单得多。又,如果你是在一个循环中做位移但没有保存和恢复 canvas 的状态,很可能到最后会发现怎么有些东西不见了,那是因为它很可能已经超出 canvas 范围以外了。
  • translate 方法同时让我们可以任意放置这些图案,而不需要在 fillRect() 方法中手工调整坐标值,既好理解也方便使用。
  • translate方法要和CSS3中的translateX,translateY…区分开来

举例:

function draw() {
  var ctx = document.getElementById('canvas').getContext('2d');
  for(var i=0;i<4;i++)
  {
  	for(var j=0;j<3;j++)
  	{
  		ctx.save();//保存
  		ctx.fillStyle="rgb("+50*i+",255,0)";
  		ctx.translate(10+i*50,10+j*50);
  		ctx.fillRect(0,0,25,25);
  		ctx.restore();//清除
  	}
  }
}

translate 方法同时让我们可以任意放置这些图案,而不需要在 fillRect() 方法中手工调整坐标值,既好理解也方便使用。
在这里插入图片描述

3.旋转rotate(deg)

  • 旋转rotate(deg)方法: 我们可以给绘制好的路径图形设置旋转,默认是顺时针方向,单位是弧度Math.PI/180,旋转的相对中心是当前canvas的原点,我们可以用translate方法来设置原点.

举例:

function draw() {
  var ctx = document.getElementById('canvas').getContext('2d');
  ctx.translate(100,100);
  for(var i=0;i<5;i++)
  {
  	ctx.save();
  	ctx.fillStyle="rgb("+51*i+","+(255-51*i)+",255)";
  	for(var j=0;j<6*i+1;j++)
  	{
  		ctx.rotate(Math.PI/(3*i));
  		ctx.beginPath();
  		ctx.arc(0,12.5*i,5,0,Math.PI*2,true);
  		ctx.fill();
  	}
  	ctx.restore();//清除
  }
}

在这里插入图片描述

3.缩放 Scale(x,y)

  • 缩放scale(x,y) :给图形设置横向和纵向的缩放,我们用它来增减图形在 canvas 中的像素数目,对形状,位图进行缩小或者放大。

  • scale 方法可以缩放画布的水平和垂直的单位。两个参数都是实数,可以为负数,x 为水平缩放因子,y 为垂直缩放因子,如果比1小,会比缩放图形, 如果比1大会放大图形。默认值为1, 为实际大小。

  • 镜像翻转:如果参数为负实数, 相当于以x 或 y轴作为对称轴镜像反转(例如, 使用translate(0,canvas.height); scale(1,-1); 以y轴作为对称轴镜像反转, 就可得到著名的笛卡尔坐标系,左下角为原点)。

  • 注意:放缩是相对于现有原点坐标的线性等比例放大或缩小,比如说如下的图形将是完全相等的

  ctx.fillRect(10, 30, 100, 30);//未放缩
  ctx.scale(10, 3);
  ctx.fillRect(1, 10, 10, 10);

举例:

function draw() {
  var ctx = document.getElementById('canvas').getContext('2d');

  // draw a simple rectangle, but scale it.
  ctx.save();
  ctx.fillStyle="rgba(51,200,255,0.2)";
  ctx.scale(10, 3);
  ctx.fillRect(1, 10, 10, 10);
  ctx.restore();

  // mirror horizontally
  ctx.font = '48px serif';
  ctx.fillText('Hello', 10, 120);
  
  ctx.scale(-1, 1);
  ctx.fillText('Hello',-135, 180);
}

在这里插入图片描述

4.矩阵变换transform:

transform方法

实际上上面提供的rotate旋转,scale放缩以及translate平移都能用一个变形矩阵来进行变换。只要我们操纵这个变形矩阵,就能进行变换,transform方法提供了这样的操作方法。将当前的变形矩阵乘上一个基于自身参数的矩阵,在这里我们用下面的矩阵描述:

m11 m21 dx
m12 m22 dy
0 	0 	1

如果任意一个参数是无限大,变形矩阵也必须被标记为无限大,否则会抛出异常。
参数如下:

  • m11:水平方向的缩放
  • m12:水平方向的倾斜偏移
  • m21:竖直方向的倾斜偏移
  • m22:竖直方向的缩放
  • dx:水平方向的移动
  • dy:竖直方向的移动

setTransform(m11, m12, m21, m22, dx, dy)方法

将当前的变形矩阵重置为单位矩阵,然后用相同的参数调用 transform 方法。如果任意一个参数是无限大,那么变形矩阵也必须被标记为无限大,否则会抛出异常。从根本上来说,该方法是取消了当前变形,然后设置为指定的变形,一步完成。

resetTransform()方法

重置当前矩阵为单位矩阵,等价于:

ctx.setTransform
ctx.setTransform(1,0,0,1,0,0);

举例:

function draw() {
  var ctx = document.getElementById('canvas').getContext('2d');

  var sin = Math.sin(Math.PI/6);
  var cos = Math.cos(Math.PI/6);
  ctx.translate(100, 100);
  var c = 0;
  for (var i=0; i <= 12; i++) {
    c = Math.floor(255 / 12 * i);
    ctx.fillStyle = "rgb(" + c + "," + c + "," + c + ")";
    ctx.fillRect(0, 0, 100, 10);
    ctx.transform(cos, sin, -sin, cos, 0, 0);
  }
  
  ctx.setTransform(-1, 0, 0, 1, 100, 100);
  ctx.fillStyle = "rgba(255, 128, 255, 0.5)";
  ctx.fillRect(0, 50, 100, 100);
}

在这里插入图片描述

发布了119 篇原创文章 · 获赞 133 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_44307065/article/details/104098906