Canvas エディタの「選択枠」を DOM に出した OSS ライブラリ「HeadlessCanvas」を公開

Web ブラウザ上で動作する Canvas エディタ・エンジン 「HeadlessCanvas(ヘッドレスキャンバス)」 を、MIT ライセンスのオープンソースソフトウェアとして npm に公開しました。デザインツール、ホワイトボード、図面エディタ、間取り図、画像アノテーション UI などを自社製品に組み込みたい開発者に向けたライブラリです。

公式サイト・ライブデモ: https://headlesscanvas.com/
ソースコード: https://github.com/elephancube/headlesscanvas-js

目次

開発のきっかけ ― 「Fabric.js をこれからも使い続けるために」

当社は受託開発・自社サービスの双方で、長年 Fabric.js を利用してきました。図形モデル、変形、シリアライズまで一通りが揃っていて素直に動く、実績あるライブラリです。今回のライブラリは Fabric.js を置き換えるために作ったものではなく、Fabric.js を使い込む中で「ここだけは自分たちで何とかしたい」と感じた一点から出発しています。

その一点とは、選択枠やリサイズハンドルといった操作 UI が Canvas の中に描かれることです。これは Canvas 系ライブラリのほぼ共通の設計で、描画性能の観点では自然な選択です。しかし、Canvas に描かれたピクセルである以上、次の2つは原理的に手が届きません。

  1. CSS でデザインを変えられない。
    製品のデザインシステムに合わせてハンドルの形・色・太さを整えたいとき、ライブラリの描画オプションが用意している範囲までしか寄せられず、その先は自前の描画コードを書き足すことになります。
  2. アクセシビリティに弱く、支援技術から見えない。
    スクリーンリーダーにとって Canvas は1枚の画像です。「選択中のオブジェクト」「拡大ハンドル」といった操作 UI は、そこに存在しないのと同じ扱いになります。

HeadlessCanvas は、この2つを一度に解決するために 「図形は Canvas に描き、操作 UI は Canvas に重ねた DOM 要素として描く」 という構成としました。ハンドルは実在する DOM 要素なので、CSS で普通にスタイルできますし、Tab キーでフォーカスでき、ARIA 属性を持ち、スクリーンリーダーが読み上げます。

主な特徴

  1. 操作 UI を CSS で完全にカスタマイズできる
    状態は data 属性として DOM に出ています。CSS 変数と併せて、追加の JavaScript なしで見た目を作り込めます。

    カスタマイズは3段階を用意しました。
    Level 1 既定 UI をそのまま利用
    Level 2 CSS で restyle
    Level 3 既定 UI を使わず、自前のマークアップをハンドルとして機能させる

    Level 3 ではポインタキャプチャ・キーボード操作・ARIA 属性の付与をライブラリ側が引き受けるため、操作ロジックを書き直す必要はありません。
  2. アクセシビリティが後付けではない
    選択枠・ハンドル・シーン内容の読み上げが最初から組み込まれています。シーン内容の列挙は表示領域内に仮想化しており、オブジェクトが増えても DOM ノード数は増えません。
  3. フレームワーク非依存
    コアと既定 UI は素の TypeScript です。React バインディングは薄いアダプタとして別パッケージで提供しており、React・Vue・vanilla のいずれからでも同じ API で利用できます。
  4. オブジェクトが増えても重くならない設計
    操作 UI の DOM を持つのは選択中のオブジェクトだけです。ビューポート変換はコンテナ1要素に1回だけ適用するため、パン・ズームのコストはオブジェクト数に依存しません。ヒットテストは自前実装の R-Tree による絞り込みと図形ごとの厳密判定の2段構えです。
  5. v1.0 に向けた機能は一通り実装済み
    Undo/Redo、グリッド・オブジェクトへのスナップとスマートガイド、コピー&ペースト、テキスト編集、フリーハンド描画、PNG / JPEG / SVG 書き出し、画像を埋め込んだ自己完結型の JSON 保存、devicePixelRatio 対応、SSR 安全性に対応しています。
  6. 図形の種類は登録制
    組み込み図形も外部から追加する図形も、まったく同じ `ShapeUtil` の仕組みで実装されています。レンダラやヒットテストの内部に図形種別ごとの分岐は存在しません。TypeScript の declaration merging により、独自図形の props も型付きで扱えます。
  7. 実行時依存ゼロ・MIT
    `core` と `ui` は実行時依存を持ちません。MIT ライセンスであり、ウォーターマークの表示義務も、商用利用時のライセンスキーも、利用料もありません。

npmパッケージ構成

@headless-canvas/core
シーングラフ、レンダラ、状態管理、座標変換、ツール、図形レジストリ、ヘッドレス UI プリミティブ
@headless-canvas/ui
既定の操作 UI とスタイルシート。命令的な DOM 実装
@headless-canvas/react
`core` / `ui` を React に橋渡しする薄い層

公開状況と今後

現在は プレビュー版(0.1.x) として公開しています。API は固まっており、1.0 までに破壊的変更が入る場合は CHANGELOG に記載します。スクリーンリーダー実機での最終検証を経て v1.0 とする予定です。

その後のロードマップとして、SVG インポート、筆圧対応の可変幅ストローク、傾斜変形、WebGL レンダラを検討しています。

ドキュメントサイト(英語・日本語)には、ブラウザ上でそのまま触れるインタラクティブなデモを多数掲載しています。

最終更新日: 2026-08-14