要用 settransform 实现稳定、可预测的 canvas 图形变换,关键不是叠加操作,而是每次从干净的单位矩阵出发,直接设定全部变换效果;它先重置为单位矩阵再应用参数,不累积误差,绕任意点旋转或缩放可用一步公式计算参数,配合 save/restore 可避免状态污染,与 transform() 的叠加机制有本质区别。

要用 setTransform 实现稳定、可预测的 Canvas 图形变换,关键不是叠加操作,而是每次从干净的单位矩阵出发,直接设定你想要的全部变换效果。
setTransform 的作用机制
setTransform(a, b, c, d, e, f) 会先清空当前所有变换(重置为单位矩阵 [1,0,0,1,0,0]),再应用你传入的这组参数。它不依赖之前的状态,也不累积误差。
- 参数 a 和 d 控制 x、y 方向缩放
- 参数 b 和 c 控制倾斜(旋转也通过它们体现)
- 参数 e 和 f 是最终平移量(单位像素),已包含坐标系旋转/缩放后的偏移修正
绕任意点旋转或缩放的一步写法
想让图形绕自身中心 (cx, cy) 旋转 θ 弧度,不用 translate-rotate-translate 三步,直接用公式算出 setTransform 参数:
- a = cos(θ),b = sin(θ)
- c = -sin(θ),d = cos(θ)
- e = cx − cx×cos(θ) + cy×sin(θ)
- f = cy − cx×sin(θ) − cy×cos(θ)
例如:绕点 (100, 80) 顺时针转 45°(即 −π/4 弧度),代入后调用 setTransform 即可生效,后续 draw 就自动按新坐标系绘制。
避免污染后续绘图的关键习惯
Canvas 的变换状态是全局持续的,一次 setTransform 会影响之后所有绘制,直到被覆盖或重置。
- 每次使用前加 ctx.save()
- 设置完立即调用 ctx.setTransform(...)
- 绘图完成后必须跟 ctx.restore()
这样能确保文字、边框、图标等不同元素互不干扰。漏掉 save/restore 是图形错位最常见原因。
和 transform() 的本质区别
transform() 是“在已有变形上再叠加”,矩阵右乘,容易越调越歪;setTransform() 是“彻底换一套规则”,左乘单位矩阵,结果完全由你控制。
- 做动画或频繁更新时,优先选 setTransform()
- 需要复用同一套变换多次,就封装成函数,内部含 save/setTransform/restore
- 临时清空所有变换,可用 ctx.resetTransform()(等价于 setTransform(1,0,0,1,0,0))











