Fabric js : how to apply round corner to path & po

2019-08-09 09:44发布

问题:

I am working on fabricjs app & i need to draw a path & polygon shapes with round corner I did't get any fabric js parameter to do this & I also search but didn't get any result matching with my requirement

Can anyone describe me how draw a path & polygon shapes with round corner in detail with step by step , I need to draw various shapes.

eg- i need round corners at red dots as in image

canvas = new fabric.Canvas('canvas');
var  path = new fabric.Path('M 170.000 210.000L 217.023 234.721 L 208.042 182.361 L 246.085 145.279 L 193.511 137.639 L 170.000 90.000 L 146.489 137.639 L 93.915 145.279 L 131.958 182.361 L 122.977 234.721 L 170.000 210.000');
path.set({ left: 120, top: 120 });
canvas.add(path);
var pol = new fabric.Polygon([
  {x: 200, y: 0},
  {x: 250, y: 50},
  {x: 250, y: 100},
  {x: 150, y: 100},
  {x: 150, y: 50} ], {
    left: 250,
    top: 150,
    angle: 0,
    fill: 'green'
  }
);
canvas.add(pol);
<script src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.5.0/fabric.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id='canvas' width="500" height="400" style="border:#000 1px solid;"></canvas>

回答1:

There is no embedded function to add rounded corners to shapes. What you can use is the drawing canvas property "lineJoin" that is accessible for every path using object.strokeLineJoin = 'round'; To have a visible effect you have to use a big stroke. i used 20 here to make the effect visible.

canvas = new fabric.Canvas('canvas');
var  path = new fabric.Path('M 170.000 210.000L 217.023 234.721 L 208.042 182.361 L 246.085 145.279 L 193.511 137.639 L 170.000 90.000 L 146.489 137.639 L 93.915 145.279 L 131.958 182.361 L 122.977 234.721 L 170.000 210.000');
path.set({ left: 120, top: 120, strokeLineJoin: 'round', strokeWidth: 20, stroke: 'black' });
canvas.add(path);
var pol = new fabric.Polygon([
  {x: 200, y: 0},
  {x: 250, y: 50},
  {x: 250, y: 100},
  {x: 150, y: 100},
  {x: 150, y: 50} ], {
    left: 250,
    top: 150,
    angle: 0,
    fill: 'green',
    strokeLineJoin: 'round',
    strokeWidth: 20,
    stroke: 'green'
  }
);
canvas.add(pol);
<script src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.5.0/fabric.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id='canvas' width="500" height="400" style="border:#000 1px solid;"></canvas>



回答2:

There doesn't seem to be such an option in fabricjs Polygon constructor.

What you could do however, is to set the strokeLineJoin of your object to 'rounded', apply a huge stroke of the same color as your fill, and down-scale the shape.

However, I didn't found the right method to calculate the down-scale factor yet, so I did it approximately, by view.

// the bigger, the rounder
var sW = 50;

var canvas = new fabric.Canvas('canvas');
var  path = new fabric.Path('M 170.000 210.000L 217.023 234.721 L 208.042 182.361 L 246.085 145.279 L 193.511 137.639 L 170.000 90.000 L 146.489 137.639 L 93.915 145.279 L 131.958 182.361 L 122.977 234.721 L 170.000 210.000', {   
    stroke: 'black',
    strokeWidth: sW,
    scaleX : 0.7,
    scaleY : 0.7,
    strokeLineJoin : 'round',
    left: 120,
    top: 120}
    );
canvas.add(path);

var pol = new fabric.Polygon([
  {x: 200, y: 0},
  {x: 250, y: 50},
  {x: 250, y: 100},
  {x: 150, y: 100},
  {x: 150, y: 50} ], {
    left: 250,
    top: 160,
    angle: 0,
    fill: 'green',
    stroke: 'green',
    strokeWidth: sW,
    scaleX : 0.7,
    scaleY : 0.7,
    strokeLineJoin : 'round'
  }
);
canvas.add(pol);
<script src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.5.0/fabric.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id='canvas' width="500" height="400" style="border:#000 1px solid;"></canvas>



回答3:

i think that you need something like this

it is transparent because i set fill:'transparent', you can change it to whatever color you like.

my example is not perfect because i tried these properties in order to move the polygone to background but with no success, these are the properties to move back/front the objects:

canvas.sendBackwards(myObject)
canvas.sendToBack(myObject)
canvas.bringForward(myObject)
canvas.bringToFront(myObject)

