HTML-in-Canvas API ช่วยให้แสดงผล DOM จริงภายในองค์ประกอบ Canvas ได้โดยตรง เมื่อใช้กับบริบทการแสดงผล 3 มิติ เช่น WebGL, WebGPU หรือ Three.js การเพิ่มแอตทริบิวต์ content="drawable" ลงใน Canvas และแอตทริบิวต์ drawable ลงในองค์ประกอบ HTML ที่สืบทอดมาจะช่วยให้องค์ประกอบเหล่านั้นแสดงผลในฉาก 3 มิติได้อย่างราบรื่น สิ่งสำคัญคือ เนื่องจากองค์ประกอบ HTML ยังคงเป็นส่วนหนึ่งของแผนผังเลย์เอาต์ DOM ที่ใช้งานอยู่ องค์ประกอบเหล่านี้จึงยังคงมีการโต้ตอบอย่างเต็มรูปแบบ ซึ่งช่วยให้ผู้ใช้คลิกปุ่ม เลือกข้อความ และทริกเกอร์สถานะโฟกัสได้โดยตรงโดยไม่ต้องใช้ Raycasting ที่ซับซ้อนหรือการจัดการเหตุการณ์ที่กำหนดเอง
วิธีการนำไปใช้งาน
WebGL และ WebGPU
เมื่อใช้ WebGL หรือ WebGPU ให้ทำตามขั้นตอนต่อไปนี้
ตรวจสอบว่าเบราว์เซอร์รองรับ HTML-in-Canvas หรือไม่ โดยทำดังนี้
if ('content' in HTMLCanvasElement.prototype) { // Use HTML in Canvas API } else { // Use fallback strategy }เริ่มต้น
<canvas>เพื่อรองรับองค์ประกอบ HTML ที่สืบทอดมาโดยเพิ่มแอตทริบิวต์content="drawable"ลงในองค์ประกอบ HTML<canvas>วางเนื้อหา HTML ไว้ภายในองค์ประกอบ<canvas>และเพิ่มแอตทริบิวต์drawableลงในทุกองค์ประกอบที่คุณวาด องค์ประกอบที่มีdrawableจะจับภาพแผนผังย่อยของตนเอง ยกเว้นองค์ประกอบสืบทอดที่ฝังอยู่ซึ่งเป็นdrawableด้วย<canvas id="canvas" content="drawable"> <div id="html-content" drawable></div> </canvas>ปรับขนาดตารางกริดของ Canvas ให้ตรงกับค่าตัวคูณมาตราส่วนของอุปกรณ์เพื่อป้องกันไม่ให้ภาพเบลอ โดยทำดังนี้
const observer = new ResizeObserver(([entry]) => { const dpc = entry.devicePixelContentBoxSize; canvas.width = dpc ? dpc[0].inlineSize : Math.round(entry.contentRect.width * window.devicePixelRatio); canvas.height = dpc ? dpc[0].blockSize : Math.round(entry.contentRect.height * window.devicePixelRatio); }); const supportsDevicePixelContentBox = typeof ResizeObserverEntry !== "undefined" && "devicePixelContentBoxSize" in ResizeObserverEntry.prototype; const options = supportsDevicePixelContentBox ? { box: "device-pixel-content-box" } : {}; observer.observe(canvas, options);แสดงผลเนื้อหา HTML เป็นพื้นผิวภายในเครื่องจัดการเหตุการณ์
canvas.onpaintคุณจะอัปโหลดองค์ประกอบได้หลังจากที่ Canvas แสดงผลแล้วเท่านั้น โดยเรียกใช้canvas.requestPaint()เพื่อขอเหตุการณ์paint
ปรับขนาดพื้นผิวจาก canvas.captureElementImage(element) width และ height อยู่ในพิกเซลตารางกริดของ Canvas (ที่เก็บข้อมูลสำรอง) ดังนั้นให้ปัดเศษขึ้นด้วย Math.ceil() captureElementImage() จะแสดงข้อผิดพลาดหากองค์ประกอบยังไม่มีบันทึกการแสดงผล: เรียกใช้ requestPaint() แล้วลองอีกครั้งในเหตุการณ์ paint ถัดไป
// Returns the element's size in canvas grid pixels, or null if the element
// has no paint record yet.
function getElementImageSize(canvas, element) {
let elementImage;
try {
elementImage = canvas.captureElementImage(element);
} catch (err) {
canvas.requestPaint(); // No paint record yet: retry on the next paint event.
return null;
}
const width = Math.ceil(elementImage.width);
const height = Math.ceil(elementImage.height);
elementImage.close();
return width > 0 && height > 0 ? { width, height } : null;
}
- ในบริบท WebGL ให้จัดสรรการสนับสนุนพื้นผิวก่อนโดยใช้เมธอด
texImage2Dข้อมูลโค้ดในคู่มือนี้ใช้บริบท WebGL 2 (canvas.getContext("webgl2")) จัดสรรพื้นที่เก็บข้อมูลพื้นผิวโดยเรียกใช้texImage2D()ด้วยnullแทนข้อมูลพิกเซล ซึ่งจะจองหน่วยความจำ GPU ตามขนาดและรูปแบบที่ระบุโดยไม่ต้องอัปโหลดพิกเซลใดๆ โดยทำตามกฎต่อไปนี้- ปรับขนาดพื้นผิวจาก
captureElementImage()ดังที่แสดงด้านบน - จัดสรรระดับ 0 เฉพาะในการอัปโหลดครั้งแรก หรือเมื่อขนาดมีการเปลี่ยนแปลง เนื่องจากการจัดสรรใหม่จะล้างพื้นผิว ใช้พื้นที่เก็บข้อมูลที่เปลี่ยนแปลงได้: พื้นที่เก็บข้อมูล
texStorage2D()ที่เปลี่ยนแปลงไม่ได้จะไม่สามารถปรับขนาดได้เมื่อองค์ประกอบเปลี่ยนขนาด
- ปรับขนาดพื้นผิวจาก
// Binds the texture, and allocates its storage on the first upload, and when
// the element size changes. `state` stores the allocated size.
function allocateElementTexture(gl, texture, state, width, height) {
gl.bindTexture(gl.TEXTURE_2D, texture);
if (state.width === width && state.height === height) return;
gl.texImage2D(
gl.TEXTURE_2D,
0, // Mipmap level
gl.RGBA8, // Internal format: 8 bits per RGBA channel
width, // Size in canvas grid pixels
height,
0, // Border: must be 0
gl.RGBA, // Format and type that match RGBA8
gl.UNSIGNED_BYTE,
null // null reserves GPU memory without uploading pixels
);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
state.width = width;
state.height = height;
}
const texture = gl.createTexture();
const textureState = { width: 0, height: 0 };
- จากนั้นในบริบท WebGL ให้แสดงผลเนื้อหา HTML เป็นพื้นผิวโดยใช้เมธอด
texElementSubImage2Dโดยทำตามกฎต่อไปนี้- ส่ง
{ width, height }ในการกำหนดค่า ซึ่งจะทำให้สำเนาเติมเต็มพื้นผิวที่จัดสรรไว้ ไม่ว่า Canvas จะปรับขนาดอย่างไรก็ตาม - จัดสรรพื้นผิวใหม่หากขนาดมีการเปลี่ยนแปลง ดังที่แสดงด้านบน
- ส่ง
// Uploads the element into the texture. Returns false if the element has no
// paint record yet. In that case, it's uploaded on the next paint event.
function uploadElementWebGL(gl, canvas, texture, element, state) {
const size = getElementImageSize(canvas, element);
if (!size) return false;
const { width, height } = size;
// Bind the texture, and reallocate it if the size changed (see above).
allocateElementTexture(gl, texture, state, width, height);
gl.texElementSubImage2D(gl.TEXTURE_2D, 0, 0, 0, element, { width, height });
return true;
}
canvas.onpaint = () => {
try {
uploadElementWebGL(gl, canvas, texture, uiElement, textureState);
} catch (err) {
console.error('texElementSubImage2D copy failed:', err);
}
};
- ในบริบท WebGPU ให้ใช้เมธอด
drawElementImageToTextureโดยทำตามกฎต่อไปนี้- สร้างพื้นผิวด้วยการใช้งาน
COPY_DSTและRENDER_ATTACHMENTและเพิ่มTEXTURE_BINDINGเพื่อสุ่มตัวอย่างในตัวปรับเฉดสี ระบบจะรายงานการใช้งานที่ไม่ถูกต้องเป็นข้อผิดพลาดในการตรวจสอบ WebGPU ไม่ใช่ข้อยกเว้น - ส่งขนาดพื้นผิวเป็น
sizeหากไม่มีsizeองค์ประกอบที่ใหญ่กว่าจะถูกตัดให้พอดีกับพื้นผิว เมื่อใช้sizeองค์ประกอบจะปรับขนาดให้พอดีกับพื้นที่ - ปรับขนาดพื้นผิว WebGPU ไม่ได้ สร้างพื้นผิวใหม่เมื่อขนาดองค์ประกอบเปลี่ยนแปลง และสร้างกลุ่มการเชื่อมโยงที่อ้างอิงพื้นผิวดังกล่าวอีกครั้ง
- สร้างพื้นผิวด้วยการใช้งาน
// WebGPU textures can't be resized. Create the texture once, and recreate it
// when the element size changes.
function ensureElementTexture(device, state, width, height) {
if (state.texture?.width === width && state.texture?.height === height) {
return state.texture;
}
state.texture?.destroy();
state.texture = device.createTexture({
size: { width, height },
format: "rgba8unorm",
usage:
GPUTextureUsage.TEXTURE_BINDING |
GPUTextureUsage.COPY_DST |
GPUTextureUsage.RENDER_ATTACHMENT,
});
return state.texture; // Recreate the bind groups that used the previous texture.
}
const textureState = { texture: null };
canvas.onpaint = () => {
const size = getElementImageSize(canvas, uiElement);
if (!size) return;
const previousTexture = textureState.texture;
const texture = ensureElementTexture(device, textureState, size.width, size.height);
if (texture !== previousTexture) {
// New texture: create, or rebuild, the bind groups that reference it.
}
try {
device.queue.drawElementImageToTexture({ source: uiElement }, { texture, size });
} catch (err) {
console.error('drawElementImageToTexture copy failed:', err);
}
};
เมื่อใช้ลูป requestAnimationFrame เพื่อแสดงผลฉาก ให้เรียกใช้ canvas.requestPaint() ภายในลูปเพื่อให้แน่ใจว่าเนื้อหา HTML แสดงผลใน Canvas event.changedElements แสดงรายการองค์ประกอบที่มีการเปลี่ยนแปลงการแสดงผล ตรวจสอบว่าคุณอัปโหลดพื้นผิวซ้ำเฉพาะในกรณีที่มีการอัปเดตองค์ประกอบ HTML ที่สืบทอดมา ดังนี้
function render() {
// Request to update the canvas
canvas.requestPaint();
requestAnimationFrame(render);
}
requestAnimationFrame(render);
canvas.onpaint = (event) => {
if (event.changedElements && event.changedElements.length > 0) {
// Update the texture as shown above
}
// Render the scene, and sync the element geometry as shown in step 5
};
- ซิงค์เรขาคณิตขององค์ประกอบ
คำนวณ DOMMatrix ที่แมปกล่องเส้นขอบขององค์ประกอบในหน่วยพิกเซล CSS กับ Canvas ในหน่วยพิกเซล CSS เบราว์เซอร์ต้องแมปจากพื้นที่พิกัด 3 มิติไปยังพื้นที่พิกัด CSS โดยใช้การเปลี่ยนรูปแบบวิวพอร์ต โดยทำดังนี้
- ปรับองค์ประกอบ HTML ให้เป็นมาตรฐาน องค์ประกอบ HTML มีขนาดเป็นพิกเซล (เช่น กว้าง 200 พิกเซล) อย่างไรก็ตาม WebGL มักจะถือว่าออบเจ็กต์เป็น "สี่เหลี่ยมจัตุรัสหน่วย" เช่น ตั้งแต่ -0.5 ถึง 0.5 หากไม่ปรับให้เป็นมาตรฐาน ปุ่มขนาด 200 พิกเซลจะดูใหญ่ขึ้น 200 เท่า ขั้นตอนนี้ยังพลิกแกน Y ด้วย เนื่องจากใน CSS ค่าบวกจะอยู่ด้านล่าง แต่ใน WebGL ค่าบวกจะอยู่ด้านบน
- แปลงเมทริกซ์ MVP ของ WebGL เป็นเมทริกซ์ DOM
- แมปกับวิวพอร์ต Canvas ขั้นตอนนี้คือระยะ "การปรับขนาดใหม่" ซึ่งจะยืดคณิตศาสตร์พื้นที่หน่วยนั้นกลับออกไปเพื่อให้ตรงกับขนาดพิกเซล CSS ขององค์ประกอบ
<canvas>บนหน้าจอ และพลิกแกน Y กลับ คำนวณการเปลี่ยนรูปแบบสุดท้าย คูณเมทริกซ์ตามลำดับ: Viewport * MVP * Normalization การรวมการเปลี่ยนรูปแบบทั้ง 3 แบบเข้าด้วยกันเป็นการเปลี่ยนรูปแบบสุดท้ายจะสร้าง "แผนที่" ที่บอกเบราว์เซอร์อย่างชัดเจนว่าองค์ประกอบ HTML นั้นควรอยู่ตรงไหนเพื่อให้สอดคล้องกับภาพวาด 3 มิติ เบราว์เซอร์จะทำการแบ่งมุมมอง
// Maps the element's border box (CSS pixels) to the canvas (CSS pixels), for a // quad that spans -0.5 to 0.5 in model space and is drawn with the `mvp` matrix. function computeCanvasTransform(canvas, element, mvp) { const width = element.offsetWidth; const height = element.offsetHeight; // 1. Normalize the HTML element (CSS pixels -> WebGL Model Space) const toGLModel = new DOMMatrix() // Scale pixels to 1 unit, flip Y (as in CSS it points down, and in WebGL it points up) .scale(1 / width, -1 / height, 1 / height) // Center the origin: (0,0) becomes (-width/2, -height/2) before scaling .translate(-width / 2, -height / 2); // 2. Convert WebGL MVP Matrix to DOM Matrix const mvpDOM = new DOMMatrix(Array.from(mvp)); // 3. Map to the canvas viewport, in CSS pixels const clipToCanvasViewport = new DOMMatrix() // Move center (0,0) to center of canvas .translate(canvas.clientWidth / 2, canvas.clientHeight / 2) // Scale normalized clip (-1..1) to viewport size, and flip Y back .scale(canvas.clientWidth / 2, -canvas.clientHeight / 2, canvas.clientHeight / 2); // 4. Multiply: (Clip -> Pixels) * (MVP) * (pixels -> unit square) return clipToCanvasViewport.multiply(mvpDOM).multiply(toGLModel); }
จากนั้นส่งผ่านการเปลี่ยนรูปแบบไปยัง canvas.updateElementGeometry() เป็น canvasTransform ซึ่งจะย้ายองค์ประกอบ HTML ไปอยู่ด้านบนพิกเซลที่แสดงผลโดยตรง ซึ่งจะช่วยให้มั่นใจได้ว่าเมื่อผู้ใช้คลิกปุ่มหรือเลือกข้อความ ผู้ใช้จะกดองค์ประกอบ HTML จริงๆ เบราว์เซอร์ยังใช้การเปลี่ยนรูปแบบสำหรับขอบเขตการช่วยเหลือพิเศษขององค์ประกอบด้วย เช่น สำหรับวงแหวนโฟกัสของโปรแกรมอ่านหน้าจอ
canvas.updateElementGeometry(targetHTMLElement, {
canvasTransform: computeCanvasTransform(canvas, targetHTMLElement, htmlElementMVP),
});
ใช้ตัวเลือกเหล่านี้เพื่อควบคุมการทดสอบตัวชี้
- การเรียก
updateElementGeometry()แต่ละครั้งจะย้ายองค์ประกอบไปยังด้านบนของลำดับการทดสอบตัวชี้ ส่งบอลให้{ preserveHitTestOrder: true }เพื่อรักษาตำแหน่งไว้ - เรียกใช้
canvas.clearElementGeometry(element)เพื่อนำองค์ประกอบออกจากการทดสอบตัวชี้ เช่น เมื่อคุณซ่อนองค์ประกอบ
Three.js
ตรวจสอบว่าเบราว์เซอร์รองรับ HTML-in-Canvas หรือไม่ โดยทำดังนี้
if ('content' in HTMLCanvasElement.prototype) { // Use HTML in Canvas API } else { // Use fallback strategy }สร้างเรขาคณิตและวัสดุที่กำหนดเองสำหรับเนื้อหา HTML
ส่งองค์ประกอบ DOM ไปยัง THREE.HTMLTexture โปรแกรมแสดงผลจะเพิ่มองค์ประกอบลงใน Canvas และตั้งค่าแอตทริบิวต์ที่จำเป็น ดังนี้
material.map = new THREE.HTMLTexture(element); mesh = new THREE.Mesh( geometry, material ); scene.add( mesh );ลงทะเบียน Mesh ด้วย
InteractionManagerเพื่อทำให้องค์ประกอบ HTML เป็นแบบอินเทอร์แอกทีฟ โดยจะจัดแนวองค์ประกอบให้ตรงกับ Mesh และซิงค์เรขาคณิตขององค์ประกอบกับ Canvas เพื่อให้การคลิกและการเลือกข้อความตรงกับองค์ประกอบ HTML จริง เรียกinteractions.update()ในลูปภาพเคลื่อนไหวก่อนแสดงผล:
import { InteractionManager } from 'three/addons/interaction/InteractionManager.js';
const interactions = new InteractionManager();
interactions.connect( renderer, camera );
interactions.add( mesh );
// In the animation loop
interactions.update();
renderer.render( scene, camera );
โค้ดตัวอย่าง
Canvas ของ WebGL
<canvas id="canvas" content="drawable" style="width: 400px; height: 400px;">
<div id="ui-element" drawable>
<p>WebGL UI Element</p>
<button>Action</button>
</div>
</canvas>
<script>
const canvas = document.getElementById("canvas");
const gl = canvas.getContext("webgl2");
const uiElement = document.getElementById("ui-element");
// getElementImageSize(), allocateElementTexture(), and uploadElementWebGL()
// are defined in step 4.
// computeCanvasTransform() is defined in step 5.
// Setup WebGL texture...
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
const textureState = { width: 0, height: 0 };
canvas.onpaint = () => {
// 1. Update texture with HTML content
try {
uploadElementWebGL(gl, canvas, texture, uiElement, textureState);
} catch (err) {
console.error('texElementSubImage2D copy failed:', err);
}
// ... Render your 3D scene here, calculating htmlElementMVP matrix ...
// 2. Sync DOM position, hit testing, and accessibility bounds with 3D scene
canvas.updateElementGeometry(uiElement, {
canvasTransform: computeCanvasTransform(canvas, uiElement, htmlElementMVP),
});
};
</script>
WebGPU Canvas
<canvas id="canvas" content="drawable" style="width: 400px; height: 400px;">
<div id="ui-element" drawable>
<p>WebGPU UI Element</p>
</div>
</canvas>
<script>
const canvas = document.getElementById("canvas");
const context = canvas.getContext("webgpu");
const uiElement = document.getElementById("ui-element");
// getElementImageSize() and ensureElementTexture() are defined in step 4.
// computeCanvasTransform() is defined in step 5.
// Setup WebGPU...
// const device = ...
const textureState = { texture: null };
canvas.onpaint = () => {
// 1. Copy HTML content to a texture that matches the element size
const size = getElementImageSize(canvas, uiElement);
if (size) {
const previousTexture = textureState.texture;
const texture = ensureElementTexture(device, textureState, size.width, size.height);
if (texture !== previousTexture) {
// New texture: create, or rebuild, the bind groups that reference it.
}
try {
device.queue.drawElementImageToTexture({ source: uiElement }, { texture, size });
} catch (err) {
console.error('drawElementImageToTexture copy failed:', err);
}
}
// ... Render your 3D scene here, calculating htmlElementMVP matrix ...
// 2. Sync DOM position, hit testing, and accessibility bounds (same matrix math as WebGL)
canvas.updateElementGeometry(uiElement, {
canvasTransform: computeCanvasTransform(canvas, uiElement, htmlElementMVP),
});
};
</script>
Three.js
// 1. Initialize Three.js camera, scene, renderer, mesh, interactions;
// 2. Ensure HTML-in-Canvas feature support
if (!('content' in HTMLCanvasElement.prototype)) {
// Use a fallback strategy
}
// 3. Initialize the source HTML DOM element
const element = document.createElement('div');
element.innerHTML = '<h1>Hello World</h1>';
// 4. Create geometry and material
const geometry = new RoundedBoxGeometry( 100, 100, 100, 10, 10 );
const material = new THREE.MeshStandardMaterial( { roughness: 0, metalness: 0.5 } );
// 5. Pass the DOM element into THREE.HTMLTexture
material.map = new THREE.HTMLTexture(element);
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
// 6. Make the HTML element interactive
interactions = new InteractionManager();
interactions.connect( renderer, camera );
interactions.add( mesh );
// 7. Render Loop
function animate() {
// Keep the HTML element aligned with the mesh, so it receives input
interactions.update();
renderer.render(scene, camera);
}
แนวทางปฏิบัติแนะนำ
- จำเป็น: ตรวจสอบการรองรับเบราว์เซอร์สำหรับ HTML-in-Canvas API ก่อนใช้งาน
- บังคับ: เมื่อใช้ WebGL หรือ WebGPU ให้เพิ่มแอตทริบิวต์
content="drawable"ลงในองค์ประกอบ<canvas>เสมอ - จำเป็น: เมื่อใช้ WebGL หรือ WebGPU ให้เพิ่มแอตทริบิวต์
drawableลงในทุกองค์ประกอบที่คุณวาด รวมถึงองค์ประกอบย่อยโดยตรงของ Canvas - บังคับ: เมื่อใช้ WebGL หรือ WebGPU ให้ใช้เครื่องจัดการเหตุการณ์
onpaintเพื่อแสดงผลเนื้อหา HTML ไปยัง Canvas - บังคับ: เมื่อใช้ WebGL ให้จัดสรรบัฟเฟอร์พื้นผิวล่วงหน้าด้วย
texImage2D()1 ครั้ง (เมื่อเริ่มต้นหรือเมื่อขนาดองค์ประกอบเปลี่ยนแปลง) จัดสรรพื้นผิวใหม่เฉพาะเมื่อขนาดมีการเปลี่ยนแปลง และตั้งค่าTEXTURE_MIN_FILTERเป็นLINEAR - บังคับ: เมื่อใช้ WebGL ให้ใช้เมธอด
texElementSubImage2Dเพื่อแสดงผลเนื้อหา HTML เป็นพื้นผิวที่คุณจัดสรรไว้ล่วงหน้าด้วยtexImage2D()ซึ่งมีขนาดตั้งแต่captureElementImage() - บังคับ: เมื่อใช้ WebGPU ให้ใช้เมธอด
drawElementImageToTextureเพื่อแสดงผลเนื้อหา HTML ไปยัง Canvas ปรับขนาดพื้นผิวจากcaptureElementImage()และสร้างใหม่เฉพาะเมื่อขนาดมีการเปลี่ยนแปลง สร้างพื้นผิวด้วยการใช้งานCOPY_DSTและRENDER_ATTACHMENTและส่งขนาดพื้นผิวเป็นsize - บังคับ: เมื่อใช้ WebGL หรือ WebGPU ให้ซิงค์เรขาคณิตขององค์ประกอบ HTML กับเนื้อหาที่แสดงผลโดยเรียกใช้
canvas.updateElementGeometry(element, { canvasTransform }) - จำเป็น: เมื่อใช้ Three.js ให้ลงทะเบียน Mesh ด้วย
InteractionManagerและเรียกใช้interactions.update()ในลูปภาพเคลื่อนไหว เพื่อให้องค์ประกอบ HTML ได้รับอินพุต - บังคับ: สังเกตขนาดหน้าจอและอัปเดตขนาด Canvas ให้ตรงกับพิกเซลของอุปกรณ์ เช่น โดยใช้
ResizeObserver - อย่าฝังเนื้อหาแบบข้ามต้นทางใน Canvas เนื่องจากระบบไม่รองรับ
- อย่าเริ่มต้น
ResizeObserverภายในเครื่องจัดการเหตุการณ์onpaintเนื่องจากอาจทำให้หน่วยความจำรั่วไหล
กลยุทธ์สำรอง
ปัจจุบันเบราว์เซอร์ที่ทันสมัยบางรุ่นยังไม่รองรับ HTML-in-Canvas API ดังนั้นจึงมักต้องใช้กลยุทธ์สำรอง
อย่างไรก็ตาม เนื่องจาก API นี้มีประโยชน์ด้านประสิทธิภาพที่ดีขึ้น จึงควรใช้ HTML-in-Canvas หากเบราว์เซอร์รองรับ
กลยุทธ์สำรองจะขึ้นอยู่กับกรณีการใช้งาน ตัวอย่างเช่น สำหรับเนื้อหา HTML แบบอินเทอร์แอกทีฟใน Canvas หากระบบไม่รองรับ HTML-in-Canvas ให้วางเนื้อหา HTML ไว้ด้านบนของ Canvas โดยใช้ CSS
Polyfill ของ HTML-in-Canvas
ใช้สคริปต์ Polyfill ต่อไปนี้เพื่อเลียนแบบ HTML-in-Canvas API ในเบราว์เซอร์ที่ไม่รองรับ
ติดตั้งหรือฝังไลบรารีโดยทำดังนี้
# Install npm install three-html-render# Embed <script src="https://cdn.jsdelivr.net/npm/three-html-render/dist/polyfill.js"></script>เรียกใช้เมธอด
installHtmlInCanvasPolyfill()เพื่อแปล HTML-in-Canvas