本章摘要
在图形开发中,Canvas变形操作是关键技艺。本章深入Canvas 2D API,介绍平移、旋转、缩放及矩阵变换,让图形设计生动起来。通过translate()、rotate()、scale()等方法精确控制画布,绘制动态图形。理解矩阵变换概念,实现倾斜、翻转等复杂效果,为图形开发增添无限可能。掌握这些技术,动画、游戏、数据可视化等项目将更得心应手。
第七章 变形操作
在本系列教程的基础篇概述中讲述了画布的坐标系统 :“画布中默认被网格所覆盖,通常来说网格中的一个单元相当于 Canvas 元素中的一像素,初始时画布的起点为左上角坐标为(0,0), 水平向右为X轴,沿x轴向右方向为正值 ;垂直向下为Y轴,沿y轴方向向下为正值 ,所有元素的位置都相对于原点定位。如下图所示:
变形是一种更强大的方法,可以将画布坐标系原点移动到另一点、并可对网格进行旋转和缩放。坐标系发生变化后,其绘制的图形将按照新的坐标系进行绘制,利用该功能不仅可实现对图形的平移和缩放,也能够让图形发生旋转,在第二章 讲述文本垂直排列功能就是利用该特性实现的。
1. 平移
平移,指的画布坐标系上所有的点沿着相同的方向,移动相同的距离。
参数名
说明
x
左右偏移量,大于0向正方向偏移,小于0则向负方向偏移
y
上下偏移量,大于0向正方向偏移,小于0则向负方向偏移
在基础篇-画布操作 中,我们讲到使用save()
和restore()
可以保存和恢复画布状态,变形操作对画布的更改也可以作为状态被保存和恢复。而且也非常建议大伙在对画布进行变形操作的时候save()
状态,在变形操作结束之后restore()
状态。
translate()
方法接受两个参数,ctx.translate(100,100)
平移后的坐标系如下图所示:
在对画布进行变形操作后绘制的图形,将会绘制在新的坐标系中。例如此时我们需要在(160,60)的坐标上绘制一个宽为300高为120的矩形,就会出现下图所示的结果:
相对于原始坐标,该矩形的起点坐标为(260,160),也就是说在执行translate(x,y)
操作后绘制时的矩形,其横坐标增加了x偏移量,纵坐标增加y偏移量。其源代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <script> let canvas = document .getElementById ('canvas' ); let ctx = canvas.getContext ('2d' ); ctx.translate (120 , 120 ); drawGrid ('lightgray' , 10 , 10 , ctx); ctx.fillStyle = "#BFFFFF" ; ctx.fillRect (160 , 60 , 300 , 120 ); ctx.lineWidth = 8 ; ctx.strokeStyle = "#009999" ; ctx.strokeRect (160 , 60 , 300 , 120 ); </script>
尝试一下 »
在图形开发过程中,很多时候我们知道了如何绘制某一个复杂的形状,在需要将该形状绘制到不同位置的时候,为避免触及该复杂形状的内部实现逻辑,可以使用translate()
改变坐标系,然后绘制该形状,这样就简化了程序的实现逻辑。下面这个示例使用这种方法,在画布中绘制多颗星星,其效果如下所示:
源代码非常简单,我们编制了一个绘制星星的函数,通过随机移动画布,然后调用绘制星星的函数,就实现了上述效果,源代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 <script> let canvas = document .getElementById ('canvas' ); let ctx = canvas.getContext ('2d' ); drawGrid ('lightgray' , 10 , 10 , ctx); let num = 18 ; for (let i = 0 ; i < num; i++) { ctx.save (); let x = getRandomNum (10 , 750 ); let y = getRandomNum (10 , 350 ); ctx.translate (x, y); drawStar (); ctx.restore (); } function drawStar ( ) { ctx.save (); let coords = [0 ,-16 ,4 ,-4 ,16 ,0 ,4 ,4 ,0 ,16 ,-4 ,4 ,-16 ,0 ,-4 ,-4 ,0 ,-16 ]; ctx.beginPath (); for (let i=0 ; i<coords.length ; i+=2 ) { if (i == 0 ) { ctx.moveTo (coords[i], coords[i+1 ]); } else { ctx.lineTo (coords[i], coords[i+1 ]); } } ctx.fill (); ctx.restore (); } </script>
尝试一下 »
再次强烈建议:在执行变形操作之前使用save()
保存画布上下文状态,在执行变形操作并且绘制图形后,使用restore()
恢复画布上下文状态。
2. 旋转
旋转是指以原点(0,0)为中心旋转画布,同样也会改变画布的坐标系。
参数名
说明
angle
旋转角度(顺时针方向,以弧度为单位)
就像平移一样,旋转不会扭曲元素,并保持平行度、角度和距离。下图是旋转15°后,画布坐标系的变化。
旋转角度的单位是弧度,javascript的Math对象有一个常数PI,该常数作为弧度时其值等于180°,弧度与角度的转换函数如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function toRadians (angleInDegrees ) { return (angleInDegrees * Math .PI ) / 180 ; } function toDegrees (angleInRadians ) { return (angleInRadians * 180 ) / Math .PI ; }
尝试一下 »
弧度是一种国际单位制导出的单位,缩写是rad;
弧长等于半径的弧,其所对的圆心角为1弧度,一周的弧度数为2πr/r=2π;
角度也是一种国际单位,常用在数学中使用,缩写是°或deg,一周的角度是360°;
在对画布进行旋转 变形操作后绘制的图形,也会绘制在新的坐标系中。例如此时我们需要在(160,60)的坐标上绘制一个宽为300高为120的矩形,就会出现下图所示的结果:
其源代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <script> let canvas = document .getElementById ('canvas' ); let ctx = canvas.getContext ('2d' ); ctx.rotate (toRadians (15 )); drawGrid ('lightgray' , 10 , 10 , ctx); ctx.fillStyle = "#BFFFFF" ; ctx.fillRect (160 , 60 , 300 , 120 ); ctx.lineWidth = 8 ; ctx.strokeStyle = "#009999" ; ctx.strokeRect (160 , 60 , 300 , 120 ); function toRadians (angleInDegrees ) { return (angleInDegrees * Math .PI ) / 180 ; } </script>
尝试一下 »
图形在平面上的旋转有两个决定因素:参考点 和旋转角度 。参考点的理解可以类比这些图钉:每一张卡片可以围绕固定它的图钉旋转,图钉就是卡片的旋转变换参考点。画布缺省的参考点是坐标原点(0,0),如果需根据某形状的中心点进行旋转,需先将参考点平移translate()
到该形状的中心点,然后旋转rotate()
画布,由于平移将会更改画布的坐标系,因此还需要将参考点平移translate()
至原位置。
下面这个示例左侧的图是根据原点进行的旋转,右侧的图形时根据矩形的中心点进行的旋转,如下图所示:
其源代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 <script> let canvas1 = document .getElementById ('canvas1' ); let ctx1 = canvas1.getContext ('2d' ); drawRect (ctx1, true ); ctx1.save (); ctx1.rotate (toRadians (15 )) drawGrid ('lightgray' , 10 , 10 , ctx1); drawCoord (ctx1); drawRect (ctx1); ctx1.restore (); let canvas2 = document .getElementById ('canvas2' ); let ctx2 = canvas2.getContext ('2d' ); drawRect (ctx2, true ); ctx2.save (); ctx2.translate (160 + 300 /2 , 60 + 120 /2 ); ctx2.rotate (toRadians (15 )) ctx2.translate (-(160 + 300 /2 ), -(60 + 120 /2 )); drawGrid ('lightgray' , 10 , 10 , ctx2); drawCoord (ctx2); drawRect (ctx2); ctx2.restore (); function drawRect (context, before ) { context.lineWidth = 8 ; if (before == true ) { context.fillStyle = "#B9B9B9" ; context.strokeStyle = "#737373" ; } else { context.fillStyle = "#BFFFFF" ; context.strokeStyle = "#009999" ; } context.fillRect (160 , 60 , 300 , 120 ); context.strokeRect (160 , 60 , 300 , 120 ); } </script>
尝试一下 »
3. 缩放
缩放是指以增加或减少图形在 Canvas 中的像素数目,对形状、位图进行缩小或者放大,缩放同样也会改变画布的坐标系。
参数名
说明
x
x 为水平缩放倍率
y
y 为垂直缩放倍率
缩放改变的是图形上所有的点与变换参考点之间的距离。下图是水平和垂直方向各缩放1.5倍之后的坐标系:
从这张图中可以看出,在执行了缩放scale()
之后,坐标系中所有点均进行了缩放,此时依旧在绘制坐标为(160,60),宽度是300,高度是200的矩形,其运行效果如下图所示:
其源代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <script> let canvas = document .getElementById ('canvas' ); let ctx = canvas.getContext ('2d' ); drawGrid ('lightgray' , 10 , 10 , ctx); ctx.scale (1.5 , 1.5 ); ctx.fillStyle = "#BFFFFF" ; ctx.fillRect (160 , 60 , 300 , 120 ); ctx.lineWidth = 8 ; ctx.strokeStyle = "#009999" ; ctx.strokeRect (160 , 60 , 300 , 120 ); </script>
尝试一下 »
在掌握了旋转rotate()
和scale()
的变化功能后,重新开发上面那个随机生成星星的例子,其运行效果如下所示:
这个例子中生成的星星,其旋转角度是随机产生的,其大小也是随机产生的,这样的处理取得了更逼真的效果。其源代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 <script> let canvas = document .getElementById ('canvas' ); let ctx = canvas.getContext ('2d' ); drawGrid ('lightgray' , 10 , 10 , ctx); let num = 18 ; for (let i = 0 ; i < num; i++) { ctx.save (); let x = getRandomNum (10 , 600 ); let y = getRandomNum (10 , 300 ); ctx.translate (x, y); ctx.rotate (toRadians (getRandomNum (10 , 80 ))) let scale = getRandomNum (5 , 15 ) / 10 ; ctx.scale (scale, scale); drawStar (); ctx.restore (); } function drawStar ( ) { ctx.save (); let coords = [0 ,-16 ,4 ,-4 ,16 ,0 ,4 ,4 ,0 ,16 ,-4 ,4 ,-16 ,0 ,-4 ,-4 ,0 ,-16 ]; ctx.beginPath (); for (let i=0 ; i<coords.length ; i+=2 ) { if (i == 0 ) { ctx.moveTo (coords[i], coords[i+1 ]); } else { ctx.lineTo (coords[i], coords[i+1 ]); } } ctx.fill (); ctx.restore (); } </script>
尝试一下 »
将背景改为黑色背景,可以得到更漂亮的渲染效果,如下图:
4. 矩阵变换
在图形系统开发中,矩阵变换(Matrix Transformations)是一种数学运算,用于实现对图形进行平移(translation)、旋转(rotation)、缩放(scaling)和倾斜(skewing)等操作。这些操作将会导致画布渲染上下文对象的坐标系发生变换,从而影响绘图结果。
矩阵变换在Canvas中的实现主要依赖于2D变换矩阵,这个矩阵可以表示出平移、旋转、缩放等变换的数学公式。其定义如下:
1 2 3 a c e m11 m21 dx b d f 或 m12 m22 dy 0 0 1 0 0 1
说明:
属性
说明
a(m11)
水平方向的缩放
b(m12)
竖直方向的倾斜偏移
c(m21)
水平方向的倾斜偏移
d(m22)
竖直方向的缩放
e(dx)
水平方向的移动
f(dy)
竖直方向的移动
初始矩阵各值为:
平移
矩阵运算(将当前的变换矩阵乘上参数的矩阵):
1 2 3 | 1 0 0 | | 1 0 x | | 1 0 dx | | 0 1 0 | * | 0 1 y | = | 0 1 dy | | 0 0 1 | | 0 0 1 | | 0 0 1 |
平移:translate(x, y) 等同于: transform(1, 0, 0, 1, x, y);
旋转
矩阵运算(将当前的变换矩阵乘上参数的矩阵):
1 2 3 | 1 0 0 | | 1 a 0 | | cos(a) sin(a) 0 | | 0 1 0 | * | a 1 0 | = | -sin(a) cos(a) 0 | | 0 0 1 | | 0 0 1 | | 0 0 1 |
旋转:rotate(a),等同于
1 2 3 let sin = Math.sin(a); let cos = Math.cos(a); ctx.transform(cos, sin, -sin, cos, 0, 0);
缩放
矩阵运算(将当前的变换矩阵乘上参数的矩阵):
1 2 3 | 1 0 0 | | x 0 0 | | x 0 0 | | 0 1 0 | * | 0 y 0 | = | 0 y 0 | | 0 0 1 | | 0 0 1 | | 0 0 1 |
缩放:scale(x, y) 等同于 transform(x, 0, 0, y, 0, 0)
设置矩阵
在Canvas渲染上下文中除了translate()
、rotate()
、scale()
可以实现矩阵变换,还提供了直接修改矩阵的api,可以更加灵活的改变变换矩阵的值。
叠加当前变换矩阵
1 ctx.transform (a, b, c, d, e, f);
这个方法不会覆盖当前的变换矩阵,会多次叠加变换:
1 2 3 | 1 0 0 | | a c e | | a c e | | 0 1 0 | * | b d f | = | b d f | | 0 0 1 | | 0 0 1 | | 0 0 1 |
重新设置(覆盖)当前的变换矩阵
1 ctx.setTransform(a, b, c, d, e, f)
这个方法会将当前的变形矩阵重置为单位矩阵,然后用相同的参数调用 transform方法。如果任意一个参数是无限大,那么变形矩阵也必须被标记为无限大,否则会抛出异常。从根本上来说,该方法是取消了当前变形,然后设置为指定的变形,一步完成。
重置当前的变换矩阵
获取当前的变换矩阵
它和调用以下语句是一样的:ctx.setTransform(1, 0, 0, 1, 0, 0);
示例1:中心点缩放
接下来我们通过示例熟悉一下矩阵变换的相关功能,先看看第一个示例的运行效果:
这个示例绘制了6个围绕中心点旋转的矩形,围绕中心点旋转绘制矩形之前需对画布进行三步操作:
将坐标系原点移动到矩形的中心点;
执行旋转;
将坐标系原点移回缺省原点(0,0);
在示例中蓝色的矩形通过translate()
和rotate()
实现画布平移和旋转,而红色的矩形则是通过transform()
实现了画布平移和旋转。源代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 <script> let canvas = document .getElementById ('canvas' ); let ctx = canvas.getContext ('2d' ); drawGrid ('lightgray' , 10 , 10 ); ctx.lineWidth = 4 ; drawRect1 (100 , 200 , 400 , 60 , 0 ); drawRect1 (100 , 200 , 400 , 60 , 30 ); drawRect1 (100 , 200 , 400 , 60 , 60 ); drawRect2 (100 , 200 , 400 , 60 , 90 ); drawRect2 (100 , 200 , 400 , 60 , 120 ); drawRect2 (100 , 200 , 400 , 60 , 150 ); function drawRect1 (x, y, width, height, angle ) { ctx.save (); ctx.translate (x + width / 2 , y + height / 2 ); ctx.rotate (angle * Math .PI / 180 ); ctx.translate (-(x + width / 2 ), -(y + height / 2 )); ctx.strokeStyle = "blue" ; ctx.strokeRect (x, y, width, height); ctx.restore (); } function drawRect2 (x, y, width, height, angle ) { ctx.save (); let sin = Math .sin (angle * Math .PI / 180 ); let cos = Math .cos (angle * Math .PI / 180 ); ctx.transform (1 , 0 , 0 , 1 , x + width / 2 , y + height / 2 ); ctx.transform (cos, sin, -sin, cos, 0 , 0 ); ctx.transform (1 , 0 , 0 , 1 , -(x + width / 2 ), -(y + height / 2 )); ctx.strokeStyle = "red" ; ctx.strokeRect (x, y, width, height); ctx.restore (); } </script>
尝试一下 »
示例2:水平翻转、垂直翻转
在执行缩放操作的时候,当缩放倍率大于1的时候其结果是放大,当缩放倍率小于1的时候其结果是缩小,那么缩放能否为负数呢?根据矩阵的运算规则可知:
当 a=-1时,可实现水平翻转效果;
当 d=-1时,可实现垂直翻转效果;
当 a=-1 d=-1,可实现水平+垂直翻转效果。
我们看一个这样的示例,运行效果如下图所示:
由于缩放操作将导致画布渲染上下文对象的坐标系发生变换,为了将图形绘制到指定位置,还需对画布进行平移操作。例如在变形之前X轴原本是向右的方向增大的,且大于0的值均在原点(0,0)右侧,水平翻转后X轴将会反过来变为向左的方向增大,且大于0的值均在原点(0,0)的左侧,因此为了让图形在画布的原位置显示,需要对X轴进行平移,才可正确显示图形。垂直翻转时需要对Y轴进行平移,源代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 <script> function main (img ) { function main (img ) { let canvas1 = document .getElementById ('canvas1' ); let ctx1 = canvas1.getContext ('2d' ); ctx1.drawImage (img, 60 , 50 ); let canvas2 = document .getElementById ('canvas2' ); let ctx2 = canvas2.getContext ('2d' ); ctx2.scale (-1 , 1 ); ctx2.translate (-canvas2.width , 0 ); ctx2.drawImage (img, 60 , 50 ); let canvas3 = document .getElementById ('canvas3' ); let ctx3 = canvas3.getContext ('2d' ); ctx3.scale (1 , -1 ); ctx3.translate (0 , -canvas3.height ); ctx3.drawImage (img, 60 , 50 ); let canvas4 = document .getElementById ('canvas4' ); let ctx4 = canvas4.getContext ('2d' ); ctx4.scale (-1 , -1 ); ctx4.translate (-canvas4.width , -canvas4.height ); ctx4.drawImage (img, 60 , 50 ); } let image = new Image (); image.onload = function ( ) { main (image); } image.src = "./images/man2b.svg" ; </script>
尝试一下 »
示例3:设置矩阵
矩阵的作用之一就是简化多种几何变换之后新的坐标的计算方式。在上述几个示例中多次对画布进行了平移、旋转和缩放等操作,画布在渲染图形时,首先会将这些变形操作进行叠加运算,运行的结果就是一个矩阵。如果需要重新绘制这些图形,直接设置矩阵即可。
渲染上下文对象提供的getTransform()
可以得到当前的变换矩阵,而setTransform()
可以重新设置当前的变换矩阵。下面这个示例通过setTransform()
设置矩阵,直接绘制爱心,简化了编程时的矩阵变换的那些逻辑。其运行效果和源代码分别如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 <script> let canvas = document .getElementById ('canvas' ); let ctx = canvas.getContext ('2d' ); drawGrid ('lightgray' , 10 , 10 ); ctx.save (); ctx.scale (0.8 , 0.8 ); drawLove (); ctx.restore (); ctx.save (); ctx.setTransform (0.8 , 0 , 0 , -0.8 , 288 , 312 ); drawLove (); ctx.restore (); function drawLove ( ) { ctx.beginPath (); ctx.moveTo (50 , 121 ) ctx.ellipse (124 , 121 , 74 , 74 , 0 , Math .PI , 2 * Math .PI , false ) ctx.ellipse (272 , 121 , 74 , 74 , 0 , Math .PI , 2 * Math .PI , false ) ctx.quadraticCurveTo (346 , 232 , 198 , 343 ) ctx.quadraticCurveTo (50 , 232 , 50 , 121 ) ctx.closePath () ctx.lineWidth = 4 ; ctx.strokeStyle = "red" ; ctx.stroke (); } </script>
尝试一下 »
5. 倾斜
倾斜是一种几何变形,它是指物体在水平或垂直方向上受到力矩的作用而产生的变形,渲染上下文没有提供直接的方法,可通过设置矩阵实现。当矩形仅受到水平方向力矩产生变形的时候,其结果就是一个平行四边形。其效果如下图所示:
上图中灰色矩形为原矩形,其中心点收到了水平方向的力矩作用,因此产生的结果是根据中心点的倾斜,其源代码为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <script> let canvas = document .getElementById ('canvas' ); let ctx = canvas.getContext ('2d' ); drawGrid ('lightgray' , 10 , 10 ); let x = 150 , y = 50 , width = 400 , height = 200 ; ctx.lineWidth = 4 ; ctx.strokeStyle = "#A2A2A2" ; ctx.strokeRect (x, y, width, height); let cx = x + width / 2 , cy = y + height / 2 ; ctx.translate (cx, cy); ctx.transform (1 , 0 , toRadians (45 ), 1 , 0 , 0 ); ctx.translate (-cx, -cy); ctx.strokeStyle = "blue" ; ctx.strokeRect (x, y, width, height); </script>
尝试一下 »
倾斜是通过调整变换矩阵而实现的,对应的矩阵为:
根据此矩阵,我们实现了一个通用的矩阵倾斜函数,根据其水平倾斜角度a和垂直倾斜角度b绘制倾斜的矩形,其执行效果图如下:
上图中,第一行的两个矩形水平倾斜角度为:30°和-30°,垂直倾斜角度为0;中间行的水平倾斜角度为0,垂直倾斜角度为20°和-20°;下面那行的水平和垂直角度相同,分别为15°和-15°。源代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 <script> let canvas = document .getElementById ('canvas' ); let ctx = canvas.getContext ('2d' ); drawGrid ('lightgray' , 10 , 10 ); ctx.lineWidth = 4 ; drawRect (100 , 40 , 200 , 100 , 30 , 0 ) drawRect (450 , 40 , 200 , 100 , -30 , 0 ) drawRect (100 , 200 , 200 , 100 , 0 , 20 ) drawRect (450 , 200 , 200 , 100 , 0 , -20 ) drawRect (100 , 380 , 200 , 100 , 15 , 15 ) drawRect (450 , 380 , 200 , 100 , -15 , -15 ) function drawRect (x, y, width, height, deg1 = 0 , deg2 = 0 ) { let cx = x + width / 2 ; let cy = y + height / 2 ; ctx.save (); ctx.strokeStyle = "#A2A2A2" ; ctx.strokeRect (x, y, width, height); ctx.translate (cx, cy); let trans = [1 , toRadians (deg2), toRadians (deg1), 1 , 0 , 0 ]; ctx.transform (trans[0 ], trans[1 ], trans[2 ], trans[3 ], trans[4 ], trans[5 ]); ctx.translate (-cx, -cy); ctx.strokeStyle = "blue" ; ctx.strokeRect (x, y, width, height); ctx.restore (); } </script>
尝试一下 »
6. 本章小结
本节讲解了画布的平移、缩放、旋转和矩阵等画布变形操作,通过设置矩阵还实现了画布的倾斜。
通过使用矩阵,我们可以方便地表示和操作空间中的点、向量、坐标系、变换等概念。
本节内容使用了Canvas 2D API以下属性和方法:
方法
方法名
说明
ctx.translate(x, y)
平移
ctx.rotate(angle)
旋转
ctx.scale(x, y)
缩放
ctx.transform(a, b, c, d, e, f);
叠加矩阵
ctx.setTransform(a, b, c, d, e, f)
设置矩阵
ctx.getTransform()
获取当前矩阵
ctx.resetTransform()
重置矩阵
练习一下
按以下坐标和变换要求绘制三角形:
平移练习
坐标
操作
参数
[[50,250], [100,50], [150,250]]
平移
(50,0)
[[100,200], [150,0], [200,200]]
平移
(0,50)
[[50,200], [100,00], [150,200]]
平移
(50,50)
缩放练习
坐标
操作
参数
[[200,250], [300,50], [400,250]]
缩放
(0.5, 1)
[[100,500], [150,100], [200,500]]
缩放
(1, 0.5)
[[200,500], [300,100], [400,500]]
缩放
(0.5, 0.5)
旋转练习
坐标
操作
参数
[[250,-100], [50,-150], [250,-200]]
旋转
90°
[[-100,-250], [-150,-50], [-200,-250]]
旋转
180°
[[-250,100], [-50,150], [-250,200]]
旋转
-90°
组合练习1
坐标
操作
参数
[[150,450], [250,50], [350,450]]
缩放 平移
(0.5, 0.5) (50,50)
[[100,400], [200,0], [300,400]]
平移 缩放
(50,50) (0.5, 0.5)
[[-150,-300], [-200,-100], [-250,-300]]
旋转 平移
180 (50,50)
[[-50,-200], [-100,0], [-150,-200]]
平移 旋转
(50,50) 180
[[500,-200], [100,-300], [500,-400]]
旋转 缩放
90 (0.5, 0.5)
[[-200,-500], [-300,-100], [-400,-500]]
旋转 缩放
180 (0.5, 0.5)
[[250,-200], [50,-300], [250,-400]]
缩放 旋转
(0.5, 1) 90
[[250,-200], [50,-300], [250,-400]]
旋转 缩放
90 (1, 0.5)
组合练习2
坐标
操作
参数
[[250,-100], [50,-200], [250,-300]]
平移 缩放 旋转
(50, 0) (0.5, 1) 90
[[200,-200], [0,-300], [200,-400]]
平移 缩放 旋转
(0, 50) (0.5, 1) 90
矩阵练习
坐标
操作
参数
[[250,-100], [50,-200], [250,-300]]
设置矩阵
[3.0616e-17, 1, -0.5, 6.1232e-17, 50, 0]
[[100,-250], [150,-50], [200,-250]]
设置矩阵
[1, -1.2246e-16, -1.2246e-16, -1, 0, 0]
这些练习题运行的结果都是一样的,你也动手试一试吧。
尝试一下 »
本文为“图形开发学院”(www.graphanywhere.com )网站原创文章,遵循CC BY-NC-ND 4.0版权协议 ,商业转载请联系作者获得授权,非商业转载请附上原文出处链接及本声明。
0评论