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则可以用来将画布归回原位后再进行相应的效果处理;
时间: 08-28

Canvas transform浅析的相关文章

css3 matrix 2D矩阵和canvas transform 2D矩阵

一看到“2D矩阵”这个高大上的名词,有的同学可能会有种畏惧感,“矩阵”,看起来好高深的样子,我还是看点简单的吧.其实本文就很简单,你只需要有一点点css3 transform的基础就好. 没有前戏,直奔主题 2D矩阵指的是元素在2D平面内发生诸如缩放.平移.旋转.拉伸四种变化,在css3中对应4个方法分别是scale().translate().rotate()和skew(),可以说这4个方法是css3矩阵matrix的快捷方式,因为这4个方法本质都是由matrix实现的.类似地,在canvas

Html5 Canvas transform setTransform

Html5 Canvas transform就是矩阵变换,一种坐标的变形. 坐标变形的三种方式,平移translate, 缩放scale以及旋转rotate都可以通过transform做到. transform(m11, m12, m21, m22, dx, dy):这个方法必须将当前的变形矩阵乘上下面的矩阵: m11 m21 dx m12 m22 dy 0 0 1 也就是说假设 变化前A(x,y)得到 变换后B(x’,y’)可以通过乘以上述矩阵即可得到: 比如说:缩放scale x”=x*a;

HTML5 canvas transform与矩阵

首先,我们看一下w3school上的例子: Javascript语法:context.transform( a , b , c , d , e , f ); 定义与用法:画布上的每个对象都拥有一个当前的变换矩阵.而transform则是用来定义一个新的矩阵,来替换原来的变换矩阵. 六个参数,对应的矩阵就是: 在这里,我说一下变换矩阵要用到的关于矩阵的知识,一个图形,在画布上无非是移动,缩小放大,还有旋转,斜切,等等. PS告诉我们,无论多复杂的图形,都是由一个个点组成的,变换矩阵要做的,无非是应

C++ transform 浅析

[摘要] transform,一个区间元素交换函数.该函数用于实现容器元素的变换操作.有例如以下两个使用原型,一个将迭代器区间[first.last)中元素.运行一元函数(有一个输入变量)对象op操作.交换后的结果放在[result,result+(last-first))区间中.还有一个将迭代器区间[first1,last1)的元素*i,依次与[first2,first2+(last-first))的元素*j,运行二元函数(有两个输入变量)操作binary_op(*i,*j).交换结果放在[r

transform你不知道的那些事

transform是诸多css3新特性中最打动我的,因为它让方方正正的box module变得真实了. transform通过一组函数实现了对盒子大小.位置.角度的2D或者3D变换.不过很长时间内,我对以下问题都想不太明白: 1.尺寸缩放scale与zoom变换有何不同,为什么被scale的盒子里的内容不会错位,但zoom不是. 2.位移(transform:translate)与相对定位.绝对定位(position:relative | absolute)有何关系? 3.在实际项目中发现,位图

HTML5 界面元素 Canvas 參考手冊

太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:太阳火神的漂亮人生 -  本博客专注于 敏捷开发及移动和物联设备研究:iOS.Android.Html5.Arduino.pcDuino,否则,出自本博客的文章拒绝转载或再转载,谢谢合作. HTML5 界面元素 Canvas 參考手冊HTML Canvas Reference 描写叙述Description The HTML5 <

HTML5 界面元素 Canvas 参考手册

太阳火神的美丽人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:太阳火神的美丽人生 -  本博客专注于 敏捷开发及移动和物联设备研究:iOS.Android.Html5.Arduino.pcDuino,否则,出自本博客的文章拒绝转载或再转载,谢谢合作. HTML5 界面元素 Canvas 参考手册HTML Canvas Reference 描述Description The HTML5 <c

javascript canvas全部API

1 2 HTMLCanvasElement//canvas elem对象 3 属性 4 height//高 5 width//宽 6 方法 7 getContext()//获取<canvas>相关的可绘制的上下文 8 toBlob()//(ie 不支持)此方法可以将<canvas>画布转换为base64格式的图片数据,我们可以通过设定参数指定转换的图片类型,甚至图片的清晰度 9 toDataURL()//可以将<canvas>画布转换为Blob对象 10 11 12 1

UI图像拖动更换

今天做一个拖动图像的demo,效果图如下: 1 拖动的类需要实现 IDropHandler, IPointerEnterHandler, IPointerExitHandler 这三个接口: 2 接受的类需要实现 IBeginDragHandler,IDragHandler,IEndDragHandler 这三个接口: 下面贴代码 Drag.cs using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; //