Fabric.js キャンバス上の複数のクリッピング領域 質問する

Fabric.js キャンバス上の複数のクリッピング領域 質問する

作るため写真コラージュメーカー私は、オブジェクトベースのクリッピング機能を備えた fabric js を使用しています。この機能は素晴らしいのですが、クリッピング領域内の画像は拡大縮小、移動、回転できません。固定位置のクリッピング領域が必要で、画像はユーザーが望むように固定クリッピング領域内に配置できます。

グーグルで検索したら、非常に近い解決策が見つかりました。

var canvas = new fabric.Canvas('c');
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.rect(10,10,150,150);
ctx.rect(180,10,200,200);
ctx.closePath();
ctx.stroke();
ctx.clip();

ファブリック js キャンバス上の複数のクリッピング領域

あるクリッピング領域の画像が別のクリッピング領域に表示されています。どうすればこれを回避できますか。または、fabric js を使用してこれを実現する別の方法はありますか。

ベストアンサー1

これは、プロパティを使用して Fabric で実現できますclipToが、関数内で変換 (スケールと回転) を「逆転」させる必要がありますclipTo

Fabricでプロパティを使用するとclipTo、スケーリングと回転が適用されますクリッピングは画像に合わせて拡大縮小され、回転します。これに対処するには、逆行するプロパティ関数の変換clipTo

私の解決策は、Fabric.Rectクリップ領域の「プレースホルダー」として機能することです (Fabric を使用してオブジェクトを移動し、クリップ領域を移動できるため、これには利点があります)。

私の解決策は、ローダッシュユーティリティライブラリ、特に_.bind()(コンテキストについてはコードを参照してください)。

フィドルの例


壊す

1. ファブリックを初期化する

まず、もちろんキャンバスが必要です。

var canvas = new fabric.Canvas('c');

2. クリップ領域

var clipRect1 = new fabric.Rect({
    originX: 'left',
    originY: 'top',
    left: 180,
    top: 10,
    width: 200,
    height: 200,
    fill: 'none',
    stroke: 'black',
    strokeWidth: 2,
    selectable: false
});

これらのRectオブジェクトに名前プロパティを指定してclipForclipTo関数がクリップするオブジェクトを見つけられるようにします。

clipRect1.set({
    clipFor: 'pug'
});
canvas.add(clipRect1);

ない持っているクリップ領域の実際のオブジェクトにはなりませんが、Fabric を使用して移動できるため、管理が容易になります。

3. クリッピング機能

コードの重複を避けるために、画像のプロパティで使用される関数をclipTo個別に定義します。

angleImage オブジェクトのプロパティは度単位で保存されるため、これを使用してラジアンに変換します。

function degToRad(degrees) {
    return degrees * (Math.PI / 180);
}

findByClipName()は便利な関数であり、ローダッシュ、クリップする Image オブジェクトの プロパティを持つ を検索しますclipFor(たとえば、下の画像ではnameになります'pug')。

function findByClipName(name) {
    return _(canvas.getObjects()).where({
            clipFor: name
        }).first()
}

そして、これが実際に動作する部分です。

var clipByName = function (ctx) {
    var clipRect = findByClipName(this.clipName);
    var scaleXTo1 = (1 / this.scaleX);
    var scaleYTo1 = (1 / this.scaleY);
    ctx.save();
    ctx.translate(0,0);
    ctx.rotate(degToRad(this.angle * -1));
    ctx.scale(scaleXTo1, scaleYTo1);
    ctx.beginPath();
    ctx.rect(
        clipRect.left - this.left,
        clipRect.top - this.top,
        clipRect.width,
        clipRect.height
    );
    ctx.closePath();
    ctx.restore();
}

注記:this上記の関数でのの使用法については、以下を参照してください。

4.fabric.Imageオブジェクトの使用clipByName()

最後に、次のようにイメージをインスタンス化してclipByName関数を使用するようにすることができます。

var pugImg = new Image();
pugImg.onload = function (img) {    
    var pug = new fabric.Image(pugImg, {
        angle: 45,
        width: 500,
        height: 500,
        left: 230,
        top: 170,
        scaleX: 0.3,
        scaleY: 0.3,
        clipName: 'pug',
        clipTo: function(ctx) { 
            return _.bind(clipByName, pug)(ctx) 
        }
    });
    canvas.add(pug);
};
pugImg.src = 'https://fabricjs.com/lib/pug.jpg';

_.bind()をするのですか?

参照は_.bind()関数。

私がこれを使用している_.bind()理由は次の 2 つです。

  1. Image参照オブジェクトを渡す必要がありますclipByName()
  2. プロパティclipToにはオブジェクトではなくキャンバス コンテキストが渡されます。

基本的に、_.bind()指定したオブジェクトをコンテキストとして使用する関数のバージョンを作成できますthis

出典
  1. https://lodash.com/docs#bind
  2. https://fabricjs.com/docs/fabric.Object.html#clipTo
  3. https://html5.litten.com/understanding-save-and-restore-for-the-canvas-context/

おすすめ記事