कैनवस कॉन्टेंट को ब्राउज़र की सुविधाओं के लिए उपलब्ध कराएं

वेब सुविधाएं: कैनवस में एचटीएमएल

सामान्य <canvas> कॉन्टेंट, ब्राउज़र की सुविधाओं के लिए उपलब्ध नहीं होता. जैसे, स्क्रीन रीडर, इंडेक्स करना, अनुवाद करने वाले टूल, सुलभता से जुड़े सहायक टूल, पेज पर ढूंढना, प्रिंट करना वगैरह. HTML in canvas की मदद से, रीयल डीओएम को सीधे कैनवस एलिमेंट में रेंडर किया जा सकता है. <canvas> एचटीएमएल एलिमेंट में content="drawable" एट्रिब्यूट जोड़ने से, उसके डिसेंडेंट एचटीएमएल एलिमेंट लेआउट हो जाते हैं. साथ ही, drawable एट्रिब्यूट उन एलिमेंट को मार्क करता है जिन्हें कैनवस के रेंडरिंग कॉन्टेक्स्ट में रेंडर किया जा सकता है. इसका इस्तेमाल, कैनवस में टेक्स्ट को स्टाइल करने और लेआउट करने के लिए किया जा सकता है. साथ ही, कैनवस के कॉन्टेंट को ब्राउज़र की सुविधाओं (जैसे, सुलभता, अनुवाद या पेज पर ढूंढें) के लिए एक्सपोज़ किया जा सकता है. इसके अलावा, एचटीएमएल पर 2D और 3D इफ़ेक्ट लागू किए जा सकते हैं.

इन्हें कैसे लागू करें

  1. देखें कि ब्राउज़र में HTML-in-Canvas की सुविधा काम करती है या नहीं:

    if ('content' in HTMLCanvasElement.prototype) {
      // Use HTML in Canvas API
    } else {
      // Use fallback strategy
    }
    
  2. <canvas> एचटीएमएल एलिमेंट में content="drawable" एट्रिब्यूट जोड़ें.

  3. अपने एचटीएमएल कॉन्टेंट को <canvas> एलिमेंट के अंदर रखें. साथ ही, ड्रॉ किए जाने वाले हर एलिमेंट में drawable एट्रिब्यूट जोड़ें. drawable वाला एलिमेंट, अपने सबट्री को कैप्चर करता है. हालांकि, यह नेस्ट किए गए उन डिसेंडेंट को कैप्चर नहीं करता जो drawable भी हैं.

    <canvas id="canvas" content="drawable">
      <div id="html-content" drawable></div>
    </canvas>
    
  4. धुंधलेपन से बचने के लिए, अपने कैनवस ग्रिड को डिवाइस के स्केल फ़ैक्टर के हिसाब से स्केल करें:

    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);
    
  5. canvas.onpaint इवेंट हैंडलर में, एचटीएमएल कॉन्टेंट को कैनवस पर रेंडर करें. कैनवस पर पेंट होने के बाद ही किसी एलिमेंट को ड्रॉ किया जा सकता है: paint इवेंट का अनुरोध करने के लिए, canvas.requestPaint() को कॉल करें.

  • 2D कॉन्टेक्स्ट में, drawElementImage वाला तरीका इस्तेमाल करें. यह सीएसएस ट्रांसफ़ॉर्म से पहले, एलिमेंट के बॉर्डर बॉक्स से शुरू होने वाले drawable एलिमेंट और उसके ड्रॉ किए जा सकने वाले सबट्री का आखिरी स्नैपशॉट ड्रॉ करता है:
canvas.onpaint = () => {
  ctx.reset();
  // Draw the form element at x:0, y:0
  ctx.drawElementImage(form_element, 0, 0);
};
  • WebGL और WebGPU कॉन्टेक्स्ट में, एलिमेंट को टेक्सचर में कॉपी किया जाता है. canvas.captureElementImage(element) से टेक्स्चर का साइज़ तय करें. इसके width और height, कैनवस ग्रिड (बैकिंग स्टोर) पिक्सल में होते हैं. इसलिए, उन्हें 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")) का इस्तेमाल करते हैं. पिक्सल डेटा के बजाय null के साथ texImage2D() को कॉल करके, टेक्सचर स्टोरेज तय करें. इससे, बिना कोई पिक्सल अपलोड किए, दिए गए साइज़ और फ़ॉर्मैट की जीपीयू मेमोरी रिज़र्व हो जाती है. इन नियमों का पालन करें:
    • 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 कॉन्टेक्स्ट में, texElementSubImage2D तरीके का इस्तेमाल करके एचटीएमएल कॉन्टेंट को टेक्सचर में रेंडर करें. इन नियमों का पालन करें:
    • कॉन्फ़िगरेशन में { width, height } पास करें. इससे कॉपी, तय किए गए टेक्सचर को भर देती है. भले ही, कैनवस को किसी भी तरह से स्केल किया गया हो.
    • अगर साइज़ बदल गया है, तो टेक्सचर को फिर से असाइन करें, जैसा कि ऊपर दिखाया गया है.
