Canvas变换本质是修改坐标系而非图形本身,所有绘制命令均受其影响;rotate()绕坐标系原点旋转,需配合translate()调整原点位置;scale()会放大像素单位导致模糊,应同步调整lineWidth或改用CSS缩放;transform()叠加矩阵,setTransform()重置矩阵;鼠标坐标需结合getBoundingClientRect()和逆变换映射。

Canvas 变换不是“对图形操作”,而是“改坐标系”——所有后续 fillRect、strokePath 等绘制命令,都自动套用当前坐标系的规则。理解这点,90% 的错位、旋转失效、缩放翻车问题就迎刃而解。
为什么 rotate() 后图形没绕中心转?
因为 rotate() 总是绕当前坐标系原点(默认左上角)顺时针旋转,而不是绕图形自身中心。你画的矩形坐标是 (0, 0),它就贴着原点转,当然看起来像“飞出去”了。
- 先用
translate(x, y)把原点移到你想旋转的中心点(比如矩形中心) - 再调用
rotate(angle)(注意单位是弧度,不是度) - 最后用相对于新原点的坐标绘制,例如
fillRect(-w/2, -h/2, w, h) - 如果只影响单个图形,务必配对使用
ctx.save()和ctx.restore()
scale(2, 2) 后文字模糊、线条变粗怎么办?
scale() 放大的是整个坐标系单位,包括像素密度和线宽逻辑。1px 线条被放大后,浏览器会做抗锯齿插值,导致发虚;文本渲染也失去亚像素精度。
- 避免对含文本或精细描边的场景直接
scale(),优先用 CSStransform: scale()包裹 canvas 元素(但注意这会影响getBoundingClientRect()和鼠标坐标映射) - 若必须用
ctx.scale(),记得同步调整lineWidth:比如ctx.scale(2, 2)后,设ctx.lineWidth = 1实际等于 2px,想保持视觉 1px 就得写ctx.lineWidth = 0.5 - 高清屏(
devicePixelRatio > 1)下,先按 DPR 缩放 canvas 内部尺寸,再用scale()做逻辑缩放,别混用
transform() 和 setTransform() 到底该用哪个?
transform(a,b,c,d,e,f) 是“叠加”当前矩阵,setTransform(a,b,c,d,e,f) 是“覆盖重置”。新手常因误用 transform() 导致矩阵越叠越歪,最终图形消失或缩到看不见。
把任意文章或文档内容转换成精美的全屏翻页 HTML 演示文件(幻灯片风格)。当用户发来一篇文章、文档链接、Markdown 内容、或粘贴的文本,并且希望生成演示用的 HTML 时触发。支持任意内容来源:iWiki 链接、KM 链接、本地文件路径、直接粘贴的文本。生成的 HTML 文件保存到本地工作区,并通过企微直接发送给用户。触发词示例:帮我把这篇文章做成PPT、转成演示文档、生成HTML幻灯片、做个演示、转成可以演示的格式、article to deck、make a slide。
- 想累加效果(比如连续平移+旋转),用
transform() - 想从头开始(比如每次动画帧清空旧变换),无条件用
setTransform(1, 0, 0, 1, 0, 0)—— 这比save()/restore()更轻量,且不依赖栈深度 - 手算矩阵容易出错,推荐用
DOMMatrix辅助:const m = new DOMMatrix().translate(100, 50).rotate(45).scale(2); ctx.setTransform(m.a, m.b, m.c, m.d, m.e, m.f)
鼠标坐标和 canvas 变换对不上?
只要 canvas 经历过 translate、scale 或 CSS 层 transform,鼠标事件返回的 clientX/clientY 就和绘图坐标系不再一致——这不是 bug,是必然结果。
- 永远用
canvas.getBoundingClientRect()获取 canvas 左上角在视口中的真实位置 - 计算相对坐标:
const x = event.clientX - rect.left,const y = event.clientY - rect.top - 再逆向应用当前变换矩阵:需用
getTransform()拿到当前矩阵,求逆矩阵,然后把 (x, y) 代入反推逻辑坐标;更稳的做法是,在绘制前就把业务坐标(如地图经纬度、格子行列)正向映射为 canvas 像素坐标,鼠标处理全程用同一套映射逻辑 - 切记:CSS
width/height和 canvas 的width/height属性是两回事,缩放 mismatch 是高频坑点
最易被忽略的一点:Canvas 变换没有“局部作用域”概念。哪怕你只画一个图标,一旦调了 rotate(),后面所有 fillText()、drawImage() 都受牵连——除非显式 save()/restore() 或 setTransform() 重置。别指望“画完就自动恢复”。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










