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 橡皮擦问题画布的主要内容,如果未能解决你的问题,请参考以下文章

HTML5 画布橡皮擦

Canvas-橡皮擦在画布保存为图像后在画布上绘制黑色线条

适用于 Android 画布的橡皮擦/橡胶

Canvas 橡皮擦效果

js实现画布绘图橡皮擦除刮刮卡效果

如何撤消 HTML5 Canvas 绘图应用程序的橡皮擦操作