Fabric JS 2.4.1 ClipPath 裁剪不适用于动态创建的矩形掩码

Fabric JS 2.4.1 ClipPath Crop Not Working with a Dynamically Created rect Mask

我正在使用 fabric js 2.4.1 制作一个编辑器,并且已经完成了除动态图像裁剪之外的所有功能。该功能涉及使用鼠标在图像上创建一个矩形并单击裁剪按钮。

我已经使用静态创建的矩形成功完成了概念验证,但无法在我的动态代码中呈现它。我不认为问题与动态创建的矩形有关,但我似乎无法隔离问题。它必须是我忽略的简单东西,我认为问题可能出在我的裁剪按钮代码中。

    document.getElementById("crop").addEventListener("click", function() {
        if (target !== null && mask !== null) {
            mask.setCoords();
            target.clipPath = mask; // THIS LINE IS NOT WORKING!!!
            //target.selectable = true;
            target.setCoords();
            console.log(target);
            canvas.renderAll();
            //canvas.remove(mask);
        }
    });

这里是fiddle有问题的动态代码: https://jsfiddle.net/Larry_Robertson/mqrv5fnt/

这是我从中获得概念证明的静态代码的 fiddle: https://jsfiddle.net/Larry_Robertson/f34q67op/

动态版源代码:

HTML

<canvas id="c" width="500" height="500" style="border:1px solid #ccc"></canvas>
<button id="crop">Crop</button>

JS

    var canvas = new fabric.Canvas('c', {
        selection: true
    });

    var rect, isDown, origX, origY, done, object, mask, target;

    var src = "http://fabricjs.com/lib/pug.jpg";
    fabric.Image.fromURL(src, function(img) {
        img.selectable = false;
        img.id = 'image';
        object = img;
        canvas.add(img);
    });

    canvas.on('object:added', function(e) {
        target = null;
        mask = null;
        canvas.forEachObject(function(obj) {
            //alert(obj.get('id'));
            var id = obj.get('id');
            if (id === 'image') {
                target = obj;
            }
            if (id === 'mask') {
                //alert('mask');
                mask = obj;
            }
        });
    });

    document.getElementById("crop").addEventListener("click", function() {
        if (target !== null && mask !== null) {
            mask.setCoords();
            target.clipPath = mask; // THIS LINE IS NOT WORKING!!!
            //target.selectable = true;
            target.setCoords();
            console.log(target);
            canvas.renderAll();
            //canvas.remove(mask);
        }
    });

    canvas.on('mouse:down', function(o) {
        if (done) {
            canvas.renderAll();
            return;
        }
        isDown = true;
        var pointer = canvas.getPointer(o.e);
        origX = pointer.x;
        origY = pointer.y;
        rect = new fabric.Rect({
            left: origX,
            top: origY,
            //originX: 'left',
            //originY: 'top',
            width: pointer.x - origX,
            height: pointer.y - origY,
            //angle: 0,
            fill: 'rgba(255,0,0,0.3)',
            transparentCorners: false,
            //selectable: true,
            id: 'mask'
        });
        canvas.add(rect);
        canvas.renderAll();
    });

    canvas.on('mouse:move', function(o) {
        if (done) {
            canvas.renderAll();
            return;
        }
        if (!isDown) return;
        var pointer = canvas.getPointer(o.e);

        if (origX > pointer.x) {
            rect.set({
                left: Math.abs(pointer.x)
            });
        }
        if (origY > pointer.y) {
            rect.set({
                top: Math.abs(pointer.y)
            });
        }

        rect.set({
            width: Math.abs(origX - pointer.x)
        });
        rect.set({
            height: Math.abs(origY - pointer.y)
        });


        canvas.renderAll();
    });

    canvas.on('mouse:up', function(o) {
        if (done) {
            canvas.renderAll();
            return;
        }
        isDown = false;

        //rect.selectable = true;
        rect.set({
            selectable: true
        });
        rect.setCoords();
        canvas.setActiveObject(rect);
        canvas.bringToFront(rect);
        canvas.renderAll();
        //alert(rect);
        rect.setCoords();
        object.clipPath = rect;
        object.selectable = true;
        object.setCoords();
        canvas.renderAll();
        //canvas.remove(rect);
        done = true;
    });

您需要将图像上的 dirty 参数设置为 true,这样对象的缓存将在下次渲染调用时重新渲染。 这是 fiddle: https://jsfiddle.net/mqrv5fnt/115/

 var canvas = new fabric.Canvas('c', {
  selection: true
});

var rect, isDown, origX, origY, done, object, mask, target;

var src = "http://fabricjs.com/lib/pug.jpg";
fabric.Image.fromURL(src, function(img) {
  img.selectable = false;
  img.id = 'image';
  object = img;
  canvas.add(img);
});

canvas.on('object:added', function(e) {
  target = null;
  mask = null;
  canvas.forEachObject(function(obj) {
    //alert(obj.get('id'));
    var id = obj.get('id');
    if (id === 'image') {
      target = obj;
    }
    if (id === 'mask') {
      //alert('mask');
      mask = obj;
    }
  });
});

document.getElementById("crop").addEventListener("click", function() {
  if (target !== null && mask !== null) {

    mask.setCoords();
    target.clipPath = mask; // THIS LINE IS NOT WORKING!!!
    target.dirty=true;
    //target.selectable = true;
    target.setCoords();
    canvas.remove(mask);
    canvas.renderAll();
    //canvas.remove(mask);
  }
});

canvas.on('mouse:down', function(o) {
  if (done) {
    canvas.renderAll();
    return;
  }
  isDown = true;
  var pointer = canvas.getPointer(o.e);
  origX = pointer.x;
  origY = pointer.y;
  rect = new fabric.Rect({
    left: origX,
    top: origY,
    //originX: 'left',
    //originY: 'top',
    width: pointer.x - origX,
    height: pointer.y - origY,
    //angle: 0,
    fill: 'rgba(255,0,0,0.3)',
    transparentCorners: false,
    //selectable: true,
    id: 'mask'
  });
  canvas.add(rect);
  canvas.renderAll();
});

canvas.on('mouse:move', function(o) {
  if (done) {
    canvas.renderAll();
    return;
  }
  if (!isDown) return;
  var pointer = canvas.getPointer(o.e);

  if (origX > pointer.x) {
    rect.set({
      left: Math.abs(pointer.x)
    });
  }
  if (origY > pointer.y) {
    rect.set({
      top: Math.abs(pointer.y)
    });
  }

  rect.set({
    width: Math.abs(origX - pointer.x)
  });
  rect.set({
    height: Math.abs(origY - pointer.y)
  });


  canvas.renderAll();
});

canvas.on('mouse:up', function(o) {
  if (done) {
    canvas.renderAll();
    return;
  }
  isDown = false;

  //rect.selectable = true;
  rect.set({
    selectable: true
  });
  rect.setCoords();
  canvas.setActiveObject(rect);
  canvas.bringToFront(rect);
  canvas.renderAll();
  //alert(rect);
  rect.setCoords();
  object.clipPath = rect;
  object.selectable = true;
  object.setCoords();
  canvas.renderAll();
  //canvas.remove(rect);
  done = true;
});