Canvas系列(7):形变
CSS3中有一个很重要的点,就是形变。他分为移动,缩放、旋转和倾斜。在Canvas中,形变都是基于坐标做的,所以,并没有直接的API支持倾斜,其它几种都是有独立的API来支持,命名和CSS是一样的。今天我们就看一下这几种吧。
平移
平移是最简单的一种形变,我们直接来看一个例子吧:
context.fillRect(10,10,20,20);
// x平移20px y平移20px
context.translate(20, 20);
context.fillRect(10,10,20,20);
context.translate(20, 20);
context.fillRect(10,10,20,20);
效果:
通过上面我们可以看到,平移(形变)移动的是坐标系,移动以后会以新的坐标系进行绘图,当多次平移(形变)以后每次都会以上一次的坐标系为准。此时你可能会问,那形变不是很危险吗,每次使用了形变就会使用新的坐标系,以后所有绘制的图片都会受到影响?没错是这样的,那改怎么解决呢?还记得之前的状态吗?现在给一个简单的例子:
// 形变前往往需要保存状态
context.save();
context.translate(20, 20);
context.fillRect(10,10,20,20);
// 形变结束,恢复之前的状态
context.restore();
// 此时以之前的坐标系绘制
context.beginPath();
context.fillStyle='red';
context.fillRect(10,10,20,20);
效果:
缩放
缩放也是相对于坐标系来说的,看一下这个例子:
context.strokeStyle='red';
context.lineWidth=10;
context.strokeRect(20, 20, 50, 50);
context.beginPath();
// x是原来的1.5倍 y是原来的1.5倍
context.save();
context.scale(1.5, 1.5);
context.strokeStyle='blue';
context.strokeRect(20, 20, 50, 50);
context.restore();
效果:
可以看到,缩放改变的也是坐标系,在新的坐标系系中,宽度也放大了,一个像素已经不再是真正的一个像素了,而是放大以后的大小。所以可以看到都是10个像素的边框,宽度也不一样了。需要注意的是缩放的值大于1的时候是放大,0~1之间是缩小,1和原来是一样大的。
旋转
直接上代码:
context.strokeStyle='red';
context.lineWidth=10;
context.strokeRect(80, 20, 50, 50);
context.beginPath();
// x是原来的1.5倍 y是原来的1.5倍
context.save();
context.rotate(Math.PI / 180 * 45);
context.strokeStyle='blue';
context.strokeRect(80, 20, 50, 50);
context.restore();
效果:
可以看到旋转是基于坐标的原点的,如果不希望按照原点旋转的话,可以先平移再旋转。另外旋转也是根据弧度来旋转的而不是角度。
矩阵变换
矩阵变换使用的API是context.transform(a, b, c, d, e, f);
,所对应的矩阵的位置是下面这个样子:
什么,看不懂?前方高能!!!多年前欠下的线性代数债,现在要还了。
上面矩阵是平移时候的矩阵,将中间的矩阵带入矩阵的API有:context.transform(1, 0, 0, 1, e, f);
。也就是说context.translate(e, f);
等价于context.transform(1, 0, 0, 1, e, f);
。
也就是说context.scale(a, d);
等价于context.transform(a, 0, 0, d, 0, 0);
。
也就是说context.rotate(angle);
等价于context.transform(cos(angle), sin(angle), -sin(angle), cos(angle), 0, 0);
。
所以我们上面的几个例子,我们做下面的等价替换,效果是一样的:
context.translate(20, 20);
// 等价于
context.transform(1, 0, 0, 1, 20, 20);
context.scale(1.5, 1.5);
// 等价于
context.transform(1.5, 0, 0, 1.5, 0, 0);
context.rotate(Math.PI / 180 * 45);
// 等价于
var theta = Math.PI / 180 * 45;
context.transform(Math.cos(theta), Math.sin(theta), - Math.sin(theta), Math.cos(theta), 0, 0);
除了transform
外还有一个矩阵变换的方法叫setTransform
,参数是一模一样的context.setTransform(a, b, c, d, e, f);
。两者的区别是后者始终以最初的坐标做为参照,而transform
以上次变换后的坐标做为参照(类似于前面的三个API)。
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法