React + fabric.jsで手書き表現

2 min read読了の目安(約2200字

fabric.js を React 環境下で使う機会があったので、開発手順をまとめます。

作ったもの

手書きできます

文字の色・太さを変えられます

その他、ダウンロードもできます(デモでは動きません)。

デモ

状態管理について

初めはrecoilを使おうと思っていましたが、私の知識不足により fabric.js ライブラリから提供されるクラスオブジェクトをうまく状態として管理できなかったため、unstated-nextと useReducer を利用した、中央集権的な状態管理にしました。

追記

クラスオブジェクトを toObject()することで、recoil でもうまく状態管理できるようです。

キャンバスの初期化

fabric.js では、提供される変数 fabric のプロパティとして、いくつかのクラスを利用できます。今回は fabric.Canvas を利用し、コンストラクタには紐づける canvas 要素の ID を指定します。canvas 要素が先に必要なので、useEffect を利用して最初のレンダリング後にクラスを作成します。コンストラクタには canvas 要素自体を指定することもできるので、ID を割り振らず、useRef を使ってもいいかもしれません。

import { fabric } from "fabric";

const CANVAS_ID = "canvas";

const Component: VFC<Props> = memo(({ className, dispatch }) => {
  useEffect(() => {
    // キャンバスの初期化処理
    const initCanvas = new fabric.Canvas(CANVAS_ID, {
      isDrawingMode: true, // 手書きモード
      width: 800,
      height: 300,
      backgroundColor: "#80beaf",
    });

    // クラスをそのまま格納
    dispatch({ type: "init", canvas: initCanvas });
  }, []);

  // canvas要素に紐づけ
  return (
    <div className={className}>
      <canvas id={CANVAS_ID} />
    </div>
  );
});

正直言って、手書きを実現するために最低限必要な設定はこれだけです。手書き用のキャンバス作成後、ペンの設定を変更したり、状態をクリアするために作成した fabric.Canvas クラスをそのまま状態として保存しておきます。

手書きするペンの設定

fabric.Canvas クラスの手書きモードを有効にした場合、描画されるペンの設定は freeDrawingBrush 以下のプロパティを変更することで可能です。

詳細な設定は、fabric.js 公式のデモが分かりやすいと思います。

state.canvas.freeDrawingBrush.color = "#fff";
state.canvas.freeDrawingBrush.width = 800;

書き込んだ内容をクリア

case "clear": {
  if (!state.canvas) {
    return state;
  }
  // クリア
  state.canvas.clear();
  // 背景情報もクリアされるので、再定義
  state.canvas.backgroundColor = "#80beaf";
  // 背景に画像を設定する場合は、読み込み後に再レンダリング
  state.canvas.setBackgroundImage(url, () => state.canvas!.renderAll());
  return state;
}