HTML を 2D キャンバスにレンダリングする

HTML-in-Canvas API を使用すると、インタラクティブでアクセス可能な DOM サブツリーを 2D キャンバス コンテキストに直接レンダリングできます。API とそのメリットについて詳しくは、HTML-in-Canvas の概要をご覧ください。

このガイドでは、HTML を 2D キャンバスにレンダリングする方法について説明します。2D キャンバスで HTML をレンダリングするには、次の手順が必要です。

  1. キャンバスを準備します。適切な属性を宣言的に設定して、HTML をキャンバスにレンダリングする必要があることをブラウザに知らせます。この設定は、2D、WebGL、WebGPU のコンテキストで共通です。キャンバスを設定する方法と、HTML 要素を個別に描画するように宣言する方法を学習します。
  2. 要素の画像をキャンバスに描画します。
  3. [省略可] DOM とピクセルを同期します。

HTML 要素を 2D キャンバスに描画する

キャンバスの準備が整い、要素が drawable としてマークされたら、drawElementImage() メソッドを使用して 2D コンテキストにレンダリングします。

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) (sx, sy) から始まる swidth × sheight 領域のみが、その領域のデフォルト サイズ(デフォルト サイズのフォームと同じスケール)で描画されます。
ソーススライスから宛先 (element, sx, sy, swidth, sheight, dx, dy, dwidth, dheight) (sx, sy) から始まるサイズ swidth × sheight のソース要素を切り取り、(dx, dy, dwidth, dheight) にマッピングします。

DOM とピクセルを同期する

<canvas> レンダリングは必須ですが、DOM レイアウトと CSS スタイル設定はリアクティブであるため、ブラウザには、レンダリングされたキャンバス ピクセル、インタラクティブなヒットテスト領域、ユーザー補助ツリーを同期させるメカニズムが必要です。DOM とピクセルを同期する方法を学習する前に、DOM 要素が更新されて再描画が必要になったときにトリガーされる paint イベントについて理解しておいてください。

2D キャンバス コンテキストでは、ブラウザが要素のレイアウト座標、ユーザー補助の境界、ポインタのヒットテストを、描画されたキャンバス座標と自動的に同期します。

要素のジオメトリを手動で更新する

高度なシナリオでは、自動ジオメトリ同期を無効にして、空間変換を手動で制御できます。{ 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 });
2D では、drawElementImage() がこのジオメトリを自動的に更新します。このデモでは、{ preserveElementGeometry: true } が設定されている場合にジオメトリが同期されなくなる様子を示しています。

次のステップ