HTML-in-Canvas से जुड़े अपडेट: बेहतर Web API की ओर बढ़ना

Chrome के वर्शन 150 और 155 में, HTML-in-Canvas API में कई बदलाव किए गए हैं. इन बदलावों में, कम्यूनिटी और स्टैंडर्ड के फ़ीडबैक को ध्यान में रखा गया है. इनका मकसद, एपीआई के इस्तेमाल को आसान बनाना है. इस ब्लॉग पोस्ट में, बदलावों के बारे में बताया गया है. साथ ही, यह भी बताया गया है कि यह कैसे पक्का किया जा सकता है कि आपने टैग को अपडेट कर लिया है.

इन अपडेट में, एट्रिब्यूट और तरीकों के नाम बदलना, टेक्सचर मेमोरी को पहले से तय करना, और DOM सिंक्रनाइज़ेशन मॉडल को अपडेट करना शामिल है. इसके अलावा, HTML-in-Canvas के ऑरिजिन ट्रायल की अवधि को अब बढ़ा दिया गया है. यहां बताया गया है कि क्या-क्या बदलाव किए जा रहे हैं, हम ऐसा क्यों कर रहे हैं, और अपने कोडबेस को कैसे अपडेट करें.

Chrome 150 में हुए बदलाव

Chrome 150 में, हमने WebGL और WebGPU, दोनों के लिए आर्ग्युमेंट सिग्नेचर में बदलाव किया है. इससे, एक ही तरह के आर्ग्युमेंट को बार-बार इस्तेमाल करने की ज़रूरत नहीं पड़ती. साथ ही, यह आधुनिक ग्राफ़िक्स के नियमों के मुताबिक है.

WebGL

हमने texElementImage2D से गैर-ज़रूरी आर्ग्युमेंट (level, srcFormat, destType) हटा दिए हैं. ज़्यादा जानकारी के लिए, WebGL से जुड़ी चर्चा देखें:

// Old implementation (Chrome < 150)
const level = 0;
const internalFormat = gl.RGBA;
const srcFormat = gl.RGBA;
const destType = gl.UNSIGNED_BYTE;

gl.texElementImage2D(
  gl.TEXTURE_2D,
  level,
  internalFormat,
  srcFormat,
  destType,
  element
);

// New implementation (from Chrome 150)
const internalFormat = gl.RGBA8;
gl.texElementImage2D(gl.TEXTURE_2D, internalFormat, element);

WebGPU

हमने copyElementImageToTexture पैरामीटर को sourceDict और destDict ऑब्जेक्ट में स्टैंडर्ड किया है. इसके बारे में जानने के लिए, GPUWeb PR#6250 देखें:

// Old implementation (Chrome < 150)
GPUQueue.copyElementImageToTexture(
  element,
  width,
  height,
  { texture: texture }
);

// New implementation (from Chrome 150)
const sourceDict = { source: element };
const destDict = {
  destination: { texture: texture },
  width: width,
  height: height
};

GPUQueue.copyElementImageToTexture(sourceDict, destDict);

Chrome 155 में होने वाले बदलाव

Chrome 155 में, डेवलपर के सुझावों के आधार पर और सुधार किए गए हैं. हम तरीकों के नाम अपडेट कर रहे हैं. इसके लिए, टेक्सचर मेमोरी को पहले से ही असाइन करना ज़रूरी है. साथ ही, हम जटिल डीओएम सबट्री के साथ काम करने और डीओएम सिंक्रनाइज़ेशन को अलग करने की सुविधा दे रहे हैं.

WebGPU

WebGPU तरीके का नाम copyElementImageToTexture से बदलकर drawElementImageToTexture कर दिया गया है. नाम बदलने के साथ-साथ, पैरामीटर के कोऑर्डिनेट (sourceX, sourceWidth) बढ़ाए जाते हैं. साथ ही, डेस्टिनेशन की सीमाओं को स्टैंडर्ड size (GPUExtent3D) ऑब्जेक्ट में ग्रुप किया जाता है:

// BEFORE (Chrome 150)
const sourceDict = {
  source: myElement,
  sx: 0,
  sy: 0,
  swidth: 100,
  sheight: 100
};
const destDict = {
  destination: { texture: myTexture },
  width: 300,
  height: 200
};

queue.copyElementImageToTexture(sourceDict, destDict);

// AFTER (Chrome 155+)
const sourceDict = {
  source: myElement,
  sourceX: 0,
  sourceY: 0,
  sourceWidth: 100,
  sourceHeight: 100
};
const destDict = {
  texture: myTexture,
  size: { width: 300, height: 200 }
};

queue.drawElementImageToTexture(sourceDict, destDict);

WebGL

