【问题标题】:Fabric.js eraser issue canvasFabric.js 橡皮擦问题画布
【发布时间】:2013-10-19 02:45:02
【问题描述】:

我想使用 Fabric.js 在我的网络应用中实现橡皮擦。有没有办法在 Fabric.js 中实现橡皮擦?例如,比如在 MS Paint 中?

【问题讨论】:

    标签: canvas coffeescript html5-canvas fabricjs


    【解决方案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 团队决定在未来将其作为一项功能实现之前,它看起来也不好看。

      【讨论】:

        猜你喜欢
        • 2014-09-11
        • 2011-04-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-27
        相关资源
        最近更新 更多