Fabric.js を使用してCanvas上にフリーハンドで描いた線を toSVG
や
toJSON
でシリアライズしてみると fabric.Path
のベジェ曲線のデータが結構な量になることがわかります。 Paper.js の path.simplify
を利用することで、 fabric.Path
のデータ量を減らしてスムーズな線を簡単に描画することができました。
前回つくった fabric.Path
のサブクラス fabric.ExPath
と fabric.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.ExPencilBrush
で fabric.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ライフを。