HTML-in-Canvas के लिए WebGL में तीन तरह के बदलाव किए गए हैं:

  • तरीके का नाम texElementImage2D से बदलकर texElementSubImage2D हो जाता है.`
  • इस तरीके के सिग्नेचर में बदलाव होता है. सबसे अहम बात यह है कि यह xoffset और yoffset आर्ग्युमेंट जोड़ता है, ताकि एलिमेंट को डेस्टिनेशन टेक्सचर में किसी ऑफ़सेट पर ड्रा करने की अनुमति दी जा सके.
  • यह तरीका, डेस्टिनेशन टेक्सचर के लिए बफ़र स्टोरेज को अपने-आप असाइन नहीं करता. एपीआई का इस्तेमाल करने से पहले, स्टोरेज को साफ़ तौर पर असाइन किया जाना चाहिए. यह texSubImage2D के व्यवहार जैसा ही है.
// 1. Capture natural layout size of the element
const elementImage = canvas.captureElementImage(element);

// 2. Pre-allocate texture backing once (or when element resizes)
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(
  gl.TEXTURE_2D,
  0,
  gl.RGBA8,
  Math.ceil(elementImage.width),
  Math.ceil(elementImage.height),
  0,
  gl.RGBA,
  gl.UNSIGNED_BYTE,
  null // null reserves VRAM without uploading pixels
);

// 3. Upload DOM into pre-allocated VRAM
gl.texElementSubImage2D(
  gl.TEXTURE_2D,
  0,                  // level
  0,                  // xoffset
  0,                  // yoffset
  element             // pass DOM element
);

कैनवस एट्रिब्यूट और ड्रॉ किए जा सकने वाले चाइल्ड एलिमेंट

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

layoutsubtree का नाम बदलकर content="drawable" किया जा रहा है

एचटीएमएल एट्रिब्यूट के नाम रखने के नियमों के मुताबिक, <canvas> एलिमेंट पर मौजूद बूलियन layoutsubtree एट्रिब्यूट का नाम बदलकर content="drawable" कर दिया गया है. ज़्यादा जानकारी के लिए, WICG Issue #169 देखें.

वंशजों के लिए drawable एट्रिब्यूट

इससे पहले, कैनवस के सिर्फ़ चाइल्ड एलिमेंट रेंडर किए जाते थे. मार्कअप को फ़्लैट किए बिना, जटिल DOM हैरारकी के साथ काम करने के लिए, अब drawable एट्रिब्यूट को किसी भी डिसेंडेंट एलिमेंट में साफ़ तौर पर जोड़ा जा सकता है. ऐसा तब किया जाता है, जब आपको उसे स्वतंत्र रूप से ड्रा करना हो:

<!-- BEFORE -->
<canvas layoutsubtree>
  <div id="badge">
    <h2>Player Stats</h2>
    <button id="actionBtn">Equip</button>
  </div>
</canvas>

<!-- AFTER (Chrome 155+) -->
<canvas content="drawable">
  <!-- Subtree A (Body and heading) -->
  <div id="badge" drawable>
    <h2>Player Stats</h2>
    <!-- Subtree B (Excluded from Subtree A; drawn and animated independently) -->
    <button id="actionBtn" drawable>Equip</button>
  </div>
</canvas>

drawable वाला एलिमेंट, अपने पूरे सबट्री को कैप्चर करता है. हालांकि, इसमें नेस्ट किए गए डिसेंडेंट शामिल नहीं होते, जो drawable को भी तय करते हैं. इससे पैरंट कंटेनर और बटन जैसे चाइल्ड एलिमेंट को ऐनिमेट किया जा सकता है. साथ ही, उन्हें अलग-अलग ड्रॉ कॉल में बनाया जा सकता है.

हिट-टेस्टिंग सिंक करने की सुविधा

पहले, डेवलपर को ड्रॉइंग के तरीकों से मिली वैल्यू को कैप्चर करना होता था. इसके बाद, उसे element.style.transform में पाइप करना होता था. drawElementImage() तरीका अब शून्य दिखाता है. साथ ही, सिंक्रनाइज़ेशन, कॉन्टेक्स्ट पर निर्भर करता है.

2D कॉन्टेक्स्ट: अपने-आप सिंक होने की सुविधा

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

// BEFORE
const transform = ctx.drawElementImage(element, x, y);
element.style.transform = transform.toString();

// AFTER (Chrome 155+)
ctx.drawElementImage(element, x, y);
// No style update needed: position & hit-testing sync automatically

2D में ज्यामिति को मैन्युअल तरीके से मैनेज करने के लिए, { preserveElementGeometry: true } को drawElementImage() पर पास करें और canvas.updateElementGeometry() का इस्तेमाल करके ट्रांसफ़ॉर्म लागू करें.

3D कॉन्टेक्स्ट: साफ़ तौर पर बताया गया updateElementGeometry()

WebGL या WebGPU कॉन्टेक्स्ट में डीओएम को सिंक करने के लिए, DOMMatrix ट्रांसफ़ॉर्म बनाएं और इसे canvas.updateElementGeometry() में पास करें:

canvas.addEventListener('paint', () => {
  // 1. Upload element snapshot to GPU texture
  device.queue.drawElementImageToTexture({ source: element }, { texture });

  // 2. Render 3D scene...
  drawScene();

  // 3. Construct transform matrix as needed
  const canvasTransform = new DOMMatrix().translate(x, y);

  // 4. Update DOM hit-testing and accessibility bounding boxes
  canvas.updateElementGeometry(element, { canvasTransform });
});

अलग-अलग वर्शन के साथ काम करने की सुविधा

अगर ट्रांज़िशन पीरियड के दौरान, आपके ऐप्लिकेशन को Chrome के अलग-अलग वर्शन इस्तेमाल करने वाले लोगों के लिए काम करना है, तो उनके प्रोटोटाइप पर अपडेट किए गए तरीकों की मौजूदगी की जांच करें. इसके बाद, अपने सेटअप में ज़रूरी बदलाव करें.

पक्का करें कि आपने हर ब्राउज़र वर्शन के लिए, सही <canvas> एलिमेंट एट्रिब्यूट सेट किए हों:

// ============================================================================
//  Cross-version canvas markup
// ============================================================================
if (!canvas.hasAttribute('content') && !canvas.hasAttribute('layoutsubtree')) {
  if ('content' in HTMLCanvasElement.prototype) {
    // Chrome 155+ (New standardized attribute)
    canvas.setAttribute('content', 'drawable');
  } else {
    // Chrome < 155 (Legacy boolean attribute)
    canvas.setAttribute('layoutsubtree', '');
  }
}

2D कॉन्टेक्स्ट के लिए, drawElementImage() की रिटर्न वैल्यू की जांच करें. साथ ही, दोनों वर्शन के साथ काम करने के लिए, कैनवस प्रोटोटाइप एट्रिब्यूट की जांच करें:

// ============================================================================
// Cross-version 2D drawing & synchronization
// ============================================================================
function draw2DElement(ctx, element, x, y) {
  // Execute the 2D draw call
  const result = ctx.drawElementImage(element, x, y);

  if (result !== undefined && typeof result?.toString === 'function') {
    // Chrome < 155: drawElementImage returned a DOMMatrix
    // Requires manual transform piping to align DOM hit-test bounds:
    element.style.transform = result.toString();
  } else {
    // Chrome 155+: drawElementImage returns void / undefined
    // The browser automatically aligns DOM positioning, clicks, and a11y bounds!
    // If you previously had element.style.transform logic here, clear it:
    if (element.style.transform) {
      element.style.transform = "";
    }
  }
}

WebGPU के लिए, काम करने वाले तरीके के सिग्नेचर और नाम का इस्तेमाल करें:

// ============================================================================
// WebGPU cross-version support
// ============================================================================
if ('drawElementImageToTexture' in GPUQueue.prototype) {
  // Chrome 155+ (Latest implementation)
  queue.drawElementImageToTexture(
    { source: element, sourceX: 0, sourceY: 0, sourceWidth: w, sourceHeight: h },
    { texture: myTexture, size: { width: w, height: h } }
  );
} else if (typeof queue.copyElementImageToTexture === "function") {
  // Chrome 150 - 154: Try the Chrome 150+ dictionary signature first,
  // then fall back to the Chrome < 150 signature
  try {
    queue.copyElementImageToTexture(
      { source: element },
      { destination: { texture: myTexture }, width: w, height: h }
    );
  } catch (err) {
    // Chrome < 150
    queue.copyElementImageToTexture(element, { texture: myTexture });
  }
}

पक्का करें कि आपका ब्राउज़र WebGL के साथ काम करता हो:

// ============================================================================
// WebGL cross-version support
// ============================================================================
if ('texElementSubImage2D' in WebGL2RenderingContext.prototype) {
  // Chrome 155+ (Explicit pre-allocation + sub-image)
  gl.texElementSubImage2D(gl.TEXTURE_2D, 0, 0, 0, element);
} else if (gl.texElementImage2D && gl.texElementImage2D.length === 3) {
  // Chrome 150-154 (3-argument signature)
  gl.texElementImage2D(gl.TEXTURE_2D, gl.RGBA8, element);
} else if (gl.texElementImage2D) {
  // Chrome < 150 (6-argument signature)
  gl.texElementImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, element);
}

Origin Trial extension

HTML-in-Canvas के ऑरिजिन ट्रायल को Chrome 160 तक बढ़ा दिया गया है. अपने ऑरिजिन ट्रायल टोकन को रिन्यू करना न भूलें, ताकि लोगों को HTML-in-Canvas सुविधा मिलती रहे. ज़्यादा जानकारी के लिए, ऑरिजिन ट्रायल लेख पढ़ें.

सुझाव/राय दें या शिकायत करें

हमें बताएं कि ये अपडेट आपके ऐप्लिकेशन में कैसे काम करते हैं. इसके लिए, WICG GitHub रिपॉज़िटरी पर कोई समस्या फ़ाइल करें. डेवलपर न्यूज़लेटर में शामिल हों, ताकि आपको HTML-in-Canvas से जुड़ी सभी खबरें मिलती रहें.