Renderowanie kodu HTML w obszarze roboczym WebGL umożliwia używanie aktywnych poddrzew DOM jako dynamicznych tekstur GPU, stosowanie efektów cieniowania do aktywnego DOM i integrowanie interaktywnego kodu HTML ze scenami 3D.
Z tego przewodnika dowiesz się, jak renderować kod HTML na elemencie canvas WebGL. Więcej informacji o HTML-in-Canvas znajdziesz w omówieniu interfejsu API.
Renderowanie kodu HTML na obszarze roboczym WebGL wymaga wykonania tych czynności:
- 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.
- Zastosuj kod HTML jako teksturę:
- Wstępnie przydziel miejsce na tekstury GPU.
- Prześlij zrzut DOM jako teksturę.
- Zsynchronizuj DOM i piksele.
Rysowanie elementu HTML jako tekstury WebGL
W WebGL elementy HTML są przesyłane do GPU jako tekstury 2D za pomocą texElementSubImage2D().
Wstępne przydzielanie miejsca na tekstury
W przeciwieństwie do obszaru roboczego 2D, który automatycznie zarządza pamięcią pomocniczą, kontekst WebGL wymaga jawnego zarządzania pamięcią.
Przed przesłaniem pikseli DOM musisz wstępnie przydzielić pamięć GPU. Dzięki temu przeglądarka może szybko aktualizować fragmenty obrazu bez konieczności kosztownego ponownego przydzielania pamięci GPU.
Wstępnie przydziel bufor z wybranymi parametrami rozmiaru i ustawieniem srcData na null w ten sposób:
// Only allocate texture backing once
if (!textureBufferAllocated) {
// Pre-allocate texture backing with pre-determined size.
gl.texImage2D(
/* target */ gl.TEXTURE_2D,
/* level */ 0,
/* internalformat */ gl.RGBA8,
/* width */ myElementWidth,
/* height */ myElementHeight,
/* border */ 0,
/* format */ gl.RGBA,
/* type */ gl.UNSIGNED_BYTE,
/* srcData */ null
);
textureBufferAllocated = true;
}
Aby tekstura pasowała do naturalnego rozmiaru układu elementu HTML, użyj canvas.getElementImageDefaultSize(), aby pobrać jego domyślny rozmiar w pikselach siatki obszaru roboczego:
const { width, height } = canvas.getElementImageDefaultSize(myElement);
// Pre-allocate texture backing. Only do this once, or whenever the element
// changes size.
gl.texImage2D(
/* target */ gl.TEXTURE_2D,
/* level */ 0,
/* internalformat */ gl.RGBA8,
/* width */ Math.ceil(width),
/* height */ Math.ceil(height),
/* border */ 0,
/* format */ gl.RGBA,
/* type */ gl.UNSIGNED_BYTE,
/* srcData */ null
);
Prześlij zrzut DOM jako teksturę
Następnym krokiem jest przesłanie elementu HTML do tekstury w pętli renderowania lub detektorze paint.
canvas.onpaint = () => {
// 1. Pre-allocate texture backing first
// ...
// 2. Upload HTML snapshot into the WebGL texture
gl.texElementSubImage2D(
/* target */ gl.TEXTURE_2D,
/* level */ 0,
/* xoffset */ 0,
/* yoffset */ 0,
/* element */ myElement // or an ElementImage from `captureElementImage()`
);
// ...
};
Synchronizowanie geometrii
W przeciwieństwie do kontekstów 2D przeglądarka nie może automatycznie określić, gdzie tekstura pojawia się na ekranie w kontekście 3D. Musisz ręcznie dopasować testy pozycji wskaźnika DOM i ramki ograniczające ułatwień dostępu do siatki 3D.
W tym celu utwórz obiekt DOMMatrix, który mapuje pole obramowania elementu na jego wyrenderowaną lokalizację piksela na obszarze roboczym, a następnie zastosuj go za pomocą updateElementGeometry():
canvas.addEventListener("paint", () => {
// 1. Upload fresh DOM snapshot to GPU texture
gl.bindTexture(gl.TEXTURE_2D, myTexture);
gl.texElementSubImage2D(gl.TEXTURE_2D, 0, 0, 0, myElement);
// 2. Draw your 3D scene
draw3DScene();
// 3. Construct the CSS-pixel transform mapping the element's
// border box to its drawn position on the canvas as needed
// (for example: scale and translate)
const canvasTransform = new DOMMatrix();
// scale X
canvasTransform.a = canvas.clientWidth / myElement.offsetWidth;
// scale Y
canvasTransform.d = canvas.clientHeight / myElement.offsetHeight;
// translate X (CSS px)
canvasTransform.e = 50;
// translate Y (CSS px)
canvasTransform.f = 100;
// 4. Update DOM position, accessibility focus rings, and pointer hit-testing
canvas.updateElementGeometry(myElement, {
canvasTransform: canvasTransform,
});
});
Dalsze kroki
- Poznaj podstawowe zagadnienia techniczne związane z elementami HTML w elemencie Canvas.
- Dowiedz się, jak renderować kod HTML w kontekście 2D.
- Dowiedz się, jak renderować kod HTML w elemencie canvas WebGPU.
- Dowiedz się więcej o strategiach zastępczych.
- Aby podzielić się opinią, zgłoś problem na GitHubie.
- Zapoznaj się z kolekcją demonstracyjną HTML-in-Canvas utworzoną przez społeczność.