html5基础入门教程之canvas变型

在了解变形之前,先介绍一下两个在开始绘制复杂图形就必不可少的方法。

save()
restore()

save()和 restore()方法是用来保存和恢复canvas状态的,都没有参数。

Canvas状态是以堆(stack)的方式保存的,每一次调用save()方法,当前的状态就会被推入堆中保存起来。这种状态包括:

  • 当前应用的变形(即移动,旋转和缩放,见下)
  • strokeStyle, fillStyle, globalAlpha, lineWidth, lineCap, lineJoin, miterLimit, shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor, globalCompositeOperation 的值
  • 当前的裁切路径(clipping path)

可以调用任意多次save()方法。

每一次调用restore()方法,上一个保存的状态就从堆中弹出,所有设定都恢复。

看一个save()和restore()方法的例子:

save-restore


                            function draw(){
                                 var canvas=document.getElementById('test_save_restore');
                                 
                                 if(canvas.getContext){
                                    var ctx=canvas.getContext('2d');
                                    
                                    ctx.fillRect(15,15,150,150); //先绘制一个150*150的正方形,默认填充黑色
                                    ctx.save(); //保存当前状态
                                    
                                    ctx.fillStyle='#09f';  //设置填充色为蓝
                                    ctx.fillRect(30,30,120,120);  //绘制一个起始点坐标为(12,12)的120*120的正方形。它的背景色就是之前设置的蓝色。
                                    
                                    ctx.save(); //保存当前状态
                                    
                                    ctx.fillStyle='#fff'; //设置填充色为白色
                                    ctx.globalAlpha=0.5; //透明度设置为0.5
                                    ctx.fillRect(45,45,90,90); //绘制正方形
                                    
                                    ctx.restore(); //恢复栈中的第一个状态值,即最后一个保存的状态,为设置填充色为蓝色
                                    ctx.fillRect(60,60,60,60); //绘制60*60的蓝色正方形
                                    
                                    ctx.restore(); //恢复栈中的第二个值,在本例中即第一个保存的状态,填充色默认为黑色
                                    ctx.fillRect(75,75,30,30); //绘制一个30*30的黑色正方形
                                    
                                 }
                              }

这个例子第一步是绘制了一个起始位置坐标为(15,15),大小为150*150的正方形。它没有设置填充色,默认填充了黑色。第二步调用了save()方法。该方法记录了这是的状态,即fillStyle的值,即为默认的黑色。第三步设置fillStyle值为'#09f',以此为填充色绘制了一个起始位置坐标为(30,30),大小为120*120的正方形。第四步又调用了一次save()方法,此时的状态也将被推入状态栈中,即保存了填充色'#09f'。第五步绘制了一个起始坐标为(45,45)、背景色为白色、透明度为0.5、大小为90*90的正方形。第六步调用restore()方法,恢复最后一次保存的状态,绘制了一个蓝色正方形,它的起始位置为(60,60),大小为60*60。最后又调用了一次restore()方法,恢复第一次保存的状态,绘制了一个黑色正方形,它的起始位置为(75,75),大小为30*30.

移动

在canvas中用于移动的方法是translate()方法,该方法用来移动canvas和它的原点到一个不同的位置。

translate(x,y);

该方法有两个参数,分别x方向和y方向的偏移量。

看一个translate()方法的例子:

translate


                            function draw(){
                                 var canvas=document.getElementById('test_translate');
                                 
                                 if(canvas.getContext){
                                    var ctx=canvas.getContext('2d');
                                    ctx.fillRect(10,10,100,50);
                                    ctx.translate(70,70);
                                    ctx.fillRect(10,10,100,50);
                                 }
                              }

上面的例子先是绘制了一个100*50的矩形,它的原点位置是(10,10)。然后用translate()方法将其原点移至(70,70)。接着又绘制了一个100*50的矩形,它距离原点的位置是(10,10),所以,第二个矩形开始绘制的位置就应该是(80,80);

旋转

rotate()方法用以实现以原点为中心的旋转。

rotate(angle);

该方法只接受一个参数,表示要旋转的角度,以弧度为单位。如果传入的参数是正数,则表示顺时针旋转;如果是负数,则表示逆时针旋转。

默认情况下,旋转的中心始终是原点(0,0),如果想改变旋转的中心,则必须使用translate()将原点移动到指定的位置,再进行旋转。

