Fabric JS 2.4.1 ClipPath Crop 不适用于动态创建的矩形蒙版

Posted

技术标签:

【中文标题】Fabric JS 2.4.1 ClipPath Crop 不适用于动态创建的矩形蒙版【英文标题】:Fabric JS 2.4.1 ClipPath Crop Not Working with a Dynamically Created rect Mask 【发布时间】:2019-03-07 18:54:23 【问题描述】:

我正在使用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);
        
    );

这是有问题的动态代码的一个小提琴: https://jsfiddle.net/Larry_Robertson/mqrv5fnt/

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

动态版源码:

HTML

<canvas id="c"   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;
    );

【问题讨论】:

【参考方案1】:

您需要将图像上的脏参数设置为true,以便在下次渲染调用时重新渲染对象的缓存。 这是小提琴: 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;
);

【讨论】:

非常感谢马吕斯!这对我行得通。我仍然有一些定位问题,但我很确定我能解决这个问题。 这是我的小提琴,它也解决了定位问题。谢谢大家。 jsfiddle.net/Larry_Robertson/vocufy2q 我不确定这是否应该作为第二个问题提交,如果应该,请告诉我,我将删除它。尽管修复效果很好,但我注意到最终剪辑的图像仍然保留了原始图像的高度和宽度。有没有办法在不改变纵横比的情况下修剪剩余的空白或调整大小? 这与基本问题无关。需要查看官方文档。fabricjs.com/docs/fabric.Image.html。你需要使用cropX、cropY、width和height。

以上是关于Fabric JS 2.4.1 ClipPath Crop 不适用于动态创建的矩形蒙版的主要内容,如果未能解决你的问题,请参考以下文章

Fabric JS clipPath:裁剪后如何使图像适合画布?

SVG.js Mask覆盖和ClipPath裁剪

带有 clipPath 的 div 的单击事件在 angular.js 中不起作用

Hyperledger Fabric学习笔记2——超级账本介绍

如何使 ClipPath 的背景透明?

Flutter - ClipPath + AnimatedContainer - 路径动画不正确