FabricJS蒙版对象与转换 [英] Fabricjs mask object with transformation

查看:314
本文介绍了FabricJS蒙版对象与转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Fabric.js自由绘图笔刷遮盖对象.如果对象处于其默认位置并且没有任何转换,则可以正常工作.但是,一旦我向对象添加了转换,遮罩就会放置在错误的位置.我不确定该如何解决.有人可以看看吗?

I'm trying to mask an object using Fabric.js free drawing brush. It works fine if the object is in its default position and without any transformations. But once I add transformations to the object, the mask is placed in the wrong position. I'm not sure how to solve this. Can someone take a look?

我希望能够在蒙版之前或之后应用任何转换,而不会弄乱蒙版.

I want to be able to apply any transformations, before or after the mask, without messing up the mask.

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使用对象的中心点处理第一个矩阵(计算带有或不带有角度的对象的中心).第二矩阵是旋转矩阵,第三矩阵是缩放. 要显示带有设置为对象的所有选项的图像,您需要将所有矩阵相乘:

Basically whenever you set an angle, your context matrix has been transformed. In order to mask properly you need to return to initial state of the Transformation Matrices. Fabricjs handles first matrix with center point of an object (calculates center of an object with or without an angle). Second matrix is rotating matrix, and third - scaling. To display image with all options which are set to an object, you need to multiply all Matrices:

(First Matrix * Second Matrix) * Third Matrix

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

So the idea of clipping will be reverse engineering of rotating context and multiplications of matrices: difference between center points of regular object without rotation and center point of the same object but with rotation. After that take result of subtractions and divide by original object scale value.

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>

这篇关于FabricJS蒙版对象与转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