借助 HTML-in-Canvas API,您可以直接在 2D 画布上下文中渲染交互式、无障碍的 DOM 子树。请参阅 HTML-in-Canvas 概览,详细了解该 API 及其优势。
本指南演示了如何将 HTML 渲染到 2D 画布中。在 2D 画布中渲染 HTML 需要执行以下步骤:
- 准备画布。以声明方式设置正确的属性,让浏览器知道它应该将 HTML 渲染到画布中。此设置在 2D、WebGL 和 WebGPU 上下文中完全相同。了解如何设置画布以及如何声明要独立绘制的 HTML 元素。
- 将元素图片绘制到画布中。
- [可选] 同步 DOM 和像素。
将 HTML 元素绘制到 2D 画布中
画布准备就绪且元素标记为 drawable 后,使用 drawElementImage() 方法将它们渲染到 2D 上下文中。
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const childElement1 = document.getElementById("childElement1");
const childElement2 = document.getElementById("childElement2");
canvas.onpaint = () => {
ctx.reset();
// 1. Draw the primary element at coordinate (20, 20)
ctx.drawElementImage(childElement1, 20, 20);
// 2. Draw the secondary nested button at a custom offset
ctx.drawElementImage(childElement2, 40, 90);
}
drawElementImage() 支持 3 参数、5 参数、7 参数和 9 参数形式,并接受可选的 options 参数:
// 1. Basic position: (element, dx, dy, options?)
ctx.drawElementImage(targetElement, 100, 150);
// 2. Scaled / resized: (element, dx, dy, dWidth, dHeight, options?)
ctx.drawElementImage(targetElement, 100, 150, 180, 60);
// 3. Cropped, default size: (element, sx, sy, swidth, sheight, dx, dy, options?)
ctx.drawElementImage(targetElement, 0, 0, 90, 30, 100, 150);
// 4. Cropped and resized: (element, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight, options?)
ctx.drawElementImage(targetElement, 0, 0, 90, 30, 100, 150, 180, 60);
| 过载表单 | 参数 | 布局效果 |
|---|---|---|
| 默认大小 | (element, dx, dy) |
整个元素采用默认大小,左上角位于 (dx, dy)。 |
| 自定义目标框 | (element, dx, dy, dwidth, dheight) |
将完整元素图片缩放到画布上的 dw × dh 视口中。 |
| 已剪裁,默认大小 | (element, sx, sy, swidth, sheight, dx, dy) |
仅显示从 (sx, sy) 开始的 swidth × sheight 区域,并以该区域的默认大小(与默认大小表单相同的比例)绘制。 |
| 来源切片到目标 | (element, sx, sy, swidth, sheight, dx, dy, dwidth, dheight) |
从 (sx, sy) 开始裁剪源元素,尺寸为 swidth × sheight,然后将其映射到目标 (dx, dy, dwidth, dheight)。 |
同步 DOM 和像素
由于 <canvas> 渲染是命令式的,而 DOM 布局和 CSS 样式是响应式的,因此浏览器需要一种机制来保持渲染的画布像素、交互式点击测试区域和无障碍树同步。在学习如何同步 DOM 和像素之前,请务必了解当 DOM 元素更新并需要重新绘制时触发的 paint 事件。
在 2D 画布上下文中,浏览器会自动将元素的布局坐标、无障碍边界和指针点击测试与绘制的画布坐标同步。
手动更新元素几何图形
在高级场景中,您可以选择停用自动几何图形同步,并手动控制空间转换。将 { preserveElementGeometry: true } 传递给 drawElementImage(),以防止浏览器自动替换元素的现有点击测试坐标:
// 1. Draw the element without altering its existing hit-test bounds
ctx.drawElementImage(targetElement, elementX, 200, { preserveElementGeometry: true });
// 2. Construct a custom transform matrix as needed,
// assuming scaleX/scaleY = canvas grid pixels per CSS pixel,
// from your resize observer (see "Units and sizing").
const currentTransform = new DOMMatrix();
currentTransform.a = 1.5; // scale X
currentTransform.e = x / scaleX; // translate X: grid px → CSS px
currentTransform.f = y / scaleY; // translate Y: grid px → CSS px
// 3. Explicitly apply the custom transform
canvas.updateElementGeometry(targetElement, { canvasTransform: currentTransform });
drawElementImage() 会自动更新此几何图形。此演示展示了设置 { preserveElementGeometry: true } 时几何图形如何不同步。后续步骤
- 了解 HTML-in-Canvas 背后的核心技术概念。
- 了解如何在 WebGL 画布中渲染 HTML。
- 了解如何在 WebGPU 画布中渲染 HTML。
- 了解回退策略。
- 在 GitHub 上提交问题,分享您的反馈。
- 查看社区提供的 HTML-in-Canvas 演示集合。