我google了,找到非常接近的解决方案
var canvas = new fabric.Canvas('c');
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.rect(10,10,150,150);
ctx.rect(180,200,200);
ctx.closePath();
ctx.stroke();
ctx.clip();
Multiple Clipping Areas on fabric js canvas
其中一个裁剪区域的图像出现在另一裁剪区域中.如何避免这种情况,或者有另一种使用fabric js来完成这种方式的方法.
解决方法
当您在Fabric中使用clipTo属性时,缩放和旋转将在剪辑后应用,这意味着剪切与图像进行缩放和旋转.您必须通过在clipTo属性函数中应用转换的准确相反来对抗.
我的解决方案涉及到一个Fabric.Rect作为剪辑区域的“占位符”(这具有优点,因为您可以使用Fabric来移动对象,从而将剪辑区域移动.
请注意,我的解决方案使用Lo-Dash实用程序库,特别是_.bind()(参见上下文的代码).
Example Fiddle
分解
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对象一个名称属性clipFor,所以clipTo函数可以找到他们想要剪切的对象:
clipRect1.set({
clipFor: 'pug'
});
canvas.add(clipRect1);
不必是剪辑区域的实际对象,但它可以更轻松地进行管理,因为您可以使用Fabric移动它.
剪切功能
我们定义要由图像的clipTo属性单独使用的功能,以避免代码重复:
由于Image对象的angle属性以度为单位存储,我们将使用此属性将其转换为弧度.
function degToRad(degrees) {
return degrees * (Math.PI / 180);
}
findByClipName()是一个方便的函数,它正在使用Lo-Dash,找到要剪切的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();
}
注意:在上面的功能中,请参见下面的使用说明.
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 = 'http://fabricjs.com/lib/pug.jpg';
_.bind()做什么?
请注意,引用包装在_.bind()函数中.
我使用_.bind()有两个原因:
>我们需要将参考图像对象传递给clipByName()
> clipTo属性传递画布上下文,而不是对象.
基本上,_.bind()允许您创建一个使用您指定的对象作为此上下文的函数的版本.
来源
> http://lodash.com/docs#bind
> http://fabricjs.com/docs/fabric.Object.html#clipTo
> http://html5.litten.com/understanding-save-and-restore-for-the-canvas-context/