引言
在上一篇日志“canvas 图片拖拽旋转之一”中,对坐标转换有了比较深入的了解,但是仅仅利用坐标转换实现的拖拽旋转,会改变canvas坐标系的状态,从而影响画布上其他元素的绘制。因此,这个时候需要用到一对canvas方法,在变换坐标系前保存canvas状态,在变换并绘制完成之后,恢复canvas状态,即save()和restore()。
[备注]
这篇文章只是记录分享下解决问题的过程,找我要demo的,或者问我什么东西怎么做的,就不要加我了。你可以加一个canvas相关的交流群,或者如果需要用到KineticJS/FabricJS的话,可以加群251572039。
一、理解save和restore的操作对象
对于save和restore方法,有一个误解就是,认为每一步都save之后restore就等同于ctrl+z。其实save保存的只是CanvasRenderingContext2D 对象的状态以及对象的所有属性,并不包括这个对象上绘制的图形。引用一段w3school上的解释:
save() 和 restore() 方法允许你保存和恢复一个 CanvasRenderingContext2D 对象的状态。save() 把当前状态推入到栈中,而 restore() 从栈的顶端弹出最近保存的状态,并且根据这些存储的值来设置当前绘图状态。
CanvasRenderingContext2D 对象的所有属性(除了画布的属性是一个常量)都是保存的状态的一部分。变换矩阵和剪切区域也是这个状态的一部分,但是当前路径和当前点并不是。
也就是说,save()可以保存canvas的状态(比如坐标系的状态)以及fillStyle、strokeStyle、lineWidth 等等属性。
基于这一点,我们就可以在变换坐标系之前save(),变换并绘制完成后restor(),这样就可以保证图形发生了旋转偏移而canvas坐标系仍然是屏幕坐标系的状态(类似于拿了一把标尺画完图之后又把标尺放回了原位)。关键代码如下:
ctx.save();
ctx.translate(PO.x,PO.y);//坐标原点移动到图片中心点
ctx.rotate(now_rotate_radian);//旋转画布 在屏幕坐标系基础上旋转 now_rotate_radian
ctx.dr