Fabric.jsのパスデータをPaper.jsで単純化する

Fabric.js を使用してCanvas上にフリーハンドで描いた線を toSVG
toJSON でシリアライズしてみると fabric.Path のベジェ曲線のデータが結構な量になることがわかります。 Paper.jspath.simplify を利用することで、 fabric.Path のデータ量を減らしてスムーズな線を簡単に描画することができました。

前回つくった fabric.Path のサブクラス fabric.ExPathfabric.PencilBrush のサブクラス fabric.ExPencilBrush に処理を追加して、 fabric.ExPath をシリアライズしたときのデータを単純化してみます。
(Fabric.jsのバージョンは3.4.0、Paper.jsのバージョンは0.12.3を使用しています。)

まず、 fabric.ExPath に Paper.js の path.simplify をつかってパスを単純化する処理を追加します。

fabric.ExPath = fabric.util.createClass(fabric.Path, {
  initialize (path, options) {
    options || (options = {});

    this.callSuper('initialize', path, options);

    this.brushType = options.brushType || 'pencil';

    // Paper.jsの初期化
    paper.setup();

  },

  simplify (tolerance) {
    const pathData = this.path.map((path) => {
      return path.join(' ');
    }).join(' ');

    // Paper.jsでパスを単純化
    const obj = new paper.Path(pathData);
    obj.simplify(tolerance);

    const path = new fabric.ExPath(obj.pathData);
    this.path = path.path;
  }

});

次に、 fabric.ExPencilBrushfabric.ExPath のオブジェクトがCanvasに追加されるときに、先ほど追加した fabric.ExPath の単純化処理(simplify)が呼ばれるように _finalizeAndAddPath の処理をオーバライドします。

fabric.ExPencilBrush = fabric.util.createClass(fabric.PencilBrush, {
  _finalizeAndAddPath () {
    const ctx = this.canvas.contextTop;
    ctx.closePath();
    if (this.decimate) {
      this._points = this.decimatePoints(this._points, this.decimate);
    }
    const pathData = this.convertPointsToSVGPath(this._points).join('');
    if (pathData === 'M 0 0 Q 0 0 0 0 L 0 0') {
      this.canvas.requestRenderAll();
      return;
    }

    const path = this.createPath(pathData);

    // パスのデータを単純化
    path.simplify(1.5);

    this.canvas.clearContext(this.canvas.contextTop);
    this.canvas.add(path);
    this.canvas.requestRenderAll();
    path.setCoords();
    this._resetShadow();

    this.canvas.fire('path:created', { path: path });
  }
});

これで、 fabric.ExPencilBrush をつかってCanvasに絵を描くと、パスのデータが単純化された fabric.ExPath がCanvasに追加されます。
Paper.js の path.simplify を実行すると、パスのデータのベジェ曲線は、3次ベジェ曲線になります( fabric.PencilBrush で描画した fabric.Path のベジェ曲線は2次ベジェ曲線)。 path.simplify の引数に与える値が大きいほどパスが単純化されてスムーズな曲線になりますが、元のパスの形状との差が大きくなるので、適宜調整が必要です。

それでは、よいFabric.jsライフを。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

*