// 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() को कॉल करें. इससे यह पक्का किया जा सकेगा कि एचटीएमएल कॉन्टेंट, कैनवस पर रेंडर हो. event.changedElements उन एलिमेंट की सूची दिखाता है जिनकी रेंडरिंग में बदलाव हुआ है. यह पक्का करें कि अगर डिसेंडेंट एचटीएमएल एलिमेंट में कोई अपडेट हुआ है, तो सिर्फ़ एलिमेंट को फिर से ड्रॉ करें या उसके टेक्सचर को फिर से अपलोड करें:

function render() {
  // Request to update the canvas
  canvas.requestPaint();
  requestAnimationFrame(render);
}
requestAnimationFrame(render);

canvas.onpaint = (event) => {
  if (event.changedElements && event.changedElements.length > 0) {
    // Redraw the element, or update its texture, as shown above
  }
  // In WebGL and WebGPU, render the scene, and sync the element geometry as shown in step 6
};
  1. एलिमेंट की ज्यामिति को सिंक करें.

ब्राउज़र को यह पता होना चाहिए कि एचटीएमएल एलिमेंट कहां बनाया गया है, ताकि उसकी डीओएम पोज़िशन, बनाए गए पिक्सल से मैच हो सके. क्लिक और टेक्स्ट चुनने के लिए हिट टेस्टिंग और सुलभता, इस ज्यामिति का इस्तेमाल करती है: ऐसा drawable एलिमेंट जिसकी ज्यामिति अपडेट नहीं की गई है वह अब भी सुलभता ट्री में दिखता है, लेकिन ज्यामिति की जानकारी के बिना. कैनवस सिर्फ़ उन एलिमेंट का हिट टेस्ट करता है जिन्हें 2D drawElementImage() तरीके से बनाया गया है या updateElementGeometry() के साथ रजिस्टर किया गया है.

  • 2D कॉन्टेक्स्ट के मामले में, ब्राउज़र एलिमेंट को अपने-आप सिंक करता है. drawElementImage(), डीओएम हिट-टेस्ट की सीमाओं और स्क्रीन रीडर के फ़ोकस रिंग को ड्रॉ किए गए कोऑर्डिनेट के साथ अलाइन करता है. इसलिए, आपको style.transform सेट करने की ज़रूरत नहीं है. ज्यामिति को मैन्युअल तरीके से मैनेज करने के लिए, उदाहरण के लिए, जब एक ही एलिमेंट को एक से ज़्यादा बार ड्रॉ किया जाता है, तो { preserveElementGeometry: true } को drawElementImage() पर पास करें और canvas.updateElementGeometry() के साथ ट्रांसफ़ॉर्म लागू करें.

  • WebGL या WebGPU के साथ 3D केस के लिए, कैनवस यह नहीं बता सकता कि एचटीएमएल एलिमेंट कहां बनाया गया है. इसलिए, आपको यह बताना होगा. DOMMatrix की गिनती करें, जो एलिमेंट के बॉर्डर बॉक्स को सीएसएस पिक्सल में, कैनवस पर सीएसएस पिक्सल में मैप करता है. ब्राउज़र को व्यूपोर्ट ट्रांसफ़ॉर्म का इस्तेमाल करके, 3D कोऑर्डिनेट स्पेस से सीएसएस कोऑर्डिनेट स्पेस में मैप करना होगा. इसके लिए, यह तरीका अपनाएं:

    • एचटीएमएल एलिमेंट को सामान्य बनाएं. एचटीएमएल एलिमेंट का साइज़, पिक्सल में तय किया जाता है. उदाहरण के लिए, 200 पिक्सल चौड़ा. हालांकि, WebGL आम तौर पर ऑब्जेक्ट को "यूनिट स्क्वेयर" के तौर पर ट्रीट करता है. उदाहरण के लिए, -0.5 से 0.5 तक. अगर आपने नॉर्मलाइज़ नहीं किया, तो आपका 200 पिक्सल का बटन 200 गुना बड़ा दिखेगा. यह चरण Y-ऐक्सिस को भी फ़्लिप करता है. ऐसा इसलिए, क्योंकि सीएसएस में, डाउन पॉज़िटिव होता है, लेकिन WebGL में, अप पॉज़िटिव होता है.
    • WebGL एमवीपी मैट्रिक्स को DOM मैट्रिक्स में बदलें.
    • कैनवस व्यूपोर्ट पर मैप करें. यह चरण "री-स्केलिंग" फ़ेज़ है: यह उस यूनिट-स्पेस मैथ को वापस स्ट्रेच करता है, ताकि स्क्रीन पर आपके <canvas> एलिमेंट के सीएसएस पिक्सल डाइमेंशन से मैच किया जा सके. साथ ही, Y-ऐक्सिस को वापस फ़्लिप करता है.
    • फ़ाइनल ट्रांसफ़ॉर्म का हिसाब लगाएं. मैट्रिक्स को इस क्रम में गुणा करें: व्यूपोर्ट * एमवीपी * नॉर्मलाइज़ेशन. इन दोनों को एक फ़ाइनल ट्रांसफ़ॉर्म में जोड़ने से एक "मैप" बनता है. इससे ब्राउज़र को पता चलता है कि एचटीएमएल एलिमेंट को कहां रखना है, ताकि वह 3D ड्रॉइंग के साथ अलाइन हो सके. ब्राउज़र, पर्सपेक्टिव डिवाइड की प्रोसेस को पूरा करता है.
    // 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 के तौर पर पास करें. इससे एचटीएमएल एलिमेंट, रेंडर किए गए पिक्सल के ठीक ऊपर आ जाता है. इससे यह पक्का होता है कि जब कोई उपयोगकर्ता किसी बटन पर क्लिक करता है या टेक्स्ट चुनता है, तो वह असल एचटीएमएल एलिमेंट पर ही क्लिक करता है. ब्राउज़र, एलिमेंट की सुलभता सीमाओं के लिए भी ट्रांसफ़ॉर्म का इस्तेमाल करता है. उदाहरण के लिए, स्क्रीन रीडर की फ़ोकस रिंग के लिए:

  canvas.updateElementGeometry(targetHTMLElement, {
    canvasTransform: computeCanvasTransform(canvas, targetHTMLElement, htmlElementMVP),
  });

