变形操作
状态的恢复和保存
- 状态的保存 :
save(),保存画布的所有状态 - 状态的恢复:
restore(),恢复画布状态
画布中的状态在每次调用sava()方法之后,保存到状态栈中,每次restore(),状态栈中最后的状态会弹出,并恢复所有设置。
没有save() 时:
typescript
//这里设置一些初始样式 填充颜色为红色,并绘制一个矩形
canvas.beginPath()
canvas.fillStyle = `red`;
canvas.rect(0,0,100,100)
canvas.fill()
canvas.closePath()//这里使用闭合路径是更明确第一个矩形的绘制已结束
//这里没有保存上一个矩形的状态,并再添加一个矩形
canvas.rect(200,0,100,100);
//填充矩形之后会沿用上一个矩形的样式设置 canvas.fillStyle = `red`;
canvas.fill()效果图:
调用save() 时:
typescript
const colors = ["red", "#8e44ad", "#f1c40f"];
for (let i = 0; i < colors.length; i++) {
//重新开始一个新的路径
canvas.beginPath()
//设置不同样式
canvas.fillStyle = colors[i];
canvas.rect(i * 100 * 2, 0, 100, 100)
canvas.fill()
canvas.closePath()
//保存每次的状态
canvas.save()
}效果图:

恢复canvas状态restore():
typescript
for (let i = 0; i < colors.length; i++) {
//重新开始一个新的路径
canvas.beginPath()
//设置不同样式
canvas.fillStyle = colors[i];
canvas.rect(i * 100 * 2, 0, 100, 100)
canvas.fill()
canvas.closePath()
//保存每次的状态
canvas.save()
}
//再开启一个循环
for (let i = 0; i < colors.length; i++) {
//恢复状态栈中的最顶部的状态
canvas.restore()
//重新开始一个新的路径
canvas.beginPath()
//不设置样式,会使用上一个保存的样式
// canvas.fillStyle = colors[i];
canvas.rect(i * 100 * 2, 200, 100, 100)
canvas.fill()
canvas.closePath()
}效果图:

移动
如果不使用 translate 方法,那么所有矩形都将被绘制在相同的位置(0,0)。translate 方法同时让我们可以任意放置这些图案,而不需要在 fillRect() 方法中手工调整坐标值,既好理解也方便使用。
typescript
//绘制九宫格
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
//保存默认设置
canvas.save();
canvas.strokeStyle = "#3498db"
//移动画布,设置每次绘制时的x,y轴上的偏移量
canvas.translate(10 + j * 50, 10 + i * 50);
//绘制矩形,不需要设置矩形的x,y
canvas.strokeRect(0, 0, 25, 25);
//恢复默认设置,将原点重新移动到(0,0),将画布的移动设置为默认值,不然当循环足够多时,会有些图形超出画布范围
canvas.restore();
}
}效果图:
旋转
改变变形原点,旋转的中心点始终是 canvas 的原点(0,0),如果要改变它,我们需要用到 translate方法。
typescript
//绘制画布的线框
canvas.strokeStyle = 'rgba(0,0,0,0.4)'
canvas.strokeRect(0, 0, 1000, 800)
const colors = ["#1abc9c", "#9b59b6", "#34495e", "#f39c12", "#c0392b", "#2980b9"]
//改变变形原点,这里的画布大小是1000,800
canvas.translate(500, 400)
//循环数组
for (let i = 0; i < colors.length; i++) {
canvas.save()
canvas.fillStyle = colors[i];
canvas.fillRect(0,0,100,100);
//一个循环6次,每次60度
canvas.rotate((Math.PI / 180) * 60)
// canvas.restore()//这里不调用restore,不然画布的角度会被重制
}效果图:

变形
可以通过transform(a,b,c,d,e,f)方法设置对画布的倾斜、缩放、平移。
参数讲解:
a:这是变换矩阵的第一行第一列元素,表示 x 轴方向的缩放(scaling)。如果a是 1,表示不对 x 轴进行缩放;如果a大于 1,表示在 x 轴方向上进行放大;如果a小于 1,表示在 x 轴方向上进行缩小。b:这是变换矩阵的第二行第一列元素,表示 x 轴方向的倾斜(skewing)。它不会影响 x 轴的方向,但会在 x 轴方向上产生倾斜效果。c:这是变换矩阵的第一行第二列元素,表示 y 轴方向的倾斜(skewing)。它不会影响 y 轴的方向,但会在 y 轴方向上产生倾斜效果。d:这是变换矩阵的第二行第二列元素,表示 y 轴方向的缩放(scaling)。如果d是 1,表示不对 y 轴进行缩放;如果d大于 1,表示在 y 轴方向上进行放大;如果d小于 1,表示在 y 轴方向上进行缩小。e:这是变换矩阵的第一行第三列元素,表示 x 轴方向的平移(translation)。它将整个坐标系沿着 x 轴平移指定的距离。f:这是变换矩阵的第二行第三列元素,表示 y 轴方向的平移(translation)。它将整个坐标系沿着 y 轴平移指定的距离。
typescript
// 开始绘制路径
canvas.beginPath();
canvas.rect(50, 50, 100, 100); // 在 (50, 50) 处创建一个宽高为 100 的正方形
// 设置填充颜色
canvas.fillStyle = "#e74c3c";
canvas.fill();
// 应用变换 移动画布到(50,50) 只移动,不缩放,不倾斜
// 倾斜45度 平移x=50,y=50,不缩放,y轴倾斜 45度
canvas.transform(1, 0, Math.sin(Math.PI / 4), 1, 50, 50);
// 重新绘制路径
canvas.beginPath();
canvas.rect(0, 0, 100, 100); // 在 (0, 0) 处创建一个宽高为 100 的正方形
// 设置填充颜色
canvas.fillStyle = "#2ecc71";
canvas.fill();效果图:

调整代码,就实现旋转的效果:
typescript
canvas.transform(1, - Math.sin(Math.PI / 4), Math.sin(Math.PI / 4), 1, 50, 50);效果如下:
