Canvas画布进阶篇

HTML5的Canvas中提供了路径旋转、移动、扩大/缩小等变形功能。

1、变形方法

     在制作动画或绘制复杂的图形时,经常会用到两个变形方法transform()以及rotate()。在实际绘制前执行了这些方法后,实际绘制出来的图形中将显示旋转或变形。

变形方法中的旋转/移动相关方法
setTransform(m11,m12,m21,m22,dx,dy)变形矩阵的指定(清空先前的指定)
transform(m11,m12,m21,m22,dx,dy)变形矩阵的指定(可重复指定)
rotate(angle)旋转
scale(x,y)扩大/缩小
translate(x,y)移动/变形

   setTransform()与transform()的区别是,是否对已经设置的变形矩阵进行清空。transform()方法可重复制定不同效果的变形矩阵,而setTransform()方法被调用后将清空原先设置的变形矩阵。另外,提供旋转或扩大/缩小功能的rotate()方法、scale()方法与translate()方法都支持重叠变形矩阵。

变形矩阵的保存/恢复方法
save()记录变形矩阵的状态
restore()恢复变形矩阵的状态

2、移动与扩大/缩小

context.scale(x,y);

参数x为长度缩放的比例,参数y为宽带缩放的比例

context.translate(x,y);

(x,y)为基点移动后的坐标

简单案例:

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>移动translate(x,y)放大/缩小scale(x,y)</title>
</head>

<body>
<canvas id="canvas" width="400" height="300"></canvas>
<script type="text/javascript">
	//取得canvas对象
	var canvas=document.getElementById("canvas");
	//获得描绘的上下文
	var context=canvas.getContext("2d");
	context.fillStyle="#a0a0a0";
	context.fillRect(0,0,400,300);
	//定义绘制矩形的方法
	function drawRect(ctx,color){
		ctx.fillStyle=color;
		ctx.fillRect(20,20,50,50);
	}
	//绘制普通矩形
	drawRect(context,"#cccccc");
	//移动矩形以及扩大/缩小矩形
	//第一种
	//移动后的左上角坐标(x,y)计算
	//x=2*(20+20),y=1*(20+0),width=2*50,height=1*50
	/*
	context.scale(2,1);
	context.translate(20,0);
	drawRect(context,"#c0000c");
	*/
	//第二种
	//移动后的左上角坐标(x,y)计算
	//x=40+2*20,y=0+1*20,width=2*50,height=1*50
	context.translate(40,0);
	context.scale(2,1);
	drawRect(context,"#c0000c");
</script>
</body>
</html>

3、变形的保存与恢复

context.save();//变形的保存
context.restore();//变形的恢复

上述两种方法都是基于同一堆栈(stack)构造,调用save()方法后,将变形结果保存在堆栈顶端,调用restore()方法后,从堆栈顶端取出上次保存的结果用于恢复。

4、旋转

context.rotate(angle);

简单案例:通过移动/旋转等方式,分别绘制三个长方形。结合save()方法、restore()方法,以及rotate()方法。

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>旋转</title>
</head>

<body>
<canvas id="canvas" width="400" height="300"></canvas>
<script type="text/javascript">
	//取得canvas对象
	var canvas=document.getElementById("canvas");
	//获取上下文
	var ctx=canvas.getContext("2d");
	//定义描绘矩阵的函数
	function drawRect(context,color){
		context.fillStyle=color;
		context.fillRect(0,0,100,30);
	}
	//定义旋转函数
	function rotateDeg(context,deg){
		var rad=deg*Math.PI/180;//把“度”换成弧度
		context.rotate(rad);
	}
	//绘制普通的矩形
	drawRect(ctx,"red");
	//指定移动、旋转后绘图
	ctx.save();//保存状态
	ctx.translate(100,30);//移动基点
	rotateDeg(ctx,45);//旋转45度
	drawRect(ctx,"green");
	ctx.restore();//恢复状态
	//指定移动、旋转后绘图
	ctx.save();//保存状态
	ctx.translate(200,50);//移动基点
	rotateDeg(ctx,90);//旋转90度
	drawRect(ctx,"blue");
	ctx.restore();//恢复状态
</script>
</body>
</html>

上述程序中,首先绘制最初的红色长方形,接着,保存矩阵状态后,移动基点并旋转45度绘制新的绿色长方形。绿色长方形绘制结束后,恢复原先的矩阵状态,为绘制下一个长方形做准备。先移动基点,随后旋转90度,绘制蓝色的长方形。

注释掉第一个ctx.save();和ctx.restore();语句试试会发生哪些不同变化。

5、变形矩阵

context.setTransform(m11,m12,m21,m22,dx,dy);

其中的参数可变换为如下的矩阵

m11 m12 dx

m21 m22 dy

0      0      1

(1)、第1个参数m11

        参数m11的默认值为1.0.当此值越大时,以Canvas区域的左侧面为基准,向右延伸坐标空间。相反当值比1.0小时,向左侧收缩坐标空间。m11为0时,实际坐标空间完全消失。但是,当m11的值为比0小的负数时,坐标空间变成以左侧为基准,向左侧延伸。

        另外,在Firefox3.6中,当m11或m22的值比0小时,本来的图像将全被隐藏起来,其后当值重新恢复到0以上的数值时,隐藏的图像也不能恢复。

