การแสดงผล HTML ใน Canvas ของ WebGL ช่วยให้คุณใช้ซับทรี DOM แบบเรียลไทม์เป็นพื้นผิว GPU แบบไดนามิก ใช้เอฟเฟกต์ตัวปรับเฉดสีกับ DOM แบบเรียลไทม์ และผสานรวม HTML แบบอินเทอร์แอกทีฟเข้ากับฉาก 3 มิติได้
คู่มือนี้แสดงวิธีแสดงผล HTML ใน Canvas ของ WebGL ดูข้อมูลเพิ่มเติมเกี่ยวกับ HTML-in-Canvas ได้ในภาพรวม API
การแสดงผล HTML ใน Canvas ของ WebGL ต้องทำตามขั้นตอนต่อไปนี้
- เตรียมผืนผ้าใบ ตั้งค่าแอตทริบิวต์ที่ถูกต้องอย่างชัดเจนเพื่อให้เบราว์เซอร์ทราบว่าควรแสดงผล HTML เป็น Canvas การตั้งค่านี้เหมือนกันในบริบท 2D, WebGL และ WebGPU ดูวิธีตั้งค่า Canvas และวิธีประกาศองค์ประกอบ HTML ที่จะวาดแยกกัน
- ใช้ HTML เป็นพื้นผิวโดยทำดังนี้
- จัดสรรพื้นที่เก็บข้อมูลพื้นผิว GPU ล่วงหน้า
- อัปโหลดภาพรวม DOM เป็นพื้นผิว
- ซิงค์ DOM และพิกเซล
วาดองค์ประกอบ HTML เป็นพื้นผิว WebGL
ใน WebGL ระบบจะอัปโหลดองค์ประกอบ HTML ไปยัง GPU เป็นพื้นผิว 2 มิติโดยใช้ texElementSubImage2D()
จัดสรรพื้นที่เก็บข้อมูลพื้นผิวล่วงหน้า
บริบท WebGL ต้องมีการจัดการหน่วยความจำอย่างชัดเจน ซึ่งต่างจาก Canvas 2 มิติที่จัดการหน่วยความจำสำรองโดยอัตโนมัติ
คุณต้องจัดสรรหน่วยความจำ GPU ล่วงหน้าก่อนที่จะอัปโหลดพิกเซล DOM ซึ่งช่วยให้เบราว์เซอร์อัปเดตรูปภาพย่อยได้อย่างรวดเร็วโดยไม่ต้องเรียกใช้การจัดสรรหน่วยความจำ GPU ใหม่ซึ่งมีค่าใช้จ่ายสูง
จัดสรรบัฟเฟอร์ล่วงหน้าด้วยพารามิเตอร์ขนาดที่เลือกและตั้งค่า srcData เป็น null ดังนี้
// Only allocate texture backing once
if (!textureBufferAllocated) {
// Pre-allocate texture backing with pre-determined size.
gl.texImage2D(
/* target */ gl.TEXTURE_2D,
/* level */ 0,
/* internalformat */ gl.RGBA8,
/* width */ myElementWidth,
/* height */ myElementHeight,
/* border */ 0,
/* format */ gl.RGBA,
/* type */ gl.UNSIGNED_BYTE,
/* srcData */ null
);
textureBufferAllocated = true;
}
หากต้องการให้พื้นผิวตรงกับขนาดเลย์เอาต์ตามธรรมชาติขององค์ประกอบ HTML ให้ใช้ canvas.getElementImageDefaultSize() เพื่อดึงขนาดเริ่มต้นในพิกเซลตารางกริดของ Canvas ดังนี้
const { width, height } = canvas.getElementImageDefaultSize(myElement);
// Pre-allocate texture backing. Only do this once, or whenever the element
// changes size.
gl.texImage2D(
/* target */ gl.TEXTURE_2D,
/* level */ 0,
/* internalformat */ gl.RGBA8,
/* width */ Math.ceil(width),
/* height */ Math.ceil(height),
/* border */ 0,
/* format */ gl.RGBA,
/* type */ gl.UNSIGNED_BYTE,
/* srcData */ null
);
อัปโหลดภาพรวม DOM เป็นพื้นผิว
ขั้นตอนถัดไปคือการอัปโหลดองค์ประกอบ HTML ลงในพื้นผิวภายในลูปการแสดงผลหรือ Listener paint
canvas.onpaint = () => {
// 1. Pre-allocate texture backing first
// ...
// 2. Upload HTML snapshot into the WebGL texture
gl.texElementSubImage2D(
/* target */ gl.TEXTURE_2D,
/* level */ 0,
/* xoffset */ 0,
/* yoffset */ 0,
/* element */ myElement // or an ElementImage from `captureElementImage()`
);
// ...
};
ซิงค์เรขาคณิต
เบราว์เซอร์ไม่สามารถอนุมานโดยอัตโนมัติว่าพื้นผิวจะปรากฏที่ใดบนหน้าจอในบริบท 3 มิติ ซึ่งแตกต่างจากบริบท 2 มิติ คุณต้องจัดแนวการทดสอบตัวชี้ DOM และกรอบล้อมรอบการช่วยเหลือพิเศษให้สอดคล้องกับเมช 3 มิติด้วยตนเอง
โดยสร้าง DOMMatrix ที่แมปกล่องขอบเขตขององค์ประกอบกับตำแหน่งพิกเซลของ Canvas ที่แสดงผล แล้วใช้โดยใช้ updateElementGeometry() ดังนี้
canvas.addEventListener("paint", () => {
// 1. Upload fresh DOM snapshot to GPU texture
gl.bindTexture(gl.TEXTURE_2D, myTexture);
gl.texElementSubImage2D(gl.TEXTURE_2D, 0, 0, 0, myElement);
// 2. Draw your 3D scene
draw3DScene();
// 3. Construct the CSS-pixel transform mapping the element's
// border box to its drawn position on the canvas as needed
// (for example: scale and translate)
const canvasTransform = new DOMMatrix();
// scale X
canvasTransform.a = canvas.clientWidth / myElement.offsetWidth;
// scale Y
canvasTransform.d = canvas.clientHeight / myElement.offsetHeight;
// translate X (CSS px)
canvasTransform.e = 50;
// translate Y (CSS px)
canvasTransform.f = 100;
// 4. Update DOM position, accessibility focus rings, and pointer hit-testing
canvas.updateElementGeometry(myElement, {
canvasTransform: canvasTransform,
});
});
ขั้นตอนถัดไป
- ทำความเข้าใจแนวคิดทางเทคนิคหลักเบื้องหลัง HTML-in-Canvas
- ดูวิธีแสดงผล HTML ในบริบท 2 มิติ
- ดูวิธีแสดงผล HTML ใน WebGPU Canvas
- ดูข้อมูลเกี่ยวกับกลยุทธ์สำรอง
- แจ้งปัญหาใน GitHub เพื่อแชร์ความคิดเห็น
- ดูคอลเล็กชันเดโม HTML-in-Canvas โดยชุมชน