【问题标题】:Fabricjs mask object with transformation带有转换的 Fabricjs 遮罩对象
【发布时间】:2019-03-15 16:15:29
【问题描述】:

我正在尝试使用Fabric.js 免费画笔来遮盖对象。如果对象处于其默认位置并且没有任何转换,则它可以正常工作。但是一旦我向对象添加了变换,蒙版就会被放置在错误的位置。我不知道如何解决这个问题。有人可以看看吗?

我希望能够在遮罩之前或之后应用任何转换,而不会弄乱遮罩。

let canvas = new fabric.Canvas("canvas", {
    backgroundColor: "lightgray",
    width: 1280,
    height: 720,
    preserveObjectStacking: true,
    selection: false,
    stateful: true
});

canvas.isDrawingMode = true;
canvas.freeDrawingBrush.color = "black";
canvas.freeDrawingBrush.width = 2;

canvas.on("path:created", function(options) {
    clip(options.path);
});

function clip(path) {
    canvas.isDrawingMode = false;
    canvas.remove(path);

    let mask = new fabric.Path(path.path, {
        top: object.top,
        left: object.left,
        objectCaching: false,
        strokeWidth: 0,
        pathOffset: {
            x: 0,
            y: 0
        }
    });

    let originalObjLeft = object.left,
        originalObjTop = object.top;

    object.set({
        clipTo: function(ctx) {
            mask.set({
                left: -object.width / 2 - mask.width / 2 - originalObjLeft,
                top: -object.height / 2 - mask.height / 2 - originalObjTop,
                objectCaching: false
            });
            mask.render(ctx);
        }
    });

    canvas.requestRenderAll();
}

// image

let image = new Image();
let object;

image.onload = function() {
    object = new fabric.Image(image, {
        width: 500,
        height: 500,
        //scaleX: 0.8,
        //scaleY: 0.8,
        //angle: 45,
        top: 50,
        left: 300
    });

    canvas.add(object);
};

image.src = "http://i.imgur.com/8rmMZI3.jpg";

