星星上的铅笔 · javascript生成随机四位数_web实 ...· 1 周前 · |
爱听歌的筷子 · 如何在Next.js应用程序中获取共享数据? ...· 8 月前 · |
高大的木瓜 · Django, request.user ...· 1 年前 · |
追风的铁链 · oracle数据库无法连接 The ...· 1 年前 · |
鬼畜的铁链 · java - How to use MDC ...· 1 年前 · |
为了制作 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();