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点的坐标值可以用如下的等式表示:
x1 = 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轴向下才是正数,所以请换位思考一下)。
如果你会解答这道题,并且能推演一个坐标随角度变化而变化的公式,那么你很对得起你的几何老师,可惜我推不出来,我数学是挂科的!!!所以我就直接把答案搁这儿了:
x1 = x * cos(弧度) - y * sin(弧度);
y1 = y * cos(弧度) + x * sin(弧度);
弧度 = Math.PI * 180 / 角度
-------------------------------------------------------------
最终的公式
x1 = 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);
总结:
- 使用transform完全可以替换原有的三个API并且能够做出更多的效果,比如斜切;
- transform如果既有平移又有旋转,则先平移后旋转(平移和旋转顺序不同,结果不同,我拿着纸画了,确实不同 - -|);
- 如果transform的第二第三个参数中,一个为零一个非零,则会得到斜切;第二个参数拉伸Y轴,第三个X轴
- 旋转效果中,如果第二个为负数,第三个为正数,则旋转方向是逆时针的
- transform的效果可以叠加,setTransform则可以用来将画布归回原位后再进行相应的效果处理;
Canvas transform浅析的更多相关文章
- Html5 Canvas transform setTransform
Html5 Canvas transform就是矩阵变换,一种坐标的变形. 坐标变形的三种方式,平移translate, 缩放scale以及旋转rotate都可以通过transform做到. tran ...
- css3 matrix 2D矩阵和canvas transform 2D矩阵
一看到“2D矩阵”这个高大上的名词,有的同学可能会有种畏惧感,“矩阵”,看起来好高深的样子,我还是看点简单的吧.其实本文就很简单,你只需要有一点点css3 transform的基础就好. 没有前戏,直 ...
- transform你不知道的那些事
transform是诸多css3新特性中最打动我的,因为它让方方正正的box module变得真实了. transform通过一组函数实现了对盒子大小.位置.角度的2D或者3D变换.不过很长时间内,我 ...
- [JavaScript] canvas 合成图片和文字
Canvas Canvas 是 HTML5 新增的组件,就像一个画板,用 js 这杆笔,在上面乱涂乱画 创建一个 canvas <canvas id="stockGraph" ...
- Unity3D学习笔记(二十):Rect、Canvas、Toggle、Slider、ScrollBar
Rect Transform(锚点):图片中心的四个点,界面以雪花形式显示 当四个点在一起的时候组成锚点,当四个点分开的时候组成锚框(合则锚点,分则锚框) Anchors: ----Min x:控 ...
- HTML5 界面元素 Canvas 參考手冊
HTML5 界面元素 Canvas 參考手冊 太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一致"创作公用协 ...
- javascript canvas全部API
HTMLCanvasElement//canvas elem对象 属性 height//高 width//宽 方法 getContext()//获取<canvas>相关的可绘制的上下文 t ...
- Mask裁切UI粒子特效或者3D模型
刚好前几天有人问我这个问题,再加上新项目也可能用,所以这两天就研究了一下.其实如果粒子特效 和3D模型 都用RenderTexture来做的话就不会有裁切的问题,但是粒子特效用RenderTextur ...
- Android 自定义 view(三)—— onDraw 方法理解
前言: 上一篇已经介绍了用自己定义的属性怎么简单定义一个view<Android 自定义view(二) -- attr 使用>,那么接下来我们继续深究自定义view,下一步将要去简单理解自 ...
随机推荐
- myeclipse spket spket-1.6.23.jar 破解安装教程
一年前安装文档就写过了,今天写破解文档,本来开发js/ext是想用aptana的,但是安装包100多M,我还是用spket吧(才11M),这个需要破解一下license,否则用不了. 一 安装教程如下 ...
- 【Java】java的内存浅析
一.闲谈下 201407月记着那时候身体垮了下来,呵呵.想说,对自己的说,也是对大家的负责吧.那时候胸疼胸闷,然后几乎累垮了,我还坚持了一星期,那一星期真的迷迷糊糊.完全不能看代码,看代码就晕.一直想 ...
- 转:我终于离开了年薪30w的IT行业
题目乍看起来有点故意惹人眼球的味道,但是对于我事实就是如此,暂且请君听我细细道来! 先自曝家门,我03年毕业,05年来深,06年买车子,06年底结婚,07年买了房子,09年生了儿子,妻子.房 ...
- iostat 使用说明
LINUX [oracle@perass back]$ iostat -m 1 10 Linux 2.6.18-194.el5 (perass) 03/01/2014 avg-cpu: %user % ...
- 从VC到g++遇到的事
最近做的项目,需要把代码从VC移植到g++下编译,在这个过程中,遇到了几个平台相关的问题--在VC下顺利编译的代码,但在g++中编译报错. 这里贴出来给大家分享一下: 1. 枚举类型 问题代码 enu ...
- 数据结构(括号序列,线段树||点分治,堆):ZJOI 2007 捉迷藏
[题目描述] Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这N- ...
- 黄源河《左偏树的应用》——数字序列(Baltic 2004)
这道题哪里都找不到. [问题描述] 给定一个整数序列a1, a2, … , an,求一个不下降序列b1 ≤ b2 ≤ … ≤ bn,使得数列{ai}和{bi}的各项之差的绝对值之和 |a1 - b1| ...
- c++学习(1)
c++学习(1) 1.const C VS C++: 在c语言中const是一个只读变量(ReadOnly Varible),在c++中const只是代表常量(Constant). 例: const ...
- a为整型数组,&a+1的含义
#include <stdio.h> int main() { int a[10]; printf("a的值为:\t%d\n",a); printf("&am ...
- 《A First Course in Probability》-chaper3-条件概率和独立性-贝叶斯公式、全概率公式
设有事件A.B. 下面结合具体的题目进一步理解这种方法: Q1:保险公司认为人可以分为两类,一类易出事故,另一类则不易出事故.统计表明,一个易出事故者在一年内发生事故的概率是0.4,而对不易出事故者来 ...