हिट टेस्टिंग को कंट्रोल करने के लिए, इन विकल्पों का इस्तेमाल करें:

  • updateElementGeometry() को कॉल करने पर, एलिमेंट हिट-टेस्टिंग ऑर्डर में सबसे ऊपर चला जाता है. { preserveHitTestOrder: true } को पास करें, ताकि वह अपनी पोज़िशन बनाए रखे.
  • हिट टेस्टिंग से किसी एलिमेंट को हटाने के लिए, canvas.clearElementGeometry(element) को कॉल करें. उदाहरण के लिए, जब उसे छिपाया जाता है.

कोड का उदाहरण

2D कैनवस

<canvas id="canvas" content="drawable" style="width: 400px; height: 200px;">
  <div id="ui-element" drawable>
    <p>
      This text is rendered inside the canvas but is present in the DOM tree.
    </p>
    <input type="email" name="email" placeholder="enter your email" />
    <button type="button">Submit</button>
  </div>
</canvas>

<script>
  const canvas = document.getElementById("canvas");
  const ctx = canvas.getContext("2d");
  const uiElement = document.getElementById("ui-element");

  canvas.onpaint = () => {
    ctx.reset();
    // Draw the HTML element at x:0, y:0. The browser syncs the DOM location
    // with the drawn location.
    ctx.drawElementImage(uiElement, 0, 0);
  };

  // Handle resizing to match device pixels
  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);
    canvas.requestPaint();
  });

  const supportsDevicePixelContentBox =
    typeof ResizeObserverEntry !== "undefined" &&
    "devicePixelContentBoxSize" in ResizeObserverEntry.prototype;
  const options = supportsDevicePixelContentBox
    ? { box: "device-pixel-content-box" }
    : {};
  observer.observe(canvas, options);
</script>

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 5.
  // computeCanvasTransform() is defined in step 6.

  // 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 5.
  // computeCanvasTransform() is defined in step 6.

  // 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>

