এইচটিএমএল-ইন-ক্যানভাস আপডেট: একটি উন্নততর ওয়েব এপিআই-এর দিকে অগ্রগতি

ক্রোম ১৫০ এবং ১৫৫ সংস্করণে এইচটিএমএল-ইন-ক্যানভাস এপিআই-তে বেশ কিছু পরিবর্তন আনা হয়েছে। এপিআই-এর ব্যবহার-দক্ষতা উন্নত করার লক্ষ্যে কমিউনিটি এবং স্ট্যান্ডার্ডের মতামতের ভিত্তিতে এই পরিবর্তনগুলো আনা হয়েছে। এই ব্লগ পোস্টে সেই পরিবর্তনগুলো এবং কীভাবে আপনি আপনার ইমপ্লিমেন্টেশনকে সেগুলোর সাথে হালনাগাদ রাখতে পারেন, তা তুলে ধরা হয়েছে।

আপডেটগুলোর মধ্যে রয়েছে অ্যাট্রিবিউট ও মেথডের নাম পরিবর্তন, টেক্সচার মেমরির সুস্পষ্ট প্রি-অ্যালোকেশনের প্রয়োজনীয়তা এবং DOM সিনক্রোনাইজেশন মডেল আপডেট করা। এছাড়াও, HTML-in-Canvas Origin Trial-এর মেয়াদ এখন বাড়ানো হয়েছে। নিচে কী কী পরিবর্তন হচ্ছে, কেন হচ্ছে এবং কীভাবে আপনার কোডবেস আপডেট করবেন, তার ব্যাখ্যা দেওয়া হলো।

ক্রোম ১৫০-এর পরিবর্তনসমূহ

ক্রোম ১৫০-এ, আমরা পুনরাবৃত্তি দূর করতে এবং আধুনিক গ্রাফিক্স রীতির সাথে সামঞ্জস্য রাখতে WebGL ও WebGPU জুড়ে আর্গুমেন্ট সিগনেচার পরিবর্তন করেছি।

ওয়েবজিএল

আমরা 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);

ওয়েবজিপিইউ

আমরা sourceDict এবং destDict অবজেক্টগুলিতে copyElementImageToTexture প্যারামিটারগুলিকে প্রমিত করেছি (দেখুন 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);

ক্রোম ১৫৫-এর পরিবর্তনসমূহ

ডেভেলপারদের মতামতের ভিত্তিতে ক্রোম ১৫৫-এ আরও কিছু পরিমার্জন আনা হয়েছে। আমরা মেথডের নামগুলো আপডেট করছি, টেক্সচার মেমরির সুস্পষ্ট প্রি-অ্যালোকেশন বাধ্যতামূলক করছি, জটিল DOM সাবট্রি সমর্থন করছি এবং DOM সিনক্রোনাইজেশনকে পৃথক করছি।

ওয়েবজিপিইউ

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

ওয়েবজিএল

HTML-in-Canvas-এর জন্য WebGL-এ পরিবর্তনের তিনটি দিক রয়েছে:

  • মেথডের নাম texElementImage2D থেকে texElementSubImage2D তে পরিবর্তিত হয়।
  • মেথড সিগনেচার পরিবর্তিত হয়েছে; সবচেয়ে উল্লেখযোগ্য পরিবর্তন হলো, এতে xoffset এবং yoffset আর্গুমেন্ট যোগ করা হয়েছে, যার মাধ্যমে ঐচ্ছিকভাবে ডেস্টিনেশন টেক্সচারের মধ্যে একটি অফসেট নির্দিষ্ট করা যায়, যেখানে এলিমেন্টটি আঁকা হবে।
  • এই পদ্ধতিটি এখন আর গন্তব্য টেক্সচারের জন্য স্বয়ংক্রিয়ভাবে বাফার স্টোরেজ বরাদ্দ করে না; API ব্যবহার করার আগে স্টোরেজটি অবশ্যই সুস্পষ্টভাবে বরাদ্দ করতে হবে। এটি 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" রাখা হচ্ছে

