zoukankan      html  css  js  c++  java
  • Canvas transform浅析

    没有前奏,直接进入主题


    transform调用方法:

    ctx.transform(a,b,c,d,e,f);如下

    var ctx = document.getElementById("myCanvas").getContext("2d");
    
    //调用
    ctx.transform(1,1,-1,1,1,1);
    
    //画个圆形的路径
    ctx.arc(200,100,25,0,2*Math.PI);
    
    //画个已填充的矩形
    ctx.fillRect(200,150,50,50);
    
    //对路径描边
    ctx.stroke();

    结果如下(只截取了主要部分):

     使用transform前                       使用transform后

    咋一看,三个变化:

      ①两个图形的位置变化了  

      ②矩形的角度变化了  

      ③图形的大小变化

    这里正好反应了三个属性:位移旋转缩放,对应canvas的另外三个API则是translate()、rotate()、scale()。这三个API使用起来直观,但是却不能实现某些特定的效果,比如斜切

    var canvas = document.getElementById("myCanvas");
    
    var ctx = canvas.getContext("2d");
    
    //Y轴逐渐拉伸,得到上图右边状态
    ctx.transform(1,Math.PI/18,0,1,0,0);
    
    ctx.fillRect(200,150,50,50);

    仅通过原有的三个比较直观的API并不能实现这个效果,然而或许你在别的地方看过,transform除了可以实现斜切,也可以直接替代掉原有的三个API实现它们对应的效果。

    (一)位移

    用transform来替代就是修改最后两个参数: ctx.transform(a,b,c,d,e,f) 其中的e和f两个参数。

    (二)旋转

    旋转呢,就需要配合四个参数来实现了,ctx.transform(a,b,c,d,e,f)其中的abcd四个参数(为什么要四个?先别急,后面再说,总之你记住就好了)。

    (三)缩放

    缩放仅需要修改前两个参数即可,ctx.transform(a,b,c,d,e,f);

    --------------------------------------

    请记住三种情况对应的相关参数

    --------------------------------------

    接下来咱们说说为什么?

    先说简单的:位移和缩放

    对于坐标轴上的任意一点 A(x,y)移动到B(x1,y1),则B点的坐标值可以用如下的等式表示:

    x1 = x + e

    y1 = y + f

    同理,对于坐标轴上的任意一点 A(x,y)缩放到B(x1,y1),则B点的坐标值可以用如下的等式表示:

    x= x * a

    y1 = y * d

    其中a、d对应transform中的第一和第四个参数,位移的时候e和f代表具体的数值,而缩放的时候a和d则代表了对应x或者h轴上的缩放倍数,所以默认的倍数当然是1(也就是原来的大小),默认的位移当然是0,所以我们现在知道transform(a,b,c,d,e,f)的参数中a,d为1,e,f为0。

    接下来看比较复杂的旋转,如图:

    以点(0,0)为中心,将点A(100,-100)旋转45°后求点B的坐标轴是多少?(因为在我们的Canvas中y轴向下才是正数,所以请换位思考一下)。

    如果你会解答这道题,并且能推演一个坐标随角度变化而变化的公式,那么你很对得起你的几何老师,可惜我推不出来,我数学是挂科的!!!所以我就直接把答案搁这儿了:

    x = x * cos(弧度)  -  y * sin(弧度);

    y = y * cos(弧度)  +  x * sin(弧度); 

    弧度 = Math.PI * 180 / 角度

    -------------------------------------------------------------

    最终的公式

    x= ax + cy + e

    y1 = bx + dy + f

    调用:

    ctx.transform(cos(弧度),sin(弧度),-sin(弧度),cos(弧度),0,0);

    var canvas = document.getElementById("myCanvas");
    
    var ctx = canvas.getContext("2d");
    
    var deg = Math.PI/180;
    
    //旋转45°
    ctx.transform(Math.cos(deg*45),Math.sin(deg*45),-Math.sin(deg*45),Math.cos(deg*45),0,0);
    
    ctx.fillRect(200,0,50,50);

    如果我要旋转45°并且放大两倍,位移到(100,100)呢?我并没有在别的地方找到答案。我以为a和d既然是控制缩放的,那么乘以2如何?

    var canvas = document.getElementById("myCanvas");
    
    var ctx = canvas.getContext("2d");
    
    var deg = Math.PI/180;
    
    ctx.fillRect(200,0,50,50);  //第一个正方形(未变形)
    
    
    ctx.setTransform(1,0,0,1,0,0);
    ctx.beginPath();
    ctx.transform(2*Math.cos(deg*45),Math.sin(deg*45),-Math.sin(deg*45),2*Math.cos(deg*45),0,0);
    
    ctx.fillRect(200,0,50,50);   //第二个正方形(仅a和d乘以2)
    
    ctx.setTransform(1,0,0,1,0,0);
    ctx.beginPath();
    ctx.transform(2*Math.cos(deg*45),2*Math.sin(deg*45),-2*Math.sin(deg*45),2*Math.cos(deg*45),0,0);
    
    ctx.fillRect(200,0,50,50);  //第三个正方形(正确的解答)

    你没看错,abcd四个参数全部乘以2才是正确的(对于数学不太好的我,花了四五个小时也想不通,最后斗胆一试全部乘以2居然神奇的正确了O(∩_∩)O~~)

    与下面两种方法得到相同的结果:

    //第一:直接使用缩放和旋转的API
    ctx.scale(2,2);
    ctx.rotate(Math.PI/180*45);
    
    
    //第二:使用transform分别替换上面两种API
    var deg = Math.PI/180;
    ctx.transform(2,0,0,2,0,0);
    ctx.transform(Math.cos(45*deg),Math.sin(45*deg),-Math.sin(45*deg),Math.cos(45*deg),100,100);

    总结:

    1. 使用transform完全可以替换原有的三个API并且能够做出更多的效果,比如斜切;
    2. transform如果既有平移又有旋转,则先平移后旋转(平移和旋转顺序不同,结果不同,我拿着纸画了,确实不同 - -|);
    3. 如果transform的第二第三个参数中,一个为零一个非零,则会得到斜切;第二个参数拉伸Y轴,第三个X轴
    4. 旋转效果中,如果第二个为负数,第三个为正数,则旋转方向是逆时针的
    5. transform的效果可以叠加,setTransform则可以用来将画布归回原位后再进行相应的效果处理;
  • 相关阅读:
    使用java.util.LinkedList模拟实现内存页面置换算法--LRU算法
    JMS学习(八)-ActiveMQ Consumer 使用 push 还是 pull 获取消息
    判断二叉树是否是平衡二叉树 及二叉树各种操作汇总
    二叉树的前序、中序、后序的非递归遍历实现
    排列与组合的一些定理(二)
    找出数字在已排序数组中出现的次数
    SRM 212 Div II Level Two: WinningRecord,Brute Force
    覆写Activity的finish()方法
    POJ 2046 Gap 搜索- 状态压缩
    WebView利用UserAgent传递SESSIONID
  • 原文地址:https://www.cnblogs.com/gradolabs/p/4766811.html
Copyright © 2011-2022 走看看