a little about the code here:

    var roof = null;
var roofPoints = [];
var lines = [];
var dots = [];  
var lineCounter = 0;
var dotsCounter = 0;
var drawingObject = {};
drawingObject.type = "";
drawingObject.background = "";
drawingObject.border = "";

function Point(x, y) {
    this.x = x;
    this.y = y;
}



$("#btnRoof").click(function () {
    if (drawingObject.type == "roof") {
        drawingObject.type = "";
        lines.forEach(function(value, index, ar){
             canvas.remove(value);
        });
        //canvas.remove(lines[lineCounter - 1]);
        roof = makeRoof(roofPoints);
        canvas.add(roof);
        canvas.renderAll();
    } else {
        drawingObject.type = "roof"; // roof type
    }
});


// canvas Drawing
var canvas = new fabric.Canvas('canvas');
var x = 0;
var y = 0;

window.addEventListener('dblclick', function(){ 
     var left = findLeftPaddingForRoof(roofPoints);
     var top = findTopPaddingForRoof(roofPoints);
        drawingObject.type = "";
        lines.forEach(function(value, index, ar){
             canvas.remove(value);
        });
        dots.forEach(function(value, index, ar){
             canvas.remove(value);
        });

        canvas.remove(lines[lineCounter - 1]);
        roof = makeRoof(roofPoints);                               

   dots.push(roof);
   var alltogetherObj = new fabric.Group(dots,{
            left:left,
            top: top,
        originX:'center',
        originY:'center'});
    canvas.add(alltogetherObj);

    canvas.renderAll();

});

canvas.on('mouse:down', function (options) {
    if (drawingObject.type == "roof") {
        canvas.selection = false;
        setStartingPoint(options); // set x,y
        roofPoints.push(new Point(x, y));
        var points = [x, y, x, y];
        lines.push(new fabric.Line(points, {
            strokeWidth: 1,
            selectable: false,
            stroke: 'red'

        }).setOriginX(x).setOriginY(y));

        canvas.add(lines[lineCounter]);
        canvas.sendToBack(lines[lineCounter]);

        lineCounter++;

         //add red dot
       dots.push(new fabric.Circle({
           selectable:false,
            left: x-5,
            top: y-5,
            centerX:'center',
            centerY:'top',
            radius: 10,
            fill: "#dd0000"
        }));

        canvas.add(dots[dotsCounter]);
        //it does not do anything here 
        canvas.bringToFront(dots[dotsCounter]);
        //it does not do anything here  either
        canvas.bringForward(dots[dotsCounter]);
        dotsCounter++;

        canvas.on('mouse:up', function (options) {
            canvas.selection = true;
        });


    }
});
canvas.on('mouse:move', function (options) {
    if (lines[0] !== null && lines[0] !== undefined && drawingObject.type == "roof") {
        setStartingPoint(options);
        lines[lineCounter - 1].set({
            x2: x,
            y2: y
        });
        canvas.renderAll();
    }
});

function setStartingPoint(options) {
    var offset = $('#canvas').offset();
    x = options.e.pageX - offset.left;
    y = options.e.pageY - offset.top;
}

function makeRoof(roofPoints) {
    var left = findLeftPaddingForRoof(roofPoints);
    var top = findTopPaddingForRoof(roofPoints);

    var roof = new fabric.Polyline(roofPoints, {
        fill: 'transparent',
        stroke:'#7F7F7F',
        sendToBack:true
    });
    roof.set({
        left: left,
        top: top
    });


    return roof;
}

function findTopPaddingForRoof(roofPoints) {
    var result = 999999;
    for (var f = 0; f < lineCounter; f++) {
        if (roofPoints[f].y < result) {
            result = roofPoints[f].y;
        }
    }
    return Math.abs(result);
}

function findLeftPaddingForRoof(roofPoints) {
    var result = 999999;
    for (var i = 0; i < lineCounter; i++) {
        if (roofPoints[i].x < result) {
            result = roofPoints[i].x;
        }
    }
    return Math.abs(result);
}

i 've made some fixes to the code, so the shape closes , always, on double click. live example (new): http://jsfiddle.net/tornado1979/avmomzh4/



回答4:

        add = new fabric.Rect({
            width: 200, height: 100, left: 10, top: 10, angle: 0,
            fill: 'rgba(0, 0, 0, 0)',
            stroke: '#000000',
            strokeWidth: lineWidth,
            strokeLineJoin: 'round',
            rx: 10,
            ry: 10
        });