Fabric.js 橡皮擦问题画布
Posted
技术标签:
【中文标题】Fabric.js 橡皮擦问题画布【英文标题】:Fabric.js eraser issue canvas 【发布时间】:2013-10-19 02:45:02 【问题描述】:我想使用 Fabric.js 在我的网络应用中实现橡皮擦。有没有办法在 Fabric.js 中实现橡皮擦?例如,比如在 MS Paint 中?
【问题讨论】:
【参考方案1】:Fabric 中没有内置橡皮擦,实现起来有点困难。
Fabric 的特点是一切都是基于对象的,而且大多数东西也是基于向量的。
与原生画布不同,我们不能只擦除全局位图上的一些像素。我们下面有整个对象模型,画布输出是所有这些对象渲染到画布上的简单循环。
我们可以模拟橡皮擦的一种方法可能是在画布上进行某种覆盖。并在其上画出“擦除”的线条,给人一种底层物体被抹去的错觉。
但是这仍然存在复杂性:
我们如何序列化这个层(JSON 或 SVG)? 如果您擦除了一半先前绘制的路径,然后想要使用已擦除的形状怎么办?形状本身需要修改;覆盖不起作用。 橡皮擦会只影响形状还是影响背景颜色?背景图片呢?可能还有更多我当时没有想到的问题。
【讨论】:
【参考方案2】:我刚刚用 Fabric 写了我的橡皮擦,我希望也能回答@kangax 提出的问题。
首先,如果你想要一个手写橡皮擦,你应该像这样构建一个对象:
canvas.freeDrawingBrush = new fabric.PencilBrush(canvas);
然后我在这里稍微破解了实际的织物库(v. 2.4.3):
createPath: function(pathData)
var path = new fabric.Path(pathData,
fill: null,
stroke: this.color,
strokeWidth: this.width,
strokeLineCap: this.strokeLineCap,
strokeMiterLimit: this.strokeMiterLimit,
strokeLineJoin: this.strokeLineJoin,
strokeDashArray: this.strokeDashArray,
// ADDED BY AZ (24 Nov 2018)
globalCompositeOperation: this.globalCompositeOperation,
id: this.id
);
使用globalCompositeOperation
你可以管理你的canvas.freeDrawingBrush
来绘制一条彩色路径(你想要的颜色,我选择红色,但你也可以选择画布的背景颜色):
canvas.isDrawingMode = 1;
canvas.freeDrawingBrush.color = "red";
canvas.freeDrawingBrush.width = 10;
canvas.freeDrawingBrush.globalCompositeOperation = 'destination-out';
canvas.freeDrawingBrush.id = 'erasure';
ctx.beginPath(); // the context of canvas
canvas.renderAll();
因此,当您将鼠标移动到画布上时,您会看到一条红色路径。当您向上移动鼠标时,最终会创建路径并应用 gCO,从而擦除红色路径下的所有内容。
好吧,如果你想保存画布,我更喜欢使用canvas.toSVG()
函数(如果你能够管理它,它非常适合视网膜屏幕)。
因此,要将画布保存为 SVG,您只需要这一行 canvas.toSVG()
,您可以将结果存储在某处。
当你想恢复画布时,你还应该管理“擦除”id,这样你就可以使用我的恢复功能:
function restoreSketch(imageSVG)
fabric.loadSVGFromString(imageSVG, function (objects, options)
$.each(objects, function (index, value)
if (value.id && value.id == 'erasure')
value.set(
globalCompositeOperation: 'destination-out'
); //set gCO for value
);
var obj = fabric.util.groupSVGElements(objects, options);
canvas.add(obj).renderAll();
);
我希望对每个对 Fabric.js 感到头疼的人有用
编辑:正如@Benni 所建议的,与擦除相关的行可以被替换。如果您想将它们固定到画布上,您可以使用 lockMovementX 和 lockMovementY 稍微更改代码。 所以,在fabric.js lib中,在
之后globalCompositeOperation: this.globalCompositeOperation,
添加:
lockMovementX: this.lockMovementX,
lockMovementY: this.lockMovementY,
然后,在您的代码中,在canvas.freeDrawingBrush.id = 'erasure';
之后添加:
canvas.freeDrawingBrush.lockMovementX = true;
canvas.freeDrawingBrush.lockMovementY = true;
【讨论】:
这是个好主意,但是如果您使用 Fabric.js 进行选择,则可以选择这些透明线并移动它们。知道如何解决这个问题吗? 好主意,但是如果您想支持其他对象的选择,那效果并不好。透明线的移动现在被锁定(应该添加 lockScaling 和 lockRotation)。如果您移动任何非透明对象,则透明对象会停留在最后一个位置,这会让用户感到困惑。我也考虑过移动透明线或者是否有办法重绘对象..【参考方案3】:我在这里为解决方案编写了一些代码,并解释了它是如何工作的: https://github.com/fabricjs/fabric.js/issues/1225#issuecomment-499620550
类似于@Zappescu 的回答,我对内部代码进行了一些调整以达到效果;可能有更好的方法,比如当路径被画布中的 'path:created' 事件触发时捕获路径,但在 FabricJS 团队决定在未来将其作为一项功能实现之前,它看起来也不好看。
【讨论】:
以上是关于Fabric.js 橡皮擦问题画布的主要内容,如果未能解决你的问题,请参考以下文章