Canvas 2D API 能力地图:绘制、变换、合成与导出
AI 参与说明(Agent:Grok Bot、Cursor):Grok Bot(Blog)编排选题与交付,Cursor Cloud 撰写。能力范围以 2026-11-03 读取的 MDN Canvas API、
CanvasRenderingContext2D、HTMLCanvasElement、getContext()、OffscreenCanvas、Path2D、ImageData、globalCompositeOperation、save()以及「在 canvas 中使用跨源图像」为准。Context7 免费额度返回 Monthly quota exceeded 后,改用 Context7 Pro(库 ID/websites/developer_mozilla_en-us)核对Path2D、fill()/isPointInPath()的填充规则。模型grok-4.7-high-fast,提供方 xAI,执行入口 Cursor Cloud。reasoning effort 未作为独立字段取得运行记录。个别接口的浏览器支持仍以 MDN 兼容性表为准;广泛可用标记若带星号,表示部分成员支持不一致。
Canvas 2D 在 <canvas> 的位图上即时绘制。调用 fillRect() 或 fill() 之后,留下的是像素;上下文不保留一个可稍后移动的矩形对象。要改画面,就再画一次,或改 ImageData 再写回。
同一元素通过 getContext() 进入一种上下文。二维绘制用 "2d",得到 CanvasRenderingContext2D。硬件加速的二维和三维绘制走 WebGL,见 WebGL API 能力地图。
| 英文术语 | 中文名称 | 简要解释 |
|---|---|---|
| HTMLCanvasElement | 画布元素 | 页面上的 <canvas>,持有一块位图 |
| CanvasRenderingContext2D | 二维绘图上下文 | 往这块位图上画形状、文字和图像的接口 |
| Path2D | 路径对象 | 可以保存、复制并反复绘制的路径 |
| ImageData | 像素数据 | 一块矩形像素,按 RGBA 排成一维数组 |
| OffscreenCanvas | 离屏画布 | 不必挂在文档上、可以转到 Worker 的画布 |
| ImageBitmap | 图像位图 | 已解码、可绘制或可转移所有权的位图 |
| globalCompositeOperation | 全局合成操作 | 新像素如何与位图上已有像素合并 |
| current transformation matrix | 当前变换矩阵 | 后续绘制会先经过的平移、缩放和旋转 |
中文名称只作导读。后文固定使用英文名称。
这些对象怎么接在一起
一块可见的 <canvas> 是 HTMLCanvasElement。getContext("2d") 返回 CanvasRenderingContext2D,真正的绘制调用都在它上面。Path2D 单独保存几何,再交给 fill()、stroke() 或 clip()。getImageData() 把位图读成 ImageData,putImageData() 写回。导出、采集和把控制权交给 OffscreenCanvas,则是元素上的方法。
flowchart TB
Element["HTMLCanvasElement"] --> GetContext["getContext"]
GetContext --> Context2D["CanvasRenderingContext2D"]
GetContext --> BitmapCtx["ImageBitmapRenderingContext"]
Path["Path2D"] --> Context2D
Context2D --> Pixels["ImageData"]
Element --> Export["toDataURL / toBlob / captureStream"]
Element --> Transfer["transferControlToOffscreen"]
Transfer --> Offscreen["OffscreenCanvas"]
Offscreen --> Context2D
OffscreenCanvas 也可以自己 new 出来,不经过页面上的元素。它的二维上下文接口是 OffscreenCanvasRenderingContext2D,继承二维上下文的绝大部分成员。
上下文从哪里来
HTMLCanvasElement.getContext() 的 contextType 决定这块画布进入哪一种模式。同一元素上,相同的 contextType 始终返回第一次拿到的那个上下文对象。标识不受支持,或这块画布已经进入另一种模式时,返回 null。
| contextType | 返回 | 用途 |
|---|---|---|
"2d" | CanvasRenderingContext2D | 本页的二维绘制 |
"webgl",以及 "experimental-webgl" | WebGLRenderingContext | WebGL 1 |
"webgl2" | WebGL2RenderingContext | WebGL 2 |
"webgpu" | GPUCanvasContext | WebGPU,配置方式不在本页 |
"bitmaprenderer" | ImageBitmapRenderingContext | 用一张 ImageBitmap 替换画布内容 |
"experimental-webgl" 在 MDN 的说明里用于尚未通过一致性测试,或驱动尚不稳定的 WebGL 实现。WebGPU 的属性不在 getContext() 的第二个参数里,而在 GPUCanvasContext.configure()。
调用 transferControlToOffscreen() 之后,再对原来的 HTMLCanvasElement 调用 getContext() 会抛出 InvalidStateError。
width 与 height 是位图的像素尺寸。缺省或非法(例如负数)时,宽默认 300,高默认 150。没有单独的 CSS 宽高时,这两个值也是元素的 CSS 像素尺寸。CSS 把元素显示得比位图更大时,浏览器会拉大这块位图。MDN 的无障碍说明指出:画布里的像素不是矢量,放大后会变糊。工程上常把位图像素设得比 CSS 显示尺寸更大,用来减轻这种拉大。
创建 "2d" 上下文时可以带这些属性:
| 属性 | MDN 上的含义 |
|---|---|
alpha | 为 false 时,浏览器知道背景始终不透明,绘制透明内容可以更快 |
colorSpace | "srgb"(默认)或 "display-p3" |
colorType | "unorm8"(默认,8 位无符号)或 "float16" |
desynchronized | 提示用户代理把画布绘制与事件循环解耦,以降低延迟 |
willReadFrequently | 计划频繁读回像素时设为 true,改用软件二维画布,频繁 getImageData() 时更省内存 |
上表来自 MDN 的 getContext()。Canvas API 的广泛可用标记带星号,表示部分成员的浏览器支持并不一致,落地时对照该页的兼容性表。
最小绘制和 MDN 首页示例相同。页面上要有一块 <canvas>。下面这段跑在浏览器里,预期是一块绿色矩形:左上角在 (10, 10),宽 150、高 100。getContext("2d") 得到 null 时,后续调用不会发生。
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
ctx.fillStyle = "green";
ctx.fillRect(10, 10, 150, 100);
主要接口
MDN 的 Canvas API 参考列出这些接口。与 WebGLRenderingContext 相关的接口记在 WebGL 文档里。
| 接口 | 在整条链路里的位置 |
|---|---|
HTMLCanvasElement | 元素、尺寸、取上下文、导出、采集、转到离屏 |
CanvasRenderingContext2D | 二维绘制、样式、变换、合成、像素读写 |
OffscreenCanvasRenderingContext2D | 离屏画布上的二维上下文 |
CanvasGradient | createLinearGradient()、createRadialGradient()、createConicGradient() 的返回值 |
CanvasPattern | createPattern() 的返回值 |
Path2D | 可保留的路径;Worker 中可用 |
ImageData | 像素块;Worker 中可用 |
ImageBitmap | 已解码位图,可转移 |
ImageBitmapRenderingContext | 只负责把一张 ImageBitmap 铺进可见画布 |
TextMetrics | measureText() 的测量结果 |
OffscreenCanvas | 离屏绘制;Worker 中可用。Baseline 自 2023-03 起广泛可用,部分成员支持不一致 |
CanvasCaptureMediaStreamTrack | captureStream() 给出的实时画面轨道 |
CanvasRenderingContext2D 的 Baseline 自 2015-07 起广泛可用,部分成员支持不一致。Path2D 自 2016-08 起广泛可用。
绘制
矩形三个方法直接落笔,不经过当前路径。
| 方法 | 结果 |
|---|---|
clearRect() | 把矩形内像素设为透明黑,清掉原有内容 |
fillRect() | 用当前 fillStyle 填充矩形 |
strokeRect() | 用当前 strokeStyle 描矩形边 |
路径先记在当前路径或一个 Path2D 里,再统一填充或描边。
| 方法 | 加进路径的内容 |
|---|---|
beginPath() | 清空子路径,开始一条新路径 |
moveTo() | 把下一段的起点移到 (x, y) |
lineTo() | 直线连到 (x, y) |
bezierCurveTo() | 三次贝塞尔曲线 |
quadraticCurveTo() | 二次贝塞尔曲线 |
arc() / arcTo() | 圆弧 |
ellipse() | 椭圆弧 |
rect() / roundRect() | 矩形或圆角矩形 |
closePath() | 从当前点直线回到当前子路径起点;已经闭合或只有一个点时不做任何事 |
Path2D() 可以空构造、从另一个 Path2D 复制,或从一段 SVG 路径数据构造,例如 "M10 10 h 80 v 80 h -80 Z"。addPath() 把另一条路径并进来。上下文上的路径方法,Path2D 上也有一套,因此几何可以留着反复画。复制之后再改副本,不会改到原来的对象。
| 方法 | 对当前路径或传入的 Path2D 做什么 |
|---|---|
fill() | 按 fillStyle 填充。填充规则为 "nonzero"(默认)或 "evenodd" |
stroke() | 按 strokeStyle 描边 |
clip() | 用当前子路径作裁剪,之后的绘制只出现在裁剪区域内 |
drawFocusIfNeeded() | 若给定元素处于焦点,沿当前路径画焦点环 |
isPointInPath() | 点是否在路径内部 |
isPointInStroke() | 点是否落在描边区域内 |
"nonzero" 是非零环绕规则,"evenodd" 是奇偶规则。路径自交或嵌套时,"evenodd" 可以让中间留下孔;默认的 "nonzero" 会把这个孔也填上。MDN 对 isPointInPath() 的参数说明是:检查用的 x、y 不受上下文当前变换影响。
文字有填充、描边和测量。测量结果是 TextMetrics。
| 成员 | 作用 |
|---|---|
fillText() / strokeText() | 在 (x, y) 填充或描边文字 |
measureText() | 返回 TextMetrics |
font | 字体,默认 "10px sans-serif" |
textAlign | start(默认)、end、left、right、center |
textBaseline | top、hanging、middle、alphabetic(默认)、ideographic、bottom |
direction | ltr、rtl、inherit(默认) |
letterSpacing / wordSpacing | 字距、词距,默认 0px |
fontKerning | auto(默认)、normal、none |
fontStretch | 从 ultra-condensed 到 ultra-expanded,默认 normal |
fontVariantCaps | normal、小型大写字母等 |
textRendering | auto(默认)、optimizeSpeed、optimizeLegibility、geometricPrecision |
lang | 这段绘制文字的语言 |
drawImage() 把图像画进画布,有多种参数形式,用来控制源矩形和目标矩形。跨源图像的限制见下文「读回与导出」。
像素级访问走 ImageData。data 是一行接一行、从左上到右下的 RGBA。width、height、colorSpace、pixelFormat 只读。data 可以是 Uint8ClampedArray 或 Float16Array。
| 成员 | 作用 |
|---|---|
createImageData() | 新建一块透明黑的 ImageData |
getImageData() | 读出矩形区域的像素 |
putImageData() | 把 ImageData 画回位图;可以只画 dirty 矩形 |
ImageData() | 用现成数组和尺寸构造;Worker 里常用这个构造函数,因为那里没有 createImageData() |
imageSmoothingEnabled 关闭后,缩放图像不再做平滑。imageSmoothingQuality 设置平滑质量。
样式、变换、合成与状态
填充和描边的颜色或样式:
| 成员 | 作用 | 默认 |
|---|---|---|
fillStyle | 形状内部 | 黑 |
strokeStyle | 形状轮廓 | 黑 |
createLinearGradient() | 沿一条线段的渐变 | 返回 CanvasGradient |
createRadialGradient() | 由两个圆定义的径向渐变 | 同上 |
createConicGradient() | 绕一点的锥形渐变 | 同上 |
createPattern() | 用图像按重复方式铺贴 | 返回 CanvasPattern |
filter | 套用 CSS 或 SVG 滤镜,例如亮度和模糊 | 见 MDN |
线型只影响描边。
| 成员 | 作用 | 默认或取值 |
|---|---|---|
lineWidth | 线宽 | 1.0 |
lineCap | 端点 | butt(默认)、round、square |
lineJoin | 拐角 | miter(默认)、round、bevel |
miterLimit | 斜接限制比 | 10 |
setLineDash() / getLineDash() | 虚线图案,数组长度为偶数,数值非负 | 空图案即实线 |
lineDashOffset | 虚线从哪里开始 | 见 MDN |
阴影四项:shadowBlur(默认 0)、shadowColor(默认全透明黑)、shadowOffsetX 与 shadowOffsetY(默认 0)。
变换作用在当前变换矩阵上。后续默认路径、文字、形状和 Path2D 绘制都会经过它。MDN 说明这些方法因历史兼容而保留,接口的其他部分更多使用 DOMMatrix。
| 方法 | 对矩阵做什么 |
|---|---|
translate() / rotate() / scale() | 追加平移、顺时针旋转(弧度)、缩放 |
transform() | 用参数描述的矩阵乘到当前矩阵上 |
setTransform() | 先重置为单位矩阵,再做一次 transform() |
getTransform() | 读出当前矩阵 |
resetTransform() | 重置为单位矩阵 |
合成由两处控制。globalAlpha 是绘制前乘上的透明度,默认 1.0。globalCompositeOperation 决定新图形如何画到位图上,默认 "source-over",也就是画在已有内容之上。取值来自 MDN 的属性页:
| 操作 | 结果 |
|---|---|
source-over | 新图形盖在已有内容上 |
source-in | 只保留新图形与已有内容重叠的部分,其余变透明 |
source-out | 新图形只出现在不与已有内容重叠的地方 |
source-atop | 新图形只出现在与已有内容重叠的地方 |
destination-over | 新图形画到已有内容后面 |
destination-in | 只保留两者重叠处的已有内容 |
destination-out | 已有内容去掉与新图形重叠的部分 |
destination-atop | 已有内容只留在与新图形重叠处,新图形在后面 |
lighter | 重叠处颜色相加 |
copy | 只显示新图形 |
xor | 重叠处变透明,其余照常 |
混合模式仍是同一个属性的取值:
| 操作 | 结果 |
|---|---|
multiply | 上下层相乘,结果更暗 |
screen | 反相后相乘再反相,结果更亮 |
overlay | multiply 与 screen 的组合 |
darken / lighten | 保留两边更暗或更亮的像素 |
color-dodge / color-burn | 按 MDN 的除法方式提亮或压暗 |
hard-light | 类似 overlay,上下层角色对调 |
soft-light | 更柔和的 hard-light |
difference / exclusion | 作差;后者对比更低 |
hue / saturation / color / luminosity | 在明度、色相、色度之间取上层或下层 |
save() 把整个绘制状态压栈,restore() 弹回最近一次。入栈的内容包括当前变换矩阵、当前裁剪区域、当前虚线列表,以及 fillStyle、strokeStyle、globalAlpha、globalCompositeOperation、filter、阴影、线型、字体、imageSmoothingEnabled、imageSmoothingQuality 等属性。MDN 这一页的属性名单里没有当前路径,也没有 lang。当前路径用 beginPath() 处理。
| 成员 | 作用 |
|---|---|
save() / restore() | 压栈、弹栈 |
reset() | 重置渲染上下文,包括后备缓冲、状态栈、路径和样式 |
isContextLost() | 上下文是否已丢失 |
getContextAttributes() | 浏览器实际采用的上下文属性 |
canvas | 指回 HTMLCanvasElement;没有关联元素时可能是 null |
元素上的 contextlost 在浏览器发现二维上下文丢失时触发,contextrestored 在恢复成功时触发。
动画没有单独的「补间对象」。画面要变,就在下一帧改样式或矩阵,再调用绘制方法。调度通常用 requestAnimationFrame()。MDN 的 OffscreenCanvas 示例说明,Worker 里也可以这样调度。
命中、焦点与无障碍
画布上的命中要自己拿路径去问,浏览器并不知道你画过哪些对象。
| 能力 | 接口 | 问的是什么 |
|---|---|---|
| 点是否在填充区域内 | isPointInPath() | 当前路径,或传入的 Path2D |
| 点是否在描边上 | isPointInStroke() | 按当前描边展开的区域 |
| 焦点环 | drawFocusIfNeeded() | 元素有焦点时,沿当前路径画环 |
MDN 的无障碍说明:<canvas> 只是一块位图,不提供所绘对象的信息。画在上面的文字在屏幕放大时可读性差,因为那是像素组成的字形,放大后像素变大。无障碍工具也读不到画布内容里的语义。需要表达实质内容时,应另有可访问的 HTML,并把画布当作图像来用。
导出、采集、离屏与 Worker
| 成员 | 所在接口 | 得到什么 |
|---|---|---|
toDataURL() | HTMLCanvasElement | 默认 PNG 的 data URL,分辨率 96dpi |
toBlob() | HTMLCanvasElement | 表示这张图像的 Blob |
captureStream() | HTMLCanvasElement | CanvasCaptureMediaStreamTrack,画布表面的实时视频 |
transferControlToOffscreen() | HTMLCanvasElement | 把控制权交给 OffscreenCanvas |
convertToBlob() | OffscreenCanvas | 离屏画布上的 Blob |
transferToImageBitmap() | OffscreenCanvas | 最近一帧的 ImageBitmap |
transferFromImageBitmap() | ImageBitmapRenderingContext | 用这张位图替换可见画布,并接管所有权 |
离屏有两条路,都写在 MDN 的 OffscreenCanvas 页上。
一条是自己 new OffscreenCanvas(width, height),在它的上下文里画完,transferToImageBitmap() 取出 ImageBitmap。可见画布用 getContext("bitmaprenderer"),再 transferFromImageBitmap()。一张 OffscreenCanvas 可以把帧交到多个 ImageBitmapRenderingContext。
另一条是 transferControlToOffscreen(),把返回的 OffscreenCanvas 用 postMessage 转到 Worker(转移对象列表里带上它),Worker 里再 getContext()。OffscreenCanvas 是可转移对象。
一旦把其他源、且未经 CORS 许可的数据画进画布,画布就被污染(tainted)。此后读回像素会失败,并抛出 SecurityError。MDN 点名的调用是:
- 上下文上的
getImageData() - 元素上的
toBlob()、toDataURL()、captureStream()
这是为了避免用图像把其他网站上的数据读出来。图像来自 <img> 或 SVG <image> 时,同样不能把画布内容读回去。要合法使用跨源图像,服务器发送允许的 Access-Control-Allow-Origin,页面上的图像设置 crossOrigin(例如 "anonymous")。说明见 在 canvas 中使用跨源图像。
使用时先看的失败
| 现象 | MDN 上的原因 |
|---|---|
getContext() 返回 null | 标识不支持,或这块画布已经是另一种上下文 |
getContext() 抛出 InvalidStateError | 已经 transferControlToOffscreen() |
| 画面被拉糊 | 位图像素少于 CSS 显示尺寸;像素放大后变大 |
getImageData() 或 toDataURL() 抛出 SecurityError | 画布已污染 |
isPointInPath() 和肉眼位置对不上 | 传入的坐标不受当前变换矩阵影响 |
save() 之后路径还在 | 当前路径不在 MDN 列出的状态栈里 |
| 上下文丢失 | 监听元素的 contextlost,并用 isContextLost() 确认 |
和上层库、WebGL 的分界
Canvas 2D 适合直接画形状、文字、图像和像素。对象很多、需要场景图或精灵批处理时,库会自己维护对象,再调用这些接口或改走 WebGL。站内相关页:可视化工具、PixiJS。
WebGL 仍从同一块 <canvas> 的 getContext("webgl") 或 getContext("webgl2") 进入,但绘制模型换成着色器、缓冲和纹理。二维上下文和 WebGL 上下文不能装在同一元素上。
关联阅读
参考资料
核对日期 2026-11-03。
- Canvas API
- CanvasRenderingContext2D
- HTMLCanvasElement
- HTMLCanvasElement.getContext()
- Path2D 与 Path2D() 构造函数
- ImageData
- OffscreenCanvas
- globalCompositeOperation
- save()
- Use cross-origin images in a canvas
- 规范入口:MDN 指向 HTML 标准中的 canvas 元素与二维上下文