בגרסאות 150 ו-155 של Chrome, הוספנו כמה שינויים ל-HTML-in-Canvas API. השינויים האלה בוצעו בתגובה למשוב מהקהילה ולתקנים, במטרה לשפר את הארגונומיה של ה-API. בפוסט הזה בבלוג מפורטים השינויים ומוסבר איך לוודא שההטמעה שלכם מעודכנת בהתאם לשינויים האלה.
העדכונים כוללים שינוי שמות של מאפיינים ושיטות, דרישה להקצאה מראש של זיכרון מרקם ועדכון של מודלים לסנכרון DOM. בנוסף, תקופת הניסיון של HTML-in-Canvas Origin הוארכה. בהמשך מוסבר מה משתנה, למה ואיך לעדכן את בסיס הקוד.
שינויים ב-Chrome 150
בגרסה Chrome 150, שינינו את חתימות הארגומנטים ב-WebGL וב-WebGPU כדי לבטל כפילויות ולהתאים למוסכמות גרפיקה מודרניות.
WebGL
הסרנו ארגומנטים מיותרים (level, srcFormat, destType) מ-texElementImage2D
(פרטים נוספים זמינים בדיון על 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
בגרסה 155 של Chrome, בוצעו שיפורים נוספים על סמך משוב ממפתחים. אנחנו מעדכנים את שמות השיטות, דורשים הקצאה מראש של זיכרון טקסטורה, תומכים בעצי משנה מורכבים של DOM ומבטלים את ההתאמה בין DOM.
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
יש שלושה היבטים לשינויים ב-WebGL עבור HTML-in-Canvas:
- שם השיטה השתנה מ-
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
);
מאפייני Canvas ואלמנטים משניים שניתנים לציור
אנחנו מעדכנים את האופן שבו מכינים את ה-Canvas לעיבוד HTML.
שינוי השם של layoutsubtree לcontent="drawable"
כדי להתאים למוסכמות למתן שמות למאפייני HTML, המאפיין הבוליאני layoutsubtree
באלמנט <canvas> שונה ל-content="drawable" (דיון מפורט בנושא אפשר למצוא בבעיה מספר 169 של WICG).
המאפיין drawable של צאצאים
בעבר, רק רכיבים משניים ישירים של רכיב Canvas עברו עיבוד. כדי לתמוך בהיררכיות 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. ה-method drawElementImage() מחזירה עכשיו void, והסנכרון תלוי בהקשר.
הקשרים דו-ממדיים: סנכרון אוטומטי
בבד ציור דו-ממדי, הדפדפן מסנכרן באופן אוטומטי את גבולות הבדיקה של 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, מעבירים את { preserveElementGeometry: true } אל drawElementImage() ומחילים טרנספורמציות באמצעות canvas.updateElementGeometry().
הקשרים תלת-ממדיים: תוכן בוטה updateElementGeometry()
כדי לסנכרן את ה-DOM בהקשרים של WebGL או WebGPU, צריך ליצור DOMMatrix transform
ולהעביר אותו אל 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', '');
}
}
בהקשר של דו-ממד, בודקים את ערך ההחזרה של drawElementImage() ואת מאפייני אב הטיפוס של canvas כדי לתמוך בשתי הגרסאות:
// ============================================================================
// 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
התקופה של גרסת המקור לניסיון של HTML-in-Canvas הוארכה עד Chrome 160. כדי להמשיך להציע למשתמשים את התכונה HTML-in-Canvas, צריך לחדש את אסימון גרסת המקור לניסיון. פרטים נוספים זמינים במאמר הזה בנושא תקופת ניסיון של תכונות חדשות.
שיתוף משוב
נשמח לדעת איך העדכונים האלה פועלים באפליקציות שלכם. כדי לעשות זאת, אתם יכולים לדווח על בעיה במאגר GitHub של WICG. כדאי להירשם לניוזלטר למפתחים כדי להתעדכן בכל מה שקורה בנושא HTML-in-Canvas.