当尝试用Fabric.js
遮罩对象时,我有这个赏金开放Fabricjs mask object with transformation。
我正在开发的工具应允许用户在图像对象上绘制蒙版,并在蒙版之前或之后对该对象应用变换(倾斜比例旋转等)。我即将获得此结果,但是有角度的对象仍无法正常工作。
我也在尝试使用toJSON
和loadFromJSON
将该对象保存到数据库中,但是经过几天的尝试,我意识到该解决方案将无法工作,因为从JSON加载时无法访问ctx
范围,因此它们会引发错误。
clipTo: function(ctx) {
mask.set({
left:
-object.width / 2 -
(mask.width / 2) * originalMaskScaleX -
originalObjLeft / originalObjScaleX,
top:
-object.height / 2 -
(mask.height / 2) * originalMaskScaleY -
originalObjTop / originalObjScaleY,
objectCaching: false
});
mask.render(ctx);
}
Fabric.js
是解决此问题的正确方法吗?我应该使用其他东西吗?如果可以使用Fabric.js
完成操作,什么是正确的方法?
答案 0 :(得分:2)
我扩展了fabric.Image
的自定义属性。
我还把面具戴在fabric.Image
上。
对于fabric.Image.fromObject
,在加载图像后,我还需要它同时加载mask(我知道这是一个路径)并附加到图像上。
这是一个快速的实现。我很确定这段代码可以简化。
请告诉我是否有不清楚的信息
canvas = new fabric.Canvas("canvas", {
backgroundColor: "lightgray",
width: 1280,
height: 720,
preserveObjectStacking: true,
selection: false,
stateful: true
});
canvas.isDrawingMode = true;
canvas.freeDrawingBrush.color = "black";
canvas.freeDrawingBrush.width = 2;
canvas.on("path:created", function(options) {
clip(options.path);
});
function clip(path) {
canvas.isDrawingMode = false;
canvas.remove(path);
let mask = new fabric.Path(path.path, {
top: object.top,
left: object.left,
objectCaching: false,
strokeWidth: 0,
scaleX: 1 / object.scaleX,
scaleY: 1 / object.scaleY,
pathOffset: {
x: 0,
y: 0
}
});
object = canvas.getObjects()[0];
object.originalObjLeft = object.left,
object.originalObjTop = object.top,
object.originalMaskScaleX = mask.scaleX,
object.originalMaskScaleY = mask.scaleY,
object.originalObjScaleX = object.scaleX,
object.originalObjScaleY = object.scaleY;
var transformedTranslate = object.translateToGivenOrigin({
x: object.left,
y: object.top
}, object.originX, object.originY, 'center', 'center');
object.originalTransformLeft = transformedTranslate.x - object.getCenterPoint().x;
object.originalTransformTop = transformedTranslate.y - object.getCenterPoint().y;
object.originalAngle = object.angle;
object.clipMask = mask;
object.set({
clipTo: function(ctx) {
ctx.save();
ctx.rotate(-this.originalAngle * Math.PI / 180);
ctx.translate(this.originalTransformLeft / this.originalObjScaleX, this.originalTransformTop / this.originalObjScaleY)
this.clipMask.set({
left: -object.width / 2 - (this.clipMask.width / 2 * this.originalMaskScaleX) - this.originalObjLeft / this.originalObjScaleX,
top: -object.height / 2 - (this.clipMask.height / 2 * this.originalMaskScaleY) - this.originalObjTop / this.originalObjScaleY,
objectCaching: false
});
this.clipMask.render(ctx);
ctx.restore();
}
});
canvas.requestRenderAll();
}
// image
let image = new Image();
image.onload = function() {
object = new fabric.Image(image, {
width: 500,
height: 500,
scaleX: 0.8,
scaleY: 0.8,
angle: 45,
top: 50,
left: 100
});
canvas.add(object);
};
image.src = "http://i.imgur.com/8rmMZI3.jpg";
fabric.util.object.extend(fabric.Image.prototype, {
clipMask: null,
originalObjLeft: 0,
originalObjTop: 0,
originalMaskScaleX: 1,
originalMaskScaleY: 1,
originalObjScaleX: 1,
originalObjScaleY: 1,
originalAngle:0,
originalTransformLeft:0,
originalTransformTop:0
});
fabric.Image.prototype.toObject = (function(toObject) {
return function(propertiesToInclude) {
return fabric.util.object.extend(toObject.call(this, propertiesToInclude), {
clipMask: this.clipMask ? this.clipMask.toObject(propertiesToInclude) : null,
originalObjLeft: this.originalObjLeft,
originalObjTop: this.originalObjTop,
originalMaskScaleX: this.originalMaskScaleX,
originalMaskScaleY: this.originalMaskScaleY,
originalObjScaleX: this.originalObjScaleX,
originalObjScaleY: this.originalObjScaleY,
originalAngle:this.originalAngle,
originalTransformLeft:this.originalTransformLeft,
originalTransformTop:this.originalTransformTop
});
}
})(fabric.Image.prototype.toObject);
fabric.Image.fromObject = (function(fromObject) {
return function(_object, callback) {
fromObject.call(this, _object, (function(callback, _object) {
return function(image) {
if (image.clipMask) {
fabric.Path.fromObject(image.clipMask, (function(callback) {
return function(path) {
path.pathOffset.x = 0;
path.pathOffset.y = 0;
image.clipMask = path;
callback(image);
}
})(callback))
} else {
callback(image);
}
}
})(callback, _object));
return;
}
})(fabric.Image.fromObject)
$("#button1").on('click', function() {
let dataJSON = canvas.toJSON();
canvas.clear();
canvas.loadFromJSON(
dataJSON,
canvas.renderAll.bind(canvas));
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.3.6/fabric.js"></script>
<script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
<button id="button1">SAve/Load JSON</button>
<div class="canvas__wrapper">
<canvas id="canvas" width="1280" height="720"></canvas>
</div>
更新 我更新了代码,从here角度解决了这个问题: