Fabricjs mask object with transformation

后端 未结 2 1354
别跟我提以往
别跟我提以往 2021-02-19 04:03

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

相关标签:
2条回答
  • 2021-02-19 04:38

    I implement an exemple with some transformations (scaleX,scaleY,left,top). I'm strugle to find a solution when the inital object have an angle different than 0. For the current solution I need it to divide the maskscale with the object scale and also adjust the positions.

    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>

    You can check here for loadFromJSON support. The only problem remains is when the object is rotated.

    0 讨论(0)
  • 2021-02-19 04:41

    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>

    0 讨论(0)
提交回复
热议问题