m11分别为0,0.5,1.0,1.5,2.0时,图像:

       

(2)、第2个参数m12

     参数m12的默认值为0.0,当此值变大时,以canvas区域左侧面为基准,坐标空间向右下方向倾斜。相反当此值比0.0小时,以Canvas区域左侧面为基准,坐标空间向右上方向倾斜。

     m12分别为-1,-0.5,0,0.5,1时,图像:

  

 

(3)、第3个参数m21

       参数m21的默认值为0.0,当此值变大时,以canvas区域的上侧面为基准,坐标空间向右下方向倾斜。相反当此值比0.0小时,以Canvas区域的上侧面为基准,坐标空间向左下方向倾斜。

     m21分别为-1.0,-0.5,0,0.5,1.0时,图像:

 

   

(4)、第4个参数m22

参数m22的默认值为1.0,当此值越大时,以Canvas区域的上侧面为基准,向下延伸坐标空间。相反当值比1.0小时,向上侧收缩坐标空间。m22为0时,实际坐标空间完全消失。但是,当m22的值为比0小的负数时,坐标空间变成以下侧为基准,向上延伸。

当m22的值分别为0,0.5,1.0,1.5,2.0时,图像:

   

   

(5)、第5个参数dx

        参数dx的默认值为0,当此值越大时,Canvas的坐标空间向右移动。相反当此值变成负数时,坐标空间将向左移动。

当dx的值分别为-200,-100,0.0,100,200时,图像:

    

 

(6)、第6个参数dy

      参数dy的默认值为0,当此值越大时,Canvas的坐标空间向下移动。相反当此值变成负数时,坐标空间将向上移动。

当dy的值分别为-200,-100,0.0,100,200时,图像:

   

 

6、实例---旋转图片动画

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>图标旋转效果(IE8不支持)</title>
<script type="text/javascript">
	(function(){
		//不支持window.addEventListener的浏览器不执行代码
		if(!window.addEventListener){return;}
		//定义canvas对象
		var canvas=null;
		//定义上下文对象
		var ctx=null;
		//动画的频率
		var fps=60;
		//图像对象
		var image=null;
		//旋转角度
		var deg=0;
		//页面导入时的事件处理
		window.addEventListener("load",function(){
			//img元素
			image=document.getElementById("logo");
			//图像尺寸
			var w=parseInt(image.width);
			var h=parseInt(image.height);
			//创建canvas对象
			canvas=document.createElement("canvas");
			canvas.width=w;
			canvas.height=h;
			//创建canvas的上下文
			ctx=canvas.getContext("2d");
			//不支持canvas的浏览器返回
			if(!ctx){return;}
			//将图像绘制如canvas中
			ctx.drawImage(image,0,0);
			//用canvas替换img元素
			image.parentNode.replaceChild(canvas,image);
			//canvas的动画开始
			move();
		},false);
		//旋转动画
		function move(){
			//canvas的尺寸
			var cw=parseInt(canvas.width);
			var ch=parseInt(canvas.height);
			//初始化变形矩阵
			ctx.setTransform(1,0,0,1,0,0);
			//清空canvas
			ctx.clearRect(0,0,cw,ch);
			//计算变形矩阵
			var m11=Math.cos(deg*Math.PI/180);
			var dx=(cw/2)-(cw*m11/2);
			//变形矩阵设置
			ctx.setTransform(m11,0,0,1,dx,0);
			//将变形后的图像绘制入canvas中
			ctx.drawImage(image,0,0);
			//旋转角度递增
			deg++;
			deg=deg%360;
			//使用timer定时绘制下一幅图
			setTimeout(move,1000/fps);
		}
	})();
</script>
</head>

<body style="text-align: center;">
<img src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1548325966114&di=cd2d314c7491624d817795fee035b33d&imgtype=0&src=http%3A%2F%2Fwww.51yuansu.com%2Fpic2%2Fcover%2F00%2F48%2F21%2F5815e05f8afe4_610.jpg" id="logo"/>
</body>
</html>

详细解释move()函数 :

ctx.setTransform(1,0,0,1,0,0);//初始化变形矩阵
ctx.clearRect(0,0,cw,ch);//清空canvas

首先将变形矩阵恢复成默认值。便于坐标运算。

//计算变形矩阵
var m11=Math.cos(deg*Math.PI/180);
var dx=(cw/2)-(cw*m11/2);

为了让Canvas坐标平面看起来像在立体的旋转,只需要变动m11与dx即可。

在只变动m11的情况下,将以Canvas 区域的左侧面为基准进行左右伸缩。因此,通过使用dx来进行水平调整,使将向左右伸缩后的图像中心始终在Canvas区域的中心位置。

//变形矩阵设置
ctx.setTransform(m11,0,0,1,dx,0);
//将变形后的图像绘制入canvas中
ctx.drawImage(image,0,0);

将计算出来的数值m11和dx,传入到setTransform()方法中,重新设置变形矩阵。然后调用drawImage()方法重新绘制图像即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值