Renderowanie HTML w obszarze roboczym 2D

Interfejs HTML-in-Canvas API umożliwia renderowanie interaktywnych, dostępnych poddrzew DOM bezpośrednio w kontekście Canvas 2D. Aby dowiedzieć się więcej o interfejsie API i jego zaletach, przeczytaj omówienie HTML-in-Canvas.

Z tego przewodnika dowiesz się, jak renderować kod HTML na elemencie canvas 2D. Renderowanie kodu HTML w elemencie canvas 2D wymaga wykonania tych czynności:

  1. Przygotuj obszar roboczy. Deklaratywnie ustaw odpowiednie atrybuty, aby poinformować przeglądarkę, że powinna renderować kod HTML w elemencie canvas. Ta konfiguracja jest identyczna w kontekstach 2D, WebGL i WebGPU. Dowiedz się, jak skonfigurować obszar roboczy i jak zadeklarować elementy HTML, które mają być rysowane niezależnie.
  2. Narysuj obraz elementu na obszarze roboczym.
  3. [Opcjonalnie] Zsynchronizuj DOM i piksele.

Rysowanie elementów HTML na obszarze roboczym 2D

Gdy obszar roboczy jest gotowy, a elementy są oznaczone jako drawable, wyrenderuj je w kontekście 2D za pomocą metody 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);
}

Funkcja drawElementImage() obsługuje formy z 3, 5, 7 i 9 argumentami oraz akceptuje opcjonalny parametr 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);
Formularz przeciążenia Parametry Efekt układu
Rozmiar domyślny (element, dx, dy) Cały element w domyślnym rozmiarze, z lewym górnym rogiem w punkcie (dx, dy).
Pole niestandardowego miejsca docelowego (element, dx, dy, dwidth, dheight) Skaluje pełny obraz elementu do widocznego obszaru dw × dh na obszarze roboczym.
Przycięty, rozmiar domyślny (element, sx, sy, swidth, sheight, dx, dy) Tylko obszar swidth × sheight zaczynający się od (sx, sy), narysowany w domyślnym rozmiarze tego obszaru (w tej samej skali co formularz o domyślnym rozmiarze).
Wycinek źródłowy do miejsca docelowego (element, sx, sy, swidth, sheight, dx, dy, dwidth, dheight) Przycina element źródłowy, zaczynając od (sx, sy) z wymiarami swidth × sheight, a następnie mapuje go do miejsca docelowego (dx, dy, dwidth, dheight).

Synchronizowanie modelu DOM i pikseli

Ponieważ renderowanie <canvas> jest imperatywne, a układ DOM i style CSS są reaktywne, przeglądarka potrzebuje mechanizmu, który synchronizuje wyrenderowane piksele obszaru roboczego, interaktywne regiony testu pozycji wskaźnika i drzewa ułatwień dostępu. Zanim dowiesz się, jak synchronizować DOM i piksele, zapoznaj się ze zdarzeniem paint, które jest wywoływane, gdy elementy DOM są aktualizowane i wymagają ponownego narysowania.

W kontekstach canvas 2D przeglądarka automatycznie synchronizuje współrzędne układu elementu, granice ułatwień dostępu i test pozycji wskaźnika ze współrzędnymi narysowanego elementu canvas.

Ręczne aktualizowanie geometrii elementu

W bardziej zaawansowanych scenariuszach możesz zrezygnować z automatycznej synchronizacji geometrii i ręcznie kontrolować przekształcenia przestrzenne. Przekaż { preserveElementGeometry: true } do drawElementImage(), aby uniemożliwić przeglądarce automatyczne zastępowanie istniejących współrzędnych testu pozycji wskaźnika elementu:

// 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 });
W trybie 2D drawElementImage() automatycznie aktualizuje tę geometrię. Ten przykład pokazuje, jak geometria przestaje być zsynchronizowana, gdy ustawiona jest właściwość { preserveElementGeometry: true }.

Dalsze kroki