【问题讨论】:

    标签: fabricjs


    【解决方案1】:

    我实现了一个带有一些转换的示例 (scaleX,scaleY,left,top)。 当初始对象的角度不同于 0 时,我很难找到解决方案。对于当前的解决方案,我需要将 maskscale 与 object 比例分开并调整位置。

    let canvas = new fabric.Canvas("canvas", {
        backgroundColor: "lightgray",
        width: 1280,
        height: 720,
        preserveObjectStacking: true,
        selection: false,
        stateful: true
    });
    
    canvas.isDrawingMode = true;
    canvas.freeDrawingBrush.color = "black";
    canvas.freeDrawingBrush.width = 2;
    
    canvas.on("path:created", function(options) {
        clip(options.path);
    });
    
    function clip(path) {
        canvas.isDrawingMode = false;
        canvas.remove(path);
    
        let mask = new fabric.Path(path.path, {
            top: object.top,
            left: object.left,
            objectCaching: false,
            strokeWidth: 0,
        		scaleX : 1/object.scaleX,
            	scaleY : 1/object.scaleY,
            pathOffset: {
                x: 0,
                y: 0
            }
        });
    
        let originalObjLeft = object.left,
            originalObjTop = object.top,
            originalMaskScaleX = mask.scaleX,
             originalMaskScaleY = mask.scaleY,
              originalObjScaleX = object.scaleX,
             originalObjScaleY = object.scaleY;
    
        object.set({
            clipTo: function(ctx) {
           		
                mask.set({
                    left: -object.width / 2   -( mask.width / 2  * originalMaskScaleX) - originalObjLeft/originalObjScaleX ,
                    top: -object.height / 2   -( mask.height / 2 * originalMaskScaleY) - originalObjTop/originalObjScaleY ,
                    objectCaching: false
                });
                mask.render(ctx);
            }
        });
    
        canvas.requestRenderAll();
    }
    
    // image
    
    let image = new Image();
     
    
    image.onload = function() {
        object = new fabric.Image(image, {
            width: 500,
            height: 500,
            scaleX: 0.8,
            scaleY: 0.8,
           // angle: 45,
            top: 50,
            left: 100
        });
    
        canvas.add(object);
    };
    
    image.src = "http://i.imgur.com/8rmMZI3.jpg";
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.3.6/fabric.js"></script>
    <div class="canvas__wrapper">
      <canvas id="canvas" width="1280" height="720"></canvas>
    </div>

    您可以查看 here 以获得 loadFromJSON 支持。 唯一的问题是对象旋转时。

    【讨论】:

    • 我认为这不能正常工作。放置蒙版后,调整对象的大小会弄乱蒙版。
    • 感谢您的帮助。
    • @marius 我也有一个关于模式的问题。保存并编辑它们后,我得到黑色覆盖。你能帮帮我吗?
    【解决方案2】:

    基本上,每当您设置一个角度时,您的上下文矩阵就会被转换。为了正确屏蔽,您需要返回转换矩阵的初始状态。 Fabricjs 处理具有对象中心点的第一个矩阵(计算带或不带角度的对象的中心)。第二个矩阵是旋转矩阵,第三个是缩放矩阵。 要显示设置为对象的所有选项的图像,您需要将所有矩阵相乘:

    (First Matrix * Second Matrix) * Third Matrix
    

    因此,裁剪的想法将是旋转上下文和矩阵乘法的逆向工程: 没有旋转的常规物体的中心点与有旋转的同一物体的中心点之间的差异。然后取减法结果除以原始对象比例值。

    let canvas = new fabric.Canvas("canvas", {
    backgroundColor: "lightgray",
    width: 1280,
    height: 720,
    preserveObjectStacking: true,
    selection: false,
    stateful: true
    });
    
    const angle = 45;
    let objectHasBeenRotated = false;
    
    canvas.isDrawingMode = true;
    canvas.freeDrawingBrush.color = "black";
    canvas.freeDrawingBrush.width = 2;
    
    canvas.on("path:created", function (options) {
    clip(options.path);
    });
    
    function clip(path) {
    canvas.isDrawingMode = false;
    canvas.remove(path);
    
    let mask = new fabric.Path(path.path, {
        top: 0,
        left: 0,
        objectCaching: false,
        strokeWidth: 0,
        scaleX: 1 / object.scaleX,
        scaleY: 1 / object.scaleY,
        pathOffset: {
            x: 0,
            y: 0,
        }
    });
    
    let originalObjLeft = object.left,
        originalObjTop = object.top,
        originalMaskScaleX = mask.scaleX,
        originalMaskScaleY = mask.scaleY,
        originalObjScaleX = object.scaleX,
        originalObjScaleY = object.scaleY,
        transformedTranslate = object.translateToGivenOrigin({
            x: object.left,
            y: object.top
        }, object.originX, object.originY, 'center', 'center'),
        originalTransformLeft = transformedTranslate.x - object.getCenterPoint().x,
        originalTransformTop = transformedTranslate.y - object.getCenterPoint().y;
    object.set({
        clipTo: function (ctx) {
    
            ctx.save();
            ctx.rotate(-angle * Math.PI / 180);
    
            ctx.translate(originalTransformLeft / originalObjScaleX, originalTransformTop / originalObjScaleY)
    
            mask.set({
                left: -object.width / 2 - (mask.width / 2 * originalMaskScaleX) - originalObjLeft / originalObjScaleX,
                top: -object.height / 2 - (mask.height / 2 * originalMaskScaleY) - originalObjTop / originalObjScaleY,
    
                objectCaching: false
            });
            mask.render(ctx);
            ctx.restore();
        }
    });
    
    canvas.requestRenderAll();
    }
    
    
    // image
    
    let image = new Image();
    
    
    image.onload = function () {
    object = new fabric.Image(image, {
        width: 500,
        height: 500,
        scaleX: 0.8,
        scaleY: 0.8,
        angle: angle,
        top: 50,
        left: 300,
        id: 'pug'
    });
    
    canvas.add(object);
    
    };
    
    image.src = "http://i.imgur.com/8rmMZI3.jpg";
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.3.6/fabric.js"></script>
    <div class="canvas__wrapper">
      <canvas id="canvas" width="1280" height="720"></canvas>
    </div>

    【讨论】:

    • 我在视网膜上,也许正因为如此,它不能从这里工作。
    • 现在蒙版已正确放置,但旋转对象时,蒙版位置混乱。
    • @lolol,如果它解决了你的问题,请接受答案,以便其他开发人员知道解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-20
    • 1970-01-01
    • 1970-01-01
    • 2022-07-13
    • 2020-10-18
    相关资源
    最近更新 更多