Search code examples
javascripthtml5-canvasfabricjsclipfabricjs2

How to fix FabricJS scaled polygon clipping offset


I'am trying to clip the FabricJS rect shape to the polygon shape. The clipping works okay until the polygon shape which need to be clipped is now scaled. After this there is some weird offset that is caused by the polygon clipping.

Can anyone help me how can i fix the function to prevent the polygon offset issue when clip object is scaled.

This is how it looks before scalling. The clipping works fine

  1. Image => https://i.sstatic.net/u7JbH.png

And then there is the problem when the polygon is scaled.

2: Image => https://i.sstatic.net/qoEWG.png

Here is the code on fiddle with the clipping function

https://jsfiddle.net/0xpvc9uq/

So if there is anyone who knows whats the point and how can I fix it I would appriciate it.

Thx

var canvas = new fabric.Canvas('c');

var rect1 = new fabric.Rect({
    left: 0, top: 0,
    width: 900, height: 900,
    fill: 'blue',
    selectable: false,
      clipTo: clipRegion,
    scaleX: 1.5,
    scaleY: 1.5

});

var clipPoly = new fabric.Polygon([
        { x: 180, y: 10 },
        { x: 300, y: 50 },
        { x: 300, y: 180 },
        { x: 180, y: 220 }
    ], {
    originX: 'left',
    originY: 'top',
    left: 180,
    top: 10,
    fill: 'transparent', /* use transparent for no fill */
    strokeWidth: 0,
    selectable: false,
    strokeWidth: 1,
    stroke: "red",
    scaleX: 1.3,
    scaleY: 1.3
});

canvas.add(rect1, clipPoly);

function clipRegion (ctx) {
  rect1.setCoords();

    const clipObj = clipPoly;
    const scaleXTo1 = (1 / rect1.scaleX);
    const scaleYTo1 = (1 / rect1.scaleY);

    ctx.save();

    const ctxLeft = -( rect1.width / 2 ) - clipObj.strokeWidth - rect1.strokeWidth;
    const ctxTop = -( rect1.height / 2 ) - clipObj.strokeWidth - rect1.strokeWidth;

    ctx.translate( ctxLeft, ctxTop );
    ctx.scale(scaleXTo1, scaleYTo1);
    ctx.rotate((rect1.angle * -1) * (Math.PI / 180));
    ctx.beginPath();

    const matrix = clipPoly.calcTransformMatrix();

    let points = [];
    clipObj.points.forEach( (point) => {
      points.push({
        x:  ((point.x * matrix[0]) + (clipObj.strokeWidth * clipObj.scaleX)) - rect1.oCoords.tl.x,
        y:  ((point.y * matrix[3]) + (clipObj.strokeWidth * clipObj.scaleY)) - rect1.oCoords.tl.y
      });
    });

    ctx.moveTo(points[0].x, points[0].y);

    points.forEach((point) => {
      ctx.lineTo(point.x, point.y);
    });

    ctx.lineTo(points[0].x, points[0].y);
    ctx.closePath();
    ctx.restore(); 
}



Solution

  • I discovered that there is also another approach that can be used and that solves all the problem.

    The clipRegion function now looks like:

    function clipRegion (ctx) {
        ctx.save();
    
        ctx.setTransform(1, 0, 0, 1, 0, 0);
        clipPoly.render(ctx);
    
        ctx.restore(); 
    }
    

    Which makes the rendering okay. If still anyone have other way to fix the above problem, I would like to see the answer