ep4*_*p4f 18 photo image-clipping html5-canvas fabricjs
为了制作Photo Collage Maker,我使用具有基于对象剪辑功能的fabric js.此功能很棒但是剪切区域内的图像无法缩放,移动或旋转.我希望固定位置剪切区域和图像可以根据用户需要定位在固定剪切区域内.
我用Google搜索并找到非常接近的解决方案
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();
Run Code Online (Sandbox Code Playgroud)
其中一个剪辑区域的图像出现在另一个剪辑区域中.我怎样才能避免这种情况,或者是否有另一种使用结构js实现此目的的方法.
nat*_*eta 31
这可以使用Fabric使用clipTo
属性来完成,但是您必须在clipTo
函数中"反转"转换(缩放和旋转).
clipTo
在Fabric中使用该属性时,剪切后会应用缩放和旋转,这意味着剪裁会随图像缩放并旋转.您必须通过在属性函数中应用完全相反的转换来对此进行反击clipTo
.
我的解决方案涉及将Fabric.Rect
服务作为剪辑区域的"占位符"(这具有优势,因为您可以使用Fabric来移动对象,从而移动剪辑区域.
请注意,我的解决方案使用Lo-Dash实用程序库,尤其适用于_.bind()
(请参阅上下文代码).
首先,我们想要我们的画布,当然:
var canvas = new fabric.Canvas('c');
Run Code Online (Sandbox Code Playgroud)
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
});
Run Code Online (Sandbox Code Playgroud)
我们为这些Rect
对象提供了一个name属性,clipFor
因此clipTo
函数可以找到它们想要剪切的对象:
clipRect1.set({
clipFor: 'pug'
});
canvas.add(clipRect1);
Run Code Online (Sandbox Code Playgroud)
剪辑区域不必具有实际对象,但它使管理更容易,因为您可以使用Fabric移动它.
我们分别定义图像clipTo
属性将使用的函数,以避免代码重复:
由于angle
Image对象的属性以度为单位存储,我们将使用它将其转换为弧度.
function degToRad(degrees) {
return degrees * (Math.PI / 180);
}
Run Code Online (Sandbox Code Playgroud)
findByClipName()
是一个便利函数,它使用Lo-Dash来查找具有clipFor
要剪裁的Image对象的属性(例如,在下图中,name
将是'pug'
):
function findByClipName(name) {
return _(canvas.getObjects()).where({
clipFor: name
}).first()
}
Run Code Online (Sandbox Code Playgroud)
这是完成工作的部分:
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();
}
Run Code Online (Sandbox Code Playgroud)
注意:请参阅下文,了解this
上述功能的使用说明.
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 = 'https://fabricjs.com/lib/pug.jpg';
Run Code Online (Sandbox Code Playgroud)
_.bind()
办?请注意,引用包含在_.bind()
函数中.
我正在使用_.bind()
以下两个原因:
Image
对象clipByName()
clipTo
属性传递画布上下文,而不是对象.基本上,_.bind()
允许您创建使用您指定的对象作为this
上下文的函数版本.
Pro*_*Inc 11
我已经调整了@natchiketa的解决方案,因为剪辑区域的定位没有正确定位并且在旋转时都是不稳定的.但现在一切似乎都很好.看看这个修改过的小提琴:http: //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();
}
Run Code Online (Sandbox Code Playgroud)
我找到两个小捕获:
更新到Promlnc的答案.
您需要替换上下文转换的顺序才能执行正确的裁剪.
否则,您将错误地剪切对象 - 当您在不保持纵横比(仅更改一个维度)的情况下进行缩放.
代码(69-72):
ctx.translate( ctxLeft, ctxTop );
ctx.rotate(degToRad(this.angle * -1));
ctx.scale(scaleXTo1, scaleYTo1);
Run Code Online (Sandbox Code Playgroud)
替换为:
ctx.translate( ctxLeft, ctxTop );
ctx.scale(scaleXTo1, scaleYTo1);
ctx.rotate(degToRad(this.angle * -1));
Run Code Online (Sandbox Code Playgroud)
见:http: //jsfiddle.net/ZxYCP/185/
正确的结果:
更新1:
我开发了多边形剪辑功能. http://jsfiddle.net/ZxYCP/198/