WebGL कैनवस में एचटीएमएल

WebGL कैनवस में एचटीएमएल रेंडर करने से, लाइव डीओएम सबट्री को डाइनैमिक जीपीयू टेक्स्चर के तौर पर इस्तेमाल किया जा सकता है. साथ ही, लाइव डीओएम पर शेडर इफ़ेक्ट लागू किए जा सकते हैं और इंटरैक्टिव एचटीएमएल को 3D सीन में इंटिग्रेट किया जा सकता है.

इस गाइड में, एचटीएमएल को WebGL कैनवस में रेंडर करने का तरीका बताया गया है. एपीआई की खास जानकारी में, HTML-in-Canvas के बारे में ज़्यादा जानें.

WebGL कैनवस में एचटीएमएल रेंडर करने के लिए, यह तरीका अपनाना होगा:

  1. अपना कैनवस तैयार करें. सही एट्रिब्यूट को डिक्लेयर करके सेट करें, ताकि ब्राउज़र को पता चल सके कि उसे एचटीएमएल को कैनवस में रेंडर करना है. यह सेटअप 2D, WebGL, और WebGPU कॉन्टेक्स्ट में एक जैसा होता है. कैनवस सेट अप करने और एचटीएमएल एलिमेंट को अलग-अलग ड्रॉ करने के लिए एलान करने का तरीका जानें.
  2. एचटीएमएल को टेक्सचर के तौर पर लागू करें:
    1. जीपीयू टेक्सचर स्टोरेज को पहले से तय करें.
    2. डीओएम स्नैपशॉट को टेक्स्चर के तौर पर अपलोड करें.
  3. डीओएम और पिक्सल को सिंक करना.

एचटीएमएल एलिमेंट को WebGL टेक्सचर के तौर पर ड्रॉ करना

WebGL में, एचटीएमएल एलिमेंट को texElementSubImage2D() का इस्तेमाल करके, जीपीयू पर 2D टेक्सचर के तौर पर अपलोड किया जाता है.

टेक्सचर स्टोरेज को पहले से तय करें

2D कैनवस, बैकिंग मेमोरी को अपने-आप मैनेज करता है. हालांकि, WebGL कॉन्टेक्स्ट के लिए, मेमोरी को साफ़ तौर पर मैनेज करना ज़रूरी है.

डीओएम पिक्सल अपलोड करने से पहले, आपको जीपीयू मेमोरी को पहले से तय करना होगा. इससे ब्राउज़र, सब-इमेज को तेज़ी से अपडेट कर पाता है. इसके लिए, जीपीयू मेमोरी को फिर से असाइन करने की ज़रूरत नहीं पड़ती.

चुने गए साइज़ पैरामीटर के साथ बफ़र को पहले से तय करें और 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;
}

टेक्सचर को एचटीएमएल एलिमेंट के नैचुरल लेआउट साइज़ से मैच करने के लिए, canvas.getElementImageDefaultSize() का इस्तेमाल करें. इससे कैनवस ग्रिड पिक्सल में इसका डिफ़ॉल्ट साइज़ वापस पाया जा सकता है:

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
);

डीओएम स्नैपशॉट को टेक्सचर के तौर पर अपलोड करना

अगले चरण में, एचटीएमएल एलिमेंट को अपने रेंडर लूप या 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()`
  );

  // ...
};

ज्यामिति को सिंक करना

2D कॉन्टेक्स्ट के उलट, ब्राउज़र 3D कॉन्टेक्स्ट में यह अपने-आप पता नहीं लगा सकता कि स्क्रीन पर टेक्सचर कहां दिखता है. आपको डीओएम हिट-टेस्टिंग और सुलभता बाउंडिंग बॉक्स को अपने 3D मेश के साथ मैन्युअल तरीके से अलाइन करना होगा.

ऐसा करने के लिए, एक DOMMatrix बनाएं, जो एलिमेंट के बॉर्डर बॉक्स को रेंडर किए गए कैनवस पिक्सल की जगह पर मैप करे. इसके बाद, 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,
  });
});

अगले चरण