为了制作Photo Collage Maker,我使用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();
Multiple Clipping Areas on fabric js canvas
其中一个剪切区域的图像已经出现在另一个剪切区域中。我如何避免这一点,或者有没有其他方法可以使用fabric js来实现这一点。
发布于 2013-06-14 12:30:34
这可以通过使用clipTo
属性的Fabric来完成,但是您必须在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
属性单独使用的函数,以避免代码重复:
由于Image对象的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()
有以下两个原因:
我们需要向clipByName()
clipTo
属性传递的是画布上下文,而不是对象。基本上,_.bind()
允许您创建一个使用您指定为this
上下文的对象的函数版本。
资料来源
发布于 2014-07-23 04:55:00
我已经通过@natchiketa调整了解决方案,因为剪辑区域的定位不正确,并且在旋转时都不稳定。但现在一切似乎都很好。看看这个修改过的小提琴:https://jsfiddle.net/PromInc/ZxYCP/
唯一真正的更改是在@natchiketa提供的代码的步骤3的clibByName函数中进行的。下面是更新后的函数:
var clipByName = function (ctx) {
this.setCoords();
var clipRect = findByClipName(this.clipName);
var scaleXTo1 = (1 / this.scaleX);
var scaleYTo1 = (1 / this.scaleY);
ctx.save();
var ctxLeft = -( this.width / 2 ) + clipRect.strokeWidth;
var ctxTop = -( this.height / 2 ) + clipRect.strokeWidth;
var ctxWidth = clipRect.width - clipRect.strokeWidth + 1;
var ctxHeight = clipRect.height - clipRect.strokeWidth + 1;
ctx.translate( ctxLeft, ctxTop );
ctx.rotate(degToRad(this.angle * -1));
ctx.scale(scaleXTo1, scaleYTo1);
ctx.beginPath();
ctx.rect(
clipRect.left - this.oCoords.tl.x,
clipRect.top - this.oCoords.tl.y,
ctxWidth,
ctxHeight
);
ctx.closePath();
ctx.restore();
}
我发现了两个小问题:
发布于 2015-09-14 11:40:41
更新为@Promlnc答案。
您需要替换上下文转换的顺序,以便执行适当的裁剪。
否则,当你缩放而不保持纵横比(只改变一个维度)时,你会得到错误的裁剪对象。
代码(69-72):
ctx.translate( ctxLeft, ctxTop );
ctx.rotate(degToRad(this.angle * -1));
ctx.scale(scaleXTo1, scaleYTo1);
替换为:
ctx.translate( ctxLeft, ctxTop );
ctx.scale(scaleXTo1, scaleYTo1);
ctx.rotate(degToRad(this.angle * -1));
看看这个:https://jsfiddle.net/ZxYCP/185/
正确的结果:
更新1:
我开发了一个按多边形裁剪的功能:https://jsfiddle.net/ZxYCP/198/
https://stackoverflow.com/questions/16437696
复制相似问题