存储与清除图像的变换状态
图像变换的效果会保留下来。我们绘制出一次镜像特征后,绘制其他特征时都会产生镜像效果,这可能并不方便。
对于需要临时转换坐标系统的函数来说,我们经常需要保存当前的信息,画一些图,变换图像然后重新加载之前的图像。首先,我们需要将当前函数调用的所有图形变换信息保存起来。接着,函数完成其工作,并添加更多的变换。最后我们恢复之前保存的变换状态。
2D 画布上下文的save
与restore
方法执行这个变换管理。这两个方法维护变换状态堆栈。save
方法将当前状态压到堆栈中,restore
方法将堆栈顶部的状态弹出,并将该状态作为当前context
对象的状态。
下面示例中的branch
函数首先修改变换状态,然后调用其他函数(本例中就是该函数自身)继续在特定变换状态中进行绘图。
这个方法通过画出一条线段,并把坐标系的中心移动到线段的端点,然后调用自身两次,先向左旋转,接着向右旋转,来画出一个类似树一样的图形。每次调用都会减少所画分支的长度,当长度小于 8 的时候递归结束。
<canvas width="600" height="300"></canvas>
<script>
let cx = document.querySelector("canvas").getContext("2d");
function branch(length, angle, scale) {
cx.fillRect(0, 0, 1, length);
if (length < 8) return;
cx.save();
cx.translate(0, length);
cx.rotate(-angle);
branch(length * scale, angle, scale);
cx.rotate(2 * angle);
branch(length * scale, angle, scale);
cx.restore();
}
cx.translate(300, 0);
branch(60, 0.5, 0.8);
</script>
如果没有调用save
与restore
方法,第二次递归调用branch
将会在第一次调用的位置结束。它不会与当前的分支相连接,而是更加靠近中心偏右第一次调用所画出的分支。结果图像会很有趣,但是它肯定不是一棵树。