Canvas 的变换操作作用于坐标系而非图形本身,rotate() 绕原点(默认左上角)旋转,需配合 translate 移动原点实现绕中心旋转;scale 会导致模糊,应优先用 CSS 缩放或同步调整 lineWidth/font;变换顺序影响结果,正确绕点旋转需 translate→rotate→translate(-cx,-cy);需用 save/restore 隔离变换,setTransform 可重置,鼠标坐标须逆变换映射。
Canvas 的 translate、rotate、scale 不是对图形“做变换”,而是移动、旋转、缩放整个坐标系——后续所有绘制(fillRect、strokePath、fillText)都会自动套用这个新坐标系。理解这点,就避开了 80% 的错位、飞出画布、旋转中心不对等问题。
因为 rotate() 永远绕当前坐标系原点(默认是画布左上角 (0, 0))顺时针旋转,和你要画的图形位置无关。
ctx.translate(x + width/2, y + height/2) 把原点移到矩形中心ctx.rotate(angle)(注意单位是弧度,不是度)ctx.fillRect(-width/2, -height/2, width, height)
ctx.save() 和 ctx.restore(),否则后续所有绘制都会继承该旋转scale() 放大了坐标系单位,1px 线宽实际被渲染为 2px 像素,并触发浏览器插值抗锯齿,导致视觉模糊;文本也失去亚像素渲染能力。
transform: scale() 缩放整个 <canvas> 元素,不干扰 canvas 内部坐标逻辑ctx.scale(),需同步调整线宽和字体大小:例如 ctx.scale(2, 2) 后,设 ctx.lineWidth = 0.5 才能保持视觉上 1px,ctx.font = '12px sans-serif' 要改为 '24px sans-serif'
ctx.scale(-1, 1) 水平翻转(注意文本也会反向,需额外 ctx.scale(-1, 1) 补正)Canvas 变换是矩阵叠加,顺序直接影响最终效果。比如 rotate 在 translate 前,等于绕左上角旋转后再平移;反过来,才是先移到目标点再绕该点旋转。
立即学习“前端免费学习笔记(深入)”;
(cx, cy) 旋转为例):ctx.translate(cx, cy) → ctx.rotate(angle) → ctx.translate(-cx, -cy) → 绘制ctx.save() 包裹整组操作,避免污染后续绘制ctx.setTransform(1, 0, 0, 1, 0, 0) 可一键重置所有变换(清空 translate/rotate/scale 累积),比反复 restore 更可控最容易被忽略的是:鼠标事件坐标(clientX/clientY)永远基于页面坐标,而 canvas 内部坐标已受变换影响。映射时必须用 getBoundingClientRect() 获取画布视口位置,并手动对坐标做逆变换——这步不做,交互逻辑必错。