我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()
(参见上下文的代码).
分解
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()有两个原因:
>我们需要将参考图像对象传递给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/