はじめに
HeadlessCanvas は Canvas エディタを作るためのエンジンです。デザインツール、ホワイトボード、図表エディタ、間取り作成、画像注釈 UI といったものを対象にしています。図形は <canvas> に描画し、ユーザーが操作するもの — 選択枠・リサイズハンドル・回転 UI — はその上の DOM に置きます。
解決している問題
Canvas ライブラリは選択ハンドルを Canvas の中に描きます。Konva も Fabric もそうです。そこから2つのことが帰結し、アプリケーション側のコードではどちらも打ち消せません。
- ハンドルを装飾できない。 それは要素ではなくピクセルです。「フォーカスリングはブランドカラーで 2px」と定めたデザインシステムがあっても、適用する先が存在しません。
- 支援技術から見えない。 Canvas はアクセシビリティツリー上では不透明な1個のノードです。フォーカスできるハンドルも、実行できるボタンも、読み上げる対象も存在しません。
コントロールを DOM に移すとこの2つが同時に解決します。このライブラリが存在する理由はそこにあります。
引き受けているトレードオフ
UI を DOM に置くのは無料ではありません。不用意にやれば図形1個につき DOM ノード1個になり、パンのたびにレイアウトが走ります。それを防ぐために4つの規則の上に設計されています。
- Canvas に UI を描かない。 選択枠もハンドルも DOM である。
- コントロール UI は選択中の対象にのみ生成する。 図形が1万個あってもオーバーレイのノードは数個。複数選択でも枠は N 個ではなく1個。
- ビューポート変換は1フレームに1要素へ1回だけ書き込む。 オーバーレイのコンテナが変換を担い、子はワールド座標に置かれる。パンの費用は図形10個でも1万個でも同じ。
- ハンドルの見かけの大きさは CSS で補正する。 ライブラリが書き込む
--hc-zoom変数で割る。要素ごとに JavaScript でサイズを書き込むと規則3の利点が消える。
詳細はコンセプトにあります。単独では恣意的に見える API のいくつかは、この規則のいずれかの帰結です。何かを本格的に作る前に読んでおく価値があります。
含まれないもの
HeadlessCanvas はアプリケーションではなくエンジンです。ツールバー・カラーピッカー・レイヤーパネル・メニューは一切含みません。 それらはプロダクトの判断であり、ライブラリが代わりに決めてしまえば、結局そのライブラリと戦うことになります。
v1.0 の対象外はほかにもあります。Fabric.js との機能パリティ、リッチテキスト編集エンジン、画像フィルタ、サーバーサイドでの文書描画、ページ/アートボードの概念。SVG インポートも含みません。SVG 仕様全体を相手にする作業は、ここにある他のすべてに匹敵する規模だからです。
他との比較
| 描画 | コントロール UI | CSS で装飾 | スクリーンリーダー対応 | ライセンス | |
|---|---|---|---|---|---|
| HeadlessCanvas | Canvas | DOM | 可 | 可 | MIT |
| Konva.js | Canvas | Canvas | 不可 | 不可 | MIT |
| Fabric.js | Canvas | Canvas | 不可 | 不可 | MIT |
| tldraw | DOM/SVG | DOM | 可 | 一部 | 非オープンソース |
| Excalidraw | Canvas | DOM | 再利用可能なライブラリではなくアプリ | — | MIT |
構成上もっとも近いのは tldraw で、正面から比較すべき相手です。成熟した製品であり、機能の幅ははるかに広い。同時にオープンソースではありません。本番利用にはライセンスキーが必要で、商用ライセンスを購入しない限り "Made with tldraw" のウォーターマークを保持する義務があり、あなたのプロジェクトの上に何かを作る人もそれぞれライセンスを必要とします。
それが作ろうとしているものと両立するなら、有力な選択肢です。両立しないなら — ライブラリを配布する場合、予算のない社内ツール、下流にライセンス義務を課せない何か — そこが本プロジェクトの埋める隙間です。
パッケージ
| パッケージ | 内容 | 実行時依存 |
|---|---|---|
@headless-canvas/core | シーングラフ、レンダラ、状態管理、座標変換、ツール、シェイプ登録、コントロールのプリミティブ | なし |
@headless-canvas/ui | 既定のコントロールとスタイルシート。命令的な DOM で、フレームワークを問わず使える | core |
@headless-canvas/react | 上記2つに対する React バインディング | core / ui / react |
既定 UI は React 専用ではありません。 唯一の出来合いのコントロールが React を要求するなら、それ以外の人は最初から自作に追い込まれます。コントロールを差し替えられることを売りにするライブラリの出発点として、それは妥当ではありません。