सबसे सही तरीके

  • ज़रूरी: HTML-in-Canvas API का इस्तेमाल करने से पहले, यह देख लें कि आपका ब्राउज़र इसके साथ काम करता है या नहीं.
  • ज़रूरी: <canvas> एलिमेंट में हमेशा content="drawable" एट्रिब्यूट जोड़ें.
  • ज़रूरी: ड्रॉ किए जाने वाले हर एलिमेंट में drawable एट्रिब्यूट जोड़ें. इसमें कैनवस के डायरेक्ट चाइल्ड एलिमेंट भी शामिल हैं.
  • ज़रूरी: कैनवस पर एचटीएमएल कॉन्टेंट रेंडर करने के लिए, onpaint इवेंट हैंडलर का इस्तेमाल करें.
  • ज़रूरी: एचटीएमएल कॉन्टेंट को कैनवस पर रेंडर करने के लिए, 2D में drawElementImage तरीके का इस्तेमाल करें या WebGPU में drawElementImageToTexture का इस्तेमाल करें.
  • ज़रूरी: WebGL में, texImage2D() के साथ टेक्सचर बफ़र को पहले से तय करें. ऐसा सिर्फ़ एक बार करें (जब इसे शुरू किया जाए या एलिमेंट का साइज़ बदला जाए). टेक्सचर को सिर्फ़ तब फिर से असाइन करें, जब साइज़ में बदलाव हो. साथ ही, TEXTURE_MIN_FILTER को LINEAR पर सेट करें.
  • ज़रूरी: WebGL में, एचटीएमएल कॉन्टेंट को टेक्सचर में रेंडर करने के लिए, texElementSubImage2D तरीके का इस्तेमाल करें. इसके लिए, पहले से तय किए गए texImage2D() का इस्तेमाल करें. इसका साइज़ captureElementImage() से तय करें.
  • ज़रूरी: WebGPU में, टेक्सचर का साइज़ captureElementImage() से तय करें. साथ ही, इसे सिर्फ़ तब फिर से बनाएं, जब साइज़ में बदलाव हो. COPY_DST और RENDER_ATTACHMENT के इस्तेमाल से टेक्सचर बनाएं. साथ ही, टेक्सचर का साइज़ size के तौर पर पास करें.
  • ज़रूरी: एचटीएमएल एलिमेंट की ज्यामिति को रेंडर किए गए कॉन्टेंट के साथ सिंक करें. 2D में, drawElementImage यह काम अपने-आप करता है. WebGL और WebGPU में, canvas.updateElementGeometry(element, { canvasTransform }) को कॉल करें.
  • ज़रूरी: स्क्रीन का साइज़ देखने के लिए, ResizeObserver का इस्तेमाल करें. साथ ही, कैनवस के साइज़ को डिवाइस के पिक्सल के हिसाब से अपडेट करें.
  • कैनवस में क्रॉस-ऑरिजिन कॉन्टेंट को एंबेड न करें, क्योंकि यह काम नहीं करता.
  • ResizeObserver को onpaint इवेंट हैंडलर में शुरू न करें, क्योंकि इससे मेमोरी लीक हो सकती है.

फ़ॉलबैक रणनीतियां

फ़िलहाल, HTML-in-Canvas API सभी मॉडर्न ब्राउज़र के साथ काम नहीं करता. इसलिए, आम तौर पर फ़ॉलबैक रणनीति की ज़रूरत होती है.

हालांकि, इस एपीआई की बेहतर परफ़ॉर्मेंस को देखते हुए, अगर ब्राउज़र पर HTML-in-Canvas काम करता है, तो इसका इस्तेमाल किया जाना चाहिए.

फ़ॉलबैक की रणनीति, इस्तेमाल के उदाहरण पर निर्भर करती है. उदाहरण के लिए, कैनवस में इंटरैक्टिव एचटीएमएल कॉन्टेंट के लिए, अगर HTML-in-Canvas काम नहीं करता है, तो सीएसएस का इस्तेमाल करके एचटीएमएल कॉन्टेंट को कैनवस के सबसे ऊपर रखें.

HTML-in-Canvas polyfills

HTML-in-Canvas API के साथ काम न करने वाले ब्राउज़र में, इस एपीआई की नकल करने के लिए, यहां दी गई polyfill स्क्रिप्ट का इस्तेमाल करें.

  1. लाइब्रेरी को इंस्टॉल या एंबेड करें:

    # Install
    npm install three-html-render
    
    # Embed
    <script src="https://cdn.jsdelivr.net/npm/three-html-render/dist/polyfill.js"></script>
    
  2. HTML-in-Canvas का अनुवाद करने के लिए, installHtmlInCanvasPolyfill() तरीका इस्तेमाल करें.