Canvas坐标系原点在左上角、y轴向下为正,是W3C标准设计;绘图前须调用beginPath()重置路径;鼠标坐标需通过getBoundingClientRect()和devicePixelRatio校准;setTransform()可安全切换局部坐标系;width/height属性与CSS尺寸不一致会导致坐标漂移。

Canvas 的坐标系不是“错的”,只是和数学习惯相反——原点在左上角,y 轴向下为正。所有路径绘制(moveTo、lineTo、arc)都基于这个前提,硬套数学公式或 SVG 思维会直接画偏。
canvas 坐标系为什么 y 向下?
这是 W3C 标准定义的窗口坐标系,和浏览器渲染模型一致。不是 bug,是设计选择。
-
fillRect(0, 0, 100, 100)一定出现在左上角,不是中心或底部 - 用
Math.sin(t)绘制波形时,峰值在上方、谷值在下方——和你直觉相反,但代码没错 - 如果 canvas 高度是
400,逻辑上“底部”对应的是y = 400,不是y = 0
路径绘图前必须调用 beginPath()
Canvas 是状态机,路径命令(moveTo、lineTo、arc)会累积到当前路径中。不重置就会复用上一次的路径,导致意外连线或填充错乱。
- 每次开始新图形前,明确写
ctx.beginPath() -
stroke()或fill()不会自动清空路径,只渲染当前路径 - 漏掉
beginPath()后连续画两个圆,第二个圆可能被第一个的路径连起来,变成奇怪的“8”字形
鼠标坐标怎么映射到 canvas 像素坐标?
直接用 event.clientX/event.clientY 会错——它们是视口坐标,没考虑 canvas 的 margin、border、CSS 缩放或设备像素比。
- 必须先获取 canvas 在视口中的真实位置:
const rect = canvas.getBoundingClientRect() - 再计算相对坐标:
const x = event.clientX - rect.left,const y = event.clientY - rect.top - 高清屏(
window.devicePixelRatio > 1)下还要校准缩放:const realX = x * (canvas.width / rect.width) - 如果 canvas 的
width/height属性和 CSS 尺寸不一致(比如 HTML 设width="800",CSS 设width: 400px),这步缩放就不可省
用 setTransform() 切换局部坐标系更安全
比起全局 scale(1, -1) 翻转整个 canvas(会让文字倒置、图片翻转),setTransform() 可以只对某段路径生效,且不影响后续绘制。
- 例如画仪表盘:先
ctx.setTransform(1, 0, 0, 1, centerX, centerY)把原点移到表盘中心 - 再画指针:
ctx.moveTo(0, 0),ctx.lineTo(radius * Math.cos(angle), radius * Math.sin(angle)),此时 y 向上才是“正常”方向 - 画完立刻
ctx.resetTransform()恢复默认坐标系,避免污染其他图形 - 注意:它覆盖所有变换(包括之前
translate、rotate),不是叠加
最常被忽略的其实是 canvas 元素的 width 和 height 属性与 CSS 尺寸的差异——一旦用 CSS 控制大小,绘图表面就被拉伸,所有坐标计算都会漂移。务必在 HTML 属性里设好尺寸,CSS 只管布局。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