来看一个rotate()方法的例子:


                            function draw(){
                                 var canvas=document.getElementById('test_rotate');
                                 
                                 if(canvas.getContext){
                                    var ctx=canvas.getContext('2d');
                                    ctx.fillRect(150,50,50,50);
                                    ctx.rotate(Math.PI/6);
                                    ctx.fillRect(150,50,50,50);
                                 }
                              }

这个例子,在画布没旋转之前,先绘制了一个距离原点位置为(150,50)、大小为50*50的正方形。然后旋转画布30°即Matb.PI/6,再绘制一个一样的正方形。从上图中可以看到两者的区别。注意,这里的原点是(0,0)。

缩放

scale()方法用于实现画布的缩放。

scale(x,y);

该方法接受两个参数,分别表示x方向和y方向缩放的比例。它们必须都是正值。值小于1,表示缩小;值大于1,表示放大;值等于1时,表示没有缩放。

来看一个scale()方法的例子:


                            function draw(){
                                 var canvas=document.getElementById('test_scale');
                                 
                                 if(canvas.getContext){
                                    var ctx=canvas.getContext('2d');
                                    ctx.fillRect(10,10,50,50);
                                    ctx.scale(0.5,1.5);
                                    ctx.fillRect(150,10,50,50);
                                 }
                              }

上面的例子显示绘制了一个距离原点(10,10)、大小50*50的正方形。然后进行缩放操作,将x方向缩小,y方向放大。然后再在离原点(75,15)(这里坐标已经做了缩放,150*0.5=75,10*1.5=15)的位置绘制一个25*75(50*0.5=25,50*1.5=75)的矩形。二者进行对比,就可以看出scale()是怎样变化的了。

变形

最后一个方法是变形。

transform(m11,m12,m21,m22,dx,dy);

画布上每个对象都有一个当前的变换矩阵。

调用transform()方法必须将当前的变换矩阵乘以传入的变换矩阵,对上面介绍的参数而言,传入的变形矩阵是这样的:

其中,m11表示水平缩放绘制;m12表示水平倾斜绘制;m21表示垂直倾斜绘制;m22表示垂直缩放绘制;dx表示水平移动绘制;dy表示垂直移动绘制。

换句话说,transform允许缩放、移动、旋转、倾斜当前环境。其实transform就是这几种的组合变换。当然,我们可以把这transform拆分上述三种变换,对应的矩阵计算公式如下:

还有一点需要注意,改变换只会影响调用transform()方法之后所绘制的图形。

来看一个例子:

transform


                            function draw(){
                                 var canvas=document.getElementById('test_transform');
                                 
                                 if(canvas.getContext){
                                    var ctx=canvas.getContext('2d');
                                    ctx.fillStyle="yellow";
                                    ctx.fillRect(100,100,250,100);
                                    
                                    ctx.transform(1,0.2,-0.2,1,30,10);
                                    ctx.fillStyle="red";
                                    ctx.fillRect(100,100,250,100);
                                    
                                    ctx.transform(1,0.2,-0.2,1,30,10);
                                    ctx.fillStyle="blue";
                                    ctx.fillRect(100,100,250,100);
                                    
                                 }
                              }

针对上面的这个例子,我们来分析一下图形的绘制过程。首先,画布上绘制了一个250*100的黄色矩形。然后为下一个同样大小同样位置的红色矩形做了变形。我们根据transform()各参数可以得出以下矩阵:

然后对应各参数的含义,我们可以得知,红色矩形没有进行缩放,但是进行了旋转和移动。那么我们将这两个过程分成两步来分析,便于理解。我们将上面得到的矩阵中的dx和dy的值置0,即把30和10变成0就得到了下面矩阵:

那么我们怎么计算图形旋转的角度呢?上面的矩阵其实和下面的矩阵是对应的:

根据上面的矩阵对应关系,很容易算出旋转的角度大约为10度。如下图所示:

接着我们把原来的矩阵变为下面这个矩阵:

根据上面的矩阵我们可以计算移动的坐标值,红色矩形左上定点移动后的坐标为:x'=100+30=130,y'=100+10=110,那么移动的距离就是很像右移了30px,纵向下移了10px。所以其实就是矩阵中的那两个值,即:30和10。

新建一个前端学习qun438905713,在群里大多数都是零基础学习者,大家相互帮助,相互解答,并且还准备很多学习资料,欢迎零基础的小伙伴来一起交流。

然后,蓝色矩形的绘制过程同上,但是它是在红色矩形变形的基础上再进行变形的。最终得到的图案就是下图:

! 注意:每次调用transform()时,都会再前一个变换的基础上再构建。

发布了69 篇原创文章 · 获赞 33 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/webxuexi168/article/details/104365076