使用Fabric的
clipTo
属性可以实现此目的,但您必须在
clipTo
函数中'反转'变换(缩放和旋转)。
当您在Fabric中使用
clipTo
属性时,缩放和旋转是在裁剪之后应用的,这意味着裁剪会随图像一起缩放和旋转。您必须通过在
clipTo
属性函数中应用确切的反向变换来抵消这种影响。
我的解决方案涉及使用
Fabric.Rect
作为剪辑区域的“占位符”(这样做有优势,因为您可以使用Fabric移动对象,从而移动剪辑区域)。
请注意,我的解决方案使用
Lo-Dash实用程序库,特别是
_.bind()
(请参阅上下文的代码)。
分解
1. 初始化Fabric
首先,我们需要一个画布:
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
对象一个名为clipFor
的属性,以便clipTo
函数可以通过该属性找到它们想要被裁剪的那个对象:
clipRect1.set({
clipFor: 'pug'
});
canvas.add(clipRect1);
剪辑区域不一定需要实际对象存在,但这样做可以更容易管理,因为您可以使用Fabric来移动它。
3. 剪切函数
我们单独定义将用于图像的clipTo
属性的函数,以避免代码重复:
由于图像对象的angle
属性以度数存储,我们将使用它来将其转换为弧度。
function degToRad(degrees) {
return degrees * (Math.PI / 180);
}
findByClipName()
是一个方便函数,使用 Lo-Dash 来查找要裁剪的图像对象的 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. 使用clipByName()
功能的fabric.Image
对象
最终,可以通过以下方式实例化图像,并使其使用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()
有以下两个原因:
- 我们需要传递一个
Image
对象的引用给clipByName()
。
clipTo
属性传递的是画布上下文,而不是对象。
基本上,_.bind()
让你创建一个版本的函数,该函数使用你指定的对象作为this
上下文。
来源
- https://lodash.com/docs#bind
- https://fabricjs.com/docs/fabric.Object.html#clipTo
- https://html5.litten.com/understanding-save-and-restore-for-the-canvas-context/