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ライフを。
