HTML-in-Canvas API מאפשר להציג עצי משנה נגישים ואינטראקטיביים של DOM ישירות בהקשר של קנבס דו-ממדי. כדי לקבל מידע נוסף על ה-API והיתרונות שלו, קראו את הסקירה הכללית על HTML-in-Canvas.
במדריך הזה מוסבר איך לעבד HTML ל-canvas דו-ממדי. כדי לעבד HTML ב-canvas דו-ממדי, צריך לבצע את השלבים הבאים:
- מכינים את הקנבס. מגדירים באופן הצהרתי את המאפיינים הנכונים כדי שהדפדפן ידע שהוא צריך לעבד HTML לתוך קנבס. ההגדרה הזו זהה בהקשרים של 2D, WebGL ו-WebGPU. איך מגדירים את ה-canvas ואיך מגדירים רכיבי HTML שישורטטו באופן עצמאי.
- מציירים את תמונת הרכיב באזור העריכה.
- [אופציונלי] מסנכרנים את ה-DOM והפיקסלים.
ציור רכיבי HTML ב-canvas דו-ממדי
כשהקנבס מוכן והרכיבים מסומנים כ-drawable, מעבדים אותם להקשר הדו-ממדי באמצעות השיטה drawElementImage().
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const childElement1 = document.getElementById("childElement1");
const childElement2 = document.getElementById("childElement2");
canvas.onpaint = () => {
ctx.reset();
// 1. Draw the primary element at coordinate (20, 20)
ctx.drawElementImage(childElement1, 20, 20);
// 2. Draw the secondary nested button at a custom offset
ctx.drawElementImage(childElement2, 40, 90);
}
הפונקציה drawElementImage() תומכת בטפסים עם 3, 5, 7 ו-9 ארגומנטים, ומקבלת פרמטר options אופציונלי:
// 1. Basic position: (element, dx, dy, options?)
ctx.drawElementImage(targetElement, 100, 150);
// 2. Scaled / resized: (element, dx, dy, dWidth, dHeight, options?)
ctx.drawElementImage(targetElement, 100, 150, 180, 60);
// 3. Cropped, default size: (element, sx, sy, swidth, sheight, dx, dy, options?)
ctx.drawElementImage(targetElement, 0, 0, 90, 30, 100, 150);
// 4. Cropped and resized: (element, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight, options?)
ctx.drawElementImage(targetElement, 0, 0, 90, 30, 100, 150, 180, 60);
| טופס עומס יתר | פרמטרים | אפקט הפריסה |
|---|---|---|
| גודל ברירת המחדל | (element, dx, dy) |
הרכיב כולו בגודל ברירת המחדל שלו, כשהפינה השמאלית העליונה נמצאת ב-(dx, dy). |
| תיבת יעד מותאם אישית | (element, dx, dy, dwidth, dheight) |
משנה את קנה המידה של תמונת הרכיב המלאה לאזור תצוגה של dw × dh בקנבס. |
| חתוך, גודל ברירת המחדל | (element, sx, sy, swidth, sheight, dx, dy) |
רק האזור swidth × sheight שמתחיל ב-(sx, sy), שמשורטט בגודל ברירת המחדל של האזור הזה (באותו קנה מידה כמו הטופס בגודל ברירת המחדל). |
| פרוסת מקור ליעד | (element, sx, sy, swidth, sheight, dx, dy, dwidth, dheight) |
חיתוך של רכיב המקור החל מ-(sx, sy) עם המידות swidth × sheight, ואז מיפוי שלו ליעד (dx, dy, dwidth, dheight). |
סנכרון ה-DOM והפיקסלים
מכיוון שהעיבוד של <canvas> הוא הכרחי, בעוד שהפריסה של DOM והסגנון של CSS הם ריאקטיביים, הדפדפן צריך מנגנון שיסנכרן בין הפיקסלים של לוח ה-Canvas שעובדו, אזורי הבדיקה האינטראקטיביים של מיקום המצביע ועצי הנגישות. לפני שאתם לומדים איך לסנכרן את ה-DOM והפיקסלים, חשוב שתבינו את האירוע paint שמופעל כשאלמנטים של DOM מתעדכנים וצריך לשרטט אותם מחדש.
בהקשרים של רכיבי canvas דו-ממדיים, הדפדפן מסנכרן באופן אוטומטי את קואורדינטות הפריסה של הרכיב, את גבולות הנגישות ואת בדיקת מיקום המצביע עם הקואורדינטות של רכיב ה-canvas המצויר.
עדכון ידני של הגיאומטריה של האלמנטים
בתרחישים מתקדמים, אתם יכולים לבטל את ההסכמה לסנכרון גיאומטרי אוטומטי ולשלוט בטרנספורמציות מרחביות באופן ידני. מעבירים את { preserveElementGeometry: true } אל drawElementImage() כדי למנוע מהדפדפן לשנות באופן אוטומטי את הקואורדינטות הקיימות של בדיקת מיקום המצביע של הרכיב:
// 1. Draw the element without altering its existing hit-test bounds
ctx.drawElementImage(targetElement, elementX, 200, { preserveElementGeometry: true });
// 2. Construct a custom transform matrix as needed,
// assuming scaleX/scaleY = canvas grid pixels per CSS pixel,
// from your resize observer (see "Units and sizing").
const currentTransform = new DOMMatrix();
currentTransform.a = 1.5; // scale X
currentTransform.e = x / scaleX; // translate X: grid px → CSS px
currentTransform.f = y / scaleY; // translate Y: grid px → CSS px
// 3. Explicitly apply the custom transform
canvas.updateElementGeometry(targetElement, { canvasTransform: currentTransform });
drawElementImage() מעדכן את הגיאומטריה הזו באופן אוטומטי. בהדגמה הזו אפשר לראות איך הגיאומטריה יוצאת מסנכרון כשמגדירים את { preserveElementGeometry: true }.