canvas之图形的变化(平移,缩放,旋转)

版权所有,禁止匿名转载;禁止商业使用。

1、保存与恢复canvas状态


ctx.save();暂时将当前的状态保存到堆中


ctx.restore();该方法用于将上一个保存的状态从堆中再次取出,恢复该状态的所有设置。


<!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8">
 <title></title>
 <style type="text/css">
 *{padding: 0;margin:0;}
 body{background: #1b1b1b;}
 #div1{margin:50px auto; width:300px; height: 300px;}
 canvas{background: #fff;}
 </style>
 <script type="text/javascript">
 window.onload = function(){
     var c = document.getElementById('myCanvas');
     var context = c.getContext('2d');
     
     //开始绘制矩形
     context.fillStyle = '#f0f';
     context.strokeStyle = 'blue';
     context.fillRect(20,20,100,100);
     context.strokeRect(20,20,100,100);
     context.fill();
     context.stroke();
     
     //保存当前canvas状态
     context.save();    
     
     //绘制另外一个矩形
     context.fillStyle = '#f00';
     context.strokeStyle = 'green';
     context.fillRect(140,20,100,100);
     context.strokeRect(140,20,100,100);
     context.fill();
     context.stroke();
     
     //恢复第一个矩形的状态
     context.restore();
     
     //绘制两个矩形
     context.fillRect(20,140,50,50);
     context.strokeRect(80,140,50,50);
     
 };
 </script>
 </head>
 <body>
     <div id="div1">
         <canvas id="myCanvas" width="300" height="200"></canvas>
     </div>
 </body>
 </html>

效果展示:

uyaQr2.png 

2、移动坐标空间


context.translate(dx,dy);dx,dy分别表示坐标原点沿水平和垂直两个方向的偏移量。(在图形变换之前,最好使用 save() 方法保存当前状态的好习惯。使用 restore() 方法恢复原来的状态)。


<!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8">
 <title></title>
 <style type="text/css">
 *{padding: 0;margin:0;}
 body{background: #1b1b1b;}
 #div1{margin:50px auto; width:300px; height: 300px;}
 canvas{background: #fff;}
 </style>
 <script type="text/javascript">
 window.onload = function(){
     draw();    
 };
 function drawTop(ctx,fillStyle){
     ctx.fillStyle = fillStyle;
     ctx.beginPath();
     ctx.arc(0,0,30,0,Math.PI,true);
     ctx.closePath();
     ctx.fill();
 }
 
 function drawGrip(ctx){
     ctx.save();
     ctx.fillStyle = 'blue';
     ctx.fillRect(-1.5,0,1.5,40);
     ctx.beginPath();
     ctx.arc(-5,40,4,Math.PI,Math.PI*2,true);
     ctx.stroke();
     ctx.closePath();
     ctx.restore();
 }
 
 function draw(){
     
     var ctx = document.getElementById('myCanvas').getContext('2d');
     ctx.translate(80,80);
     
     for(var i=0; i<10; i++){
         ctx.save();
         ctx.translate(60*i,0);
         drawTop(ctx,'rgb('+(30*i)+','+(255-30*i)+',255)');
         drawGrip(ctx);
         ctx.restore();
     }
     
 }
 </script>
 </head>
 <body>
     <div id="div1">
         <canvas id="myCanvas" width="700" height="300"></canvas>
     </div>
 </body>
 </html>

效果展示: ryY7bm.png

3、旋转坐标空间


context.rotate(angle);  该方法只有一个参数 旋转角度angle,旋转角度以 顺时针方向为正方向 ,以 弧度为单位 ,旋转 中心为canvas的原点 。


 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8">
 <title></title>
 <style type="text/css">
 *{padding: 0;margin:0;}
 body{background: #1b1b1b;}
 #div1{margin:50px auto; width:300px; height: 300px;}
 canvas{background: #fff;}
 </style>
 <script type="text/javascript">
 window.onload = function(){
     draw();    
 };
 function drawTop(ctx,fillStyle){
     ctx.fillStyle = fillStyle;
     ctx.beginPath();
     ctx.arc(0,0,30,0,Math.PI,true);
     ctx.closePath();
     ctx.fill();
 }
 function drawGrip(ctx){
     ctx.save();
     ctx.fillStyle = 'blue';
     ctx.fillRect(-1.5,0,1.5,40);
     ctx.beginPath();
     ctx.strokeStyle = 'blue';
     ctx.arc(-5,40,4,Math.PI,Math.PI*2,true);
     ctx.stroke();
     ctx.closePath();
     ctx.restore();
 }
 function draw(){
     var c = document.getElementById('myCanvas');
     var ctx = c.getContext('2d');
     ctx.translate(150,150);
     
     for(var i=0; i<8; i++){
         ctx.save();
         ctx.rotate(Math.PI*(2/4+i/4));
         ctx.translate(0,-100);
         drawTop(ctx,'rgb('+(30*i)+','+(255-30*i)+',255)');
         drawGrip(ctx);
         ctx.restore();
     }
 }
 </script>
 </head>
 <body>
     <div id="div1">
         <canvas id="myCanvas" width="300" height="300"></canvas>
     </div>
 </body>
 </html>

效果展示:3mIRram.png 

4、缩放图形


ctx.scale(x,y); 其中x为x轴的缩放,y为y轴的缩放,如果要缩小,值为小于1的数值,如果要放大,值为大于1的数值。


<!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8">
 <title></title>
 <style type="text/css">
 *{padding: 0;margin:0;}
 body{background: #1b1b1b;}
 #div1{margin:50px auto; width:300px; height: 300px;}
 canvas{background: #fff;}
 </style>
 <script type="text/javascript">
 window.onload = function(){
     draw();    
 };
 
 function draw(){
     var c = document.getElementById('myCanvas');
     var ctx = c.getContext('2d');
     ctx.translate(180,20);
     
     for(var i=0; i<80; i++){
         ctx.save();
         ctx.translate(30,30);
         ctx.scale(0.95,0.95);
         ctx.rotate(Math.PI/12);
         ctx.beginPath();
         ctx.fillStyle = 'red';
         ctx.globalAlpha = '0.4';
         ctx.arc(0,0,50,0,Math.PI*2,true);
         ctx.closePath();
         ctx.fill();
     }
 }
 </script>
 </head>
 <body>
     <div id="div1">
         <canvas id="myCanvas" width="300" height="300"></canvas>
     </div>
 </body>
 </html>

效果展示:m6NVvuB.png 

5、矩阵变换


transform方法用于直接对变形矩阵作修改,即进行矩阵变形。


context.transform(m11,m12,m21,m22,dx,dy);    该方法必须将当前的变换矩阵与下面的矩阵进行乘法运算。


即:


m11(默认为1) m21(默认为0) dx

m12(默认为0) m22(默认为1) dy

0 0 1

也就是说假设A(x,y)要变换成B(x’,y’)可以通过乘以上述矩阵即可得到。


一:平移(translate), translate可以用下面的方法替代


EN3Yna.png

如上图所示:

jEfm2m.png

x’=x+dx


y’=y+dy


即: 

其中dx为原点沿着x轴移动的数值,y为原点沿着y轴移动的数值。


context.translate(x,y)可以用下面的transform方法来替代:


context.transform(0,1,1,0,dx,dy); 或 context.transform(1,0,0,1,dx,dy);


二、缩放:  scale(x,y) 


x’=m11*x


y’=m22*y



x'=m12*x


y'=m21*y


(其中,m11、m22 和m12、m21分别表示在x轴和y轴上的缩放倍数)


则:scale(x,y); 可以通过下面的transform发放来替代:


context.transform(m11,0,0,m22,0,0);  或 context.transform(0,m12,m21,0,0,0);


三、旋转: rotate(angle);

RnIbmmf.png

 


可以用下面的transform方法来替代:


context.transform(cosΘ,sin Θ,-sin Θ,cos Θ,0,0 );


其中 Θ为旋转的角度,dx,dy都为0表示坐标原点不变。


如图:x' = x*cosΘ - y*sinΘ


y' = x*sinΘ + y*cosΘ


也即是 

3Qzi6je.jpg

则:


context.transform(Math.cos(θ*Math.PI/180),Math.sin(θ*Math.PI/180),
-Math.sin(θ*Math.PI/180),Math.cos(θ*Math.PI/180),0,0)可以替代context.rotate(θ)。


也可以使用


context.transform(-Math.sin(θ*Math.PI/180),Math.cos(θ*Math.PI/180),
Math.cos(θ*Math.PI/180),Math.sin(θ*Math.PI/180), 0,0)替代。
eg:context.transform(0.95,0,0,0.95,30,30); 可以替代 context.translate(30,30); context.scale(0.95.0.95);

setTransform方法用于将当前的变化矩阵 重置 为最初的矩阵,然后以相同的参数调用transform方法,即先set(重置),再transform(变换)


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


<!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8">
 <title></title>
 <style type="text/css">
 *{padding: 0;margin:0;}
 body{background: #1b1b1b;}
 #div1{margin:50px auto; width:300px; height: 300px;}
 canvas{background: #fff;}
 </style>
 <script type="text/javascript">
 window.onload = function(){
     draw();    
 };
 
 function draw(){
     var c = document.getElementById('myCanvas');
     var ctx = c.getContext('2d');
     ctx.translate(200,20);
     
     for(var i=0; i<80; i++){
         ctx.save();
         ctx.transform(0.95,0,0,0.95,30,30);
         ctx.rotate(Math.PI/12);
         ctx.beginPath();
         ctx.fillStyle = 'red';
         ctx.globalAlpha = '0.4';
         ctx.arc(0,0,50,0,Math.PI*2,true);
         ctx.closePath();
         ctx.fill();
     }
     
     ctx.setTransform(1,0,0,1,10,10);    //将前面的矩阵恢复为最初的矩阵,即恢复最初的原点,然后将坐标原点改为(10,10),并以新的坐标绘制一个蓝色的矩形
     ctx.fillStyle = 'blue';
     ctx.fillRect(0,0,50,50);
     ctx.fill();
     
 }
 </script>
 </head>
 <body>
     <div id="div1">
         <canvas id="myCanvas" width="700" height="300"></canvas>
     </div>
 </body>
 </html>

效果显示: 

NRvyEj.png

0 0