![HTML5+CSS3从入门到精通(微课精编版)](https://wfqqreader-1252317822.image.myqcloud.com/cover/697/24172697/b_24172697.jpg)
4.4 图形变形
本节将介绍如何对画布进行操作以及如何对画布中的图形进行变形,以便设计复杂图形。
4.4.1 保存和恢复状态
![](https://epubservercos.yuewen.com/1B54E6/13043253503832006/epubprivate/OEBPS/Images/Figure-P113_5128.jpg?sign=1738864960-3eCS1GDVjE3FyHY9u3YMpbD9djL6IrWO-0-8ba5f3e483f08d429a606188ac0d5721)
视频讲解
Canvas状态存储在栈中,一个绘画状态包括两部分。
当前应用的变形,如移动、旋转和缩放,包括的样式属性:strokeStyle、fillStyle、globalAlpha、lineWidth、lineCap、lineJoin、miterLimit、shadowOffsetX、shadowOffsetY、shadowBlur、shadowColor、globalCompositeOperation。
当前的裁切路径,参考4.5节介绍。
使用save()方法,可以将当前的状态推送到栈中保存,使用restore()方法可以将上一个保存的状态就从栈中弹出,恢复上一次所有的设置。
【示例】下面示例先绘制一个矩形,填充颜色为#ff00ff,轮廓颜色为蓝色,然后保存这个状态,再绘制另外一个矩形,填充颜色为#ff0000,轮廓颜色为绿色,最后恢复第一个矩形的状态,并绘制两个小的矩形,则其中一个矩形填充颜色必为#ff00ff,另外矩形轮廓颜色必为蓝色,因为此时已经恢复了原来保存的状态,所以会沿用最先设定的属性值,预览效果如图4.30所示。
![](https://epubservercos.yuewen.com/1B54E6/13043253503832006/epubprivate/OEBPS/Images/Figure-P114_78405.jpg?sign=1738864960-JK1KH8bYiAfN5qxcRjJhjT9z1YMm0kPi-0-ae796b57fd03ffaa828070f438163a80)
![](https://epubservercos.yuewen.com/1B54E6/13043253503832006/epubprivate/OEBPS/Images/Figure-P114_5290.jpg?sign=1738864960-9Kb0GDdMhZKTvUgFu141GmUPqrBGIGAq-0-1058265b52746ccf6a0af4f2912f3697)
图4.30 保存与恢复canvas状态
4.4.2 清除画布
![](https://epubservercos.yuewen.com/1B54E6/13043253503832006/epubprivate/OEBPS/Images/Figure-P114_5302.jpg?sign=1738864960-h5sJMdaZjmpvy0pd1qxcw7dNWQZ1nYqS-0-bdaa2a04b6055c0ddb722c5407f378d7)
视频讲解
使用clearRect()方法可以清除指定区域内的所有图形,显示画布背景,该方法用法如下。
context.clearRect(x,y,width,height);
参数说明如下:
x:要清除的矩形左上角的x坐标。
y:要清除的矩形左上角的y坐标。
width:要清除的矩形的宽度,以像素计。
height:要清除的矩形的高度,以像素计。
【示例】下面示例演示了如何使用clearRect()方法来擦除画布中的绘图。
![](https://epubservercos.yuewen.com/1B54E6/13043253503832006/epubprivate/OEBPS/Images/Figure-P115_78406.jpg?sign=1738864960-lqNbix6z714KXKE63m3HqvpkJyS10Tw5-0-8035b372a5f6f25c154ee57df4dc2a6d)
在浏览器中的预览效果如图4.31所示,先是在画布上绘制一段弧线。如果单击“清空画布”按钮,则会清除这段弧线,如图4.32所示。
![](https://epubservercos.yuewen.com/1B54E6/13043253503832006/epubprivate/OEBPS/Images/Figure-P115_5402.jpg?sign=1738864960-Wt2LpwESRa97kmZb6rsw1l5eBdIvUGK5-0-aa973fce93e60283fa2674dbf9810a47)
图4.31 绘制弧线
![](https://epubservercos.yuewen.com/1B54E6/13043253503832006/epubprivate/OEBPS/Images/Figure-P115_5403.jpg?sign=1738864960-9xorqN8KrU70LssCTw72pwomLjNY0N5B-0-ee5e895b4446626b04f07c4e7a715da3)
图4.32 清空画布
4.4.3 移动坐标
![](https://epubservercos.yuewen.com/1B54E6/13043253503832006/epubprivate/OEBPS/Images/Figure-P115_5471.jpg?sign=1738864960-2CSjflDYFDrukU525BkLL1m0u3hffMyb-0-30537dd8115883f047370914862b956d)
视频讲解
在默认状态下,画布以左上角(0,0)为原点作为绘图参考。使用translate()方法可以移动坐标原点,这样新绘制的图形就以新的坐标原点为参考进行绘制。其用法如下。
context.translate(dx, dy);
参数dx和dy分别为坐标原点沿水平和垂直两个方向的偏移量,如图4.33所示。
注意:在使用translate()方法之前,应该先使用save()方法保存画布的原始状态。当需要时可以使用restore()方法恢复原始状态,特别是在重复绘图时非常重要。
【示例】下面示例综合运用了save()、restore()、translate()方法来绘制一个伞状图形。
![](https://epubservercos.yuewen.com/1B54E6/13043253503832006/epubprivate/OEBPS/Images/Figure-P115_78408.jpg?sign=1738864960-5mZFFnQhwNOdw5Uc043MRl6IhoRIac8B-0-013588a45b979f6d4c06082dc59aa32f)
在浏览器中的预览效果如图4.34所示。可见,canvas中图形移动的实现,其实是通过改变画布的坐标原点来实现的,所谓的“移动图形”,只是“看上去”的样子,实际移动的是坐标空间。领会并掌握这种方法,对于随心所欲地绘制图形非常有帮助。
![](https://epubservercos.yuewen.com/1B54E6/13043253503832006/epubprivate/OEBPS/Images/Figure-P116_5661.jpg?sign=1738864960-5wDxqiQpVKCIDgewobcDm0G2tA7ZTV5A-0-654235c4f60562ffcbda0b060fae481b)
图4.33 坐标空间的偏移示意图
![](https://epubservercos.yuewen.com/1B54E6/13043253503832006/epubprivate/OEBPS/Images/Figure-P116_5662.jpg?sign=1738864960-wYw5EC2OAEFbB5AGxt3fNlCSbU9zMIhv-0-17cda6439c113815393f9342c0875d99)
图4.34 移动坐标空间
4.4.4 旋转坐标
![](https://epubservercos.yuewen.com/1B54E6/13043253503832006/epubprivate/OEBPS/Images/Figure-P116_5667.jpg?sign=1738864960-1yPLfvQYt3QqBEJvrY1k6TzAW2AOckzR-0-638b857f70e1b4be2e7847341f944e05)
视频讲解
使用rotate()方法可以以原点为中心旋转canvas上下文对象的坐标空间,其用法如下。
context.rotate(angle);
rotate()方法只有一个参数,即旋转角度angle,旋转角度以顺时针方向为正方向,以弧度为单位,旋转中心为canvas的原点,如图4.35所示。
![](https://epubservercos.yuewen.com/1B54E6/13043253503832006/epubprivate/OEBPS/Images/Figure-P117_5695.jpg?sign=1738864960-dpmHcT7VV0hhoUrSECrfQs5wNK5lSC1n-0-a03d53c45fb322123ddca08e246dd519)
图4.35 以原点为中心旋转canvas
提示:如需将角度转换为弧度,可以使用degrees*Math.PI/180公式进行计算。例如,如果要旋转5°,可套用这样的公式:5*Math.PI/180。
【示例】在上节示例的基础上,下面示例设计在每次开始绘制图形之前,先将坐标空间旋转PI*(2/4+i/4),再将坐标空间沿y轴负方向移动100,然后开始绘制图形,从而实现使图形沿一中心点平均旋转分布。在浏览器中的预览效果如图4.36所示。
![](https://epubservercos.yuewen.com/1B54E6/13043253503832006/epubprivate/OEBPS/Images/Figure-P117_78412.jpg?sign=1738864960-s5ZOM8Vs28endh1hJa3hS2oZJU5Tl9EX-0-072a35ef967e8ecdef98fbb47b2a696f)
![](https://epubservercos.yuewen.com/1B54E6/13043253503832006/epubprivate/OEBPS/Images/Figure-P117_5784.jpg?sign=1738864960-qLxHIBzKWYR09sbAnCBh5YH1PxfIpFlm-0-b742233c9e0df30f53ba4398ae02ef47)
图4.36 旋转坐标空间
4.4.5 缩放图形
![](https://epubservercos.yuewen.com/1B54E6/13043253503832006/epubprivate/OEBPS/Images/Figure-P118_5918.jpg?sign=1738864960-AidA8WLPnS4pmCdOFgTDjTi4Z1BePvc5-0-5f76fb7d095eab41e707b0c916fde40c)
视频讲解
使用scale()方法可以增减canvas上下文对象的像素数目,从而实现图形的放大或缩小,其用法如下。
context.scale(x,y);
其中x为横轴的缩放因子,y轴为纵轴的缩放因子,值必须是正值。如果需要放大图形,则将参数值设置为大于1的数值,如果需要缩小图形,则将参数值设置为小于1的数值,当参数值等于1时则没有任何效果。
【示例】下面示例使用scale(0.95,0.95)来缩小图形到上次的0.95,共循环80次,同时移动和旋转坐标空间,从而实现图形呈螺旋状由大到小的变化,预览效果如图4.37所示。
![](https://epubservercos.yuewen.com/1B54E6/13043253503832006/epubprivate/OEBPS/Images/Figure-P118_78413.jpg?sign=1738864960-uhCc2HcoK0ciSFEssFyw6HQeCvbG534x-0-85b12e70a3d6bb863d9c0e243b0c0a1d)
![](https://epubservercos.yuewen.com/1B54E6/13043253503832006/epubprivate/OEBPS/Images/Figure-P118_5906.jpg?sign=1738864960-MLDPDkChQQzOma5VUok2pDyCGI0kGZrK-0-98bcb3bb5c560107782ba98a03870d77)
图4.37 缩放图形
4.4.6 变换图形
![](https://epubservercos.yuewen.com/1B54E6/13043253503832006/epubprivate/OEBPS/Images/Figure-P118_5921.jpg?sign=1738864960-XIueUR8yXZJQJr7r7KohFzJmh9hQMRWm-0-1979d9d52511cc566e072902a10676a6)
视频讲解
transform()方法可以同时缩放、旋转、移动和倾斜当前的上下文环境,用法如下所示:
context.transform(a,b,c,d,e,f);
参数说明如下:
a:水平缩放绘图。
b:水平倾斜绘图。
c:垂直倾斜绘图。
d:垂直缩放绘图。
e:水平移动绘图。
f:垂直移动绘图。
提示:
translate(x,y)可以用下面的方法来代替:
context.transform(0,1,1,0,dx,dy);
或:
context.transform(1,0,0,1,dx,dy);
其中dx为原点沿x轴移动的数值,dy为原点沿y轴移动的数值。
scale(x,y)可以用下面的方法来代替:
context.transform(m11,0,0,m22,0,0);
或:
context.transform(0,m12,m21,0,0,0);
其中dx、dy都为0表示坐标原点不变。m11、m22或m12、m21为沿x、y轴放大的倍数。
rotate(angle)可以用下面的方法来代替:
context.transform(cosθ,sinθ,- sinθ, cosθ,0,0);
其中的θ为旋转角度的弧度值,dx、dy都为0表示坐标原点不变。
setTransform()方法用于将当前的变换矩阵进行重置为最初的矩阵,然后以相同的参数调用transform方法,用法如下所示。
context.setTransform(m11, m12, m21, m22, dx, dy);
【示例】下面示例使用setTransform()方法将前面已经发生变换的矩阵首先重置为最初的矩阵,即恢复最初的原点,然后再将坐标原点改为(10,10),并以新的坐标为基准绘制一个蓝色的矩形。
![](https://epubservercos.yuewen.com/1B54E6/13043253503832006/epubprivate/OEBPS/Images/Figure-P119_78414.jpg?sign=1738864960-XihmsGkCDJuqaTeKIy2Uww6n0FX2bDFD-0-24dbcb97661f80595168dbd47cf01fbe)
在浏览器中的预览效果如图4.38所示。在本例中,使用scale(0.95,0.95)来缩小图形到上次的0.95,共循环89次,同时移动和旋转坐标空间,从而实现图形呈螺旋状由大到小的变化。
![](https://epubservercos.yuewen.com/1B54E6/13043253503832006/epubprivate/OEBPS/Images/Figure-P120_6200.jpg?sign=1738864960-Qrzha68rPQfvZg1Yc96C5OOK1nXKHScg-0-6fdd8040ec9f0a9cf691a0cc8921d557)
图4.38 矩阵重置并变换