Afficher du code HTML dans un canevas 2D

L'API HTML-in-Canvas vous permet d'afficher des sous-arborescences DOM interactives et accessibles directement dans un contexte de canevas 2D. Consultez la présentation de HTML-in-Canvas pour en savoir plus sur l'API et ses avantages.

Ce guide explique comment afficher du code HTML dans un canevas 2D. Pour afficher du code HTML dans un canevas 2D, procédez comme suit :

  1. Préparez votre toile. Définissez de manière déclarative les attributs appropriés pour indiquer au navigateur qu'il doit afficher du code HTML dans un canevas. Cette configuration est identique pour les contextes 2D, WebGL et WebGPU. Découvrez comment configurer votre canevas et comment déclarer des éléments HTML à dessiner indépendamment.
  2. Dessinez l'image de l'élément dans le canevas.
  3. [Facultatif] Synchronisez le DOM et les pixels.

Dessiner des éléments HTML dans un canevas 2D

Une fois le canevas prêt et les éléments marqués comme drawable, affichez-les dans le contexte 2D à l'aide de la méthode 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() accepte les formes à 3, 5, 7 et 9 arguments, ainsi qu'un paramètre options facultatif :

// 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);
Formulaire de surcharge Paramètres Effet de mise en page
Taille par défaut (element, dx, dy) L'élément entier à sa taille par défaut, avec le coin supérieur gauche à (dx, dy).
Zone de destination personnalisée (element, dx, dy, dwidth, dheight) Met à l'échelle l'image complète de l'élément dans une fenêtre d'affichage dw × dh sur le canevas.
Recadrée, taille par défaut (element, sx, sy, swidth, sheight, dx, dy) Seule la zone swidth × sheight commençant à (sx, sy), dessinée à la taille par défaut de cette zone (la même échelle que le formulaire de taille par défaut).
Tranche source vers destination (element, sx, sy, swidth, sheight, dx, dy, dwidth, dheight) Recadre l'élément source à partir de (sx, sy) avec les dimensions swidth × sheight, puis le mappe vers la destination (dx, dy, dwidth, dheight).

Synchroniser le DOM et les pixels

Étant donné que le rendu <canvas> est impératif, tandis que la mise en page DOM et le style CSS sont réactifs, le navigateur a besoin d'un mécanisme pour synchroniser les pixels du canevas affiché, les régions de test de positionnement interactives et les arbres d'accessibilité. Avant d'apprendre à synchroniser le DOM et les pixels, assurez-vous de bien comprendre l'événement paint qui se déclenche lorsque les éléments du DOM sont mis à jour et doivent être redessinés.

Dans les contextes de canevas 2D, le navigateur synchronise automatiquement les coordonnées de mise en page de l'élément, les limites d'accessibilité et les tests de positionnement avec les coordonnées du canevas dessiné.

Mettre à jour manuellement la géométrie d'un élément

Dans les scénarios avancés, vous pouvez désactiver la synchronisation automatique de la géométrie et contrôler manuellement les transformations spatiales. Transmettez { preserveElementGeometry: true } à drawElementImage() pour empêcher le navigateur de remplacer automatiquement les coordonnées de test de positionnement existantes de l'élément :

// 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 });
En 2D, drawElementImage() met à jour cette géométrie automatiquement. Cette démonstration montre comment la géométrie se désynchronise lorsque { preserveElementGeometry: true } est défini.

Étapes suivantes