HTML অ্যাট্রিবিউট নামকরণের রীতির সাথে সামঞ্জস্য রাখতে, <canvas> এলিমেন্টের বুলিয়ান layoutsubtree অ্যাট্রিবিউটটির নাম পরিবর্তন করে content="drawable" রাখা হয়েছে (বিস্তারিত আলোচনার জন্য WICG ইস্যু #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 নির্দিষ্ট করে। এর ফলে প্যারেন্ট কন্টেইনার এবং বাটনের মতো চাইল্ড এলিমেন্টগুলোকে আলাদা আলাদা `draw` কলের মাধ্যমে অ্যানিমেট ও ড্র করা যায়।

হিট-টেস্টিং সিঙ্ক্রোনাইজেশন

পূর্বে, ডেভেলপারদের ড্রয়িং মেথড থেকে রিটার্ন ভ্যালু নিয়ে element.style.transform এ পাইপ করতে হতো। এখন drawElementImage() মেথডটি void রিটার্ন করে এবং সিনক্রোনাইজেশন কনটেক্সটের উপর নির্ভর করে।

২ডি কনটেক্সট: স্বয়ংক্রিয় সিঙ্ক্রোনাইজেশন

2D ক্যানভাসে, ব্রাউজার স্বয়ংক্রিয়ভাবে DOM হিট-টেস্ট বাউন্ড এবং স্ক্রিন রিডার ফোকাস রিংগুলিকে অঙ্কিত স্থানাঙ্কের সাথে সিঙ্ক্রোনাইজ করে। আপনি সমস্ত ম্যানুয়াল ট্রান্সফর্ম পাইপিং মুছে ফেলতে পারেন:

// 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 তে জ্যামিতি ম্যানুয়ালি পরিচালনা করতে, drawElementImage() এ { preserveElementGeometry: true } পাস করুন এবং canvas.updateElementGeometry() ব্যবহার করে ট্রান্সফর্ম প্রয়োগ করুন।

3D প্রেক্ষাপট: সুস্পষ্ট updateElementGeometry()

WebGL বা WebGPU প্রেক্ষাপটে DOM সিঙ্ক্রোনাইজ করতে, একটি 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 });
});

বিভিন্ন সংস্করণের মধ্যে সামঞ্জস্যতা

রূপান্তরের সময়কালে যদি আপনার অ্যাপ্লিকেশনটিকে একাধিক ক্রোম সংস্করণের ব্যবহারকারীদের সমর্থন করতে হয়, তাহলে তাদের প্রোটোটাইপে আপডেট করা মেথডগুলোর উপস্থিতি পরীক্ষা করুন এবং সেই অনুযায়ী আপনার ইমপ্লিমেন্টেশন সামঞ্জস্য করুন।

প্রতিটি ব্রাউজার সংস্করণের জন্য <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);
}

উৎপত্তি ট্রায়াল সম্প্রসারণ

এইচটিএমএল-ইন-ক্যানভাস অরিজিন ট্রায়ালটি ক্রোম ১৬০ পর্যন্ত বর্ধিত করা হয়েছে। আপনার ব্যবহারকারীদের এইচটিএমএল-ইন-ক্যানভাস ফিচারটি প্রদান করা চালিয়ে যেতে আপনার অরিজিন ট্রায়াল টোকেনটি নবায়ন করুন। আরও বিস্তারিত জানতে অরিজিন ট্রায়াল আর্টিকেলটি দেখুন।

আপনার মতামত জানান

আপনার অ্যাপ্লিকেশনগুলিতে এই আপডেটগুলি কীভাবে কাজ করছে তা WICG গিটহাব রিপোজিটরিতে একটি ইস্যু ফাইল করে আমাদের জানান। HTML-in-Canvas সম্পর্কিত যেকোনো খবরের সাথে আপ-টু-ডেট থাকতে ডেভেলপার নিউজলেটারে যোগ দিন।