HTML中Canvas的translate rotate scale变换方法应用

作者:袖梨 2026-06-07
Canvas 的变换操作作用于坐标系而非图形本身,rotate() 绕原点(默认左上角)旋转,需配合 translate 移动原点实现绕中心旋转;scale 会导致模糊,应优先用 CSS 缩放或同步调整 lineWidth/font;变换顺序影响结果,正确绕点旋转需 translate→rotate→translate(-cx,-cy);需用 save/restore 隔离变换,setTransform 可重置,鼠标坐标须逆变换映射。

Canvas 的 translaterotatescale 不是对图形“做变换”,而是移动、旋转、缩放整个坐标系——后续所有绘制(fillRectstrokePathfillText)都会自动套用这个新坐标系。理解这点,就避开了 80% 的错位、飞出画布、旋转中心不对等问题。

为什么 rotate() 后图形绕左上角转,而不是绕自己中心?

因为 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(2, 2) 后线条发虚、文字模糊,怎么保持清晰?

scale() 放大了坐标系单位,1px 线宽实际被渲染为 2px 像素,并触发浏览器插值抗锯齿,导致视觉模糊;文本也失去亚像素渲染能力。

  • 优先方案:用 CSS 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) 补正)

translate / rotate / scale 的执行顺序为什么不能乱?

Canvas 变换是矩阵叠加,顺序直接影响最终效果。比如 rotatetranslate 前,等于绕左上角旋转后再平移;反过来,才是先移到目标点再绕该点旋转。

立即学习“前端免费学习笔记(深入)”;

  • 典型正确顺序(以绕点 (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() 获取画布视口位置,并手动对坐标做逆变换——这步不做,交互逻辑必错。

相关文章

精彩推荐