Rafik Avtoyan
Rafik Avtoyan

Reputation: 433

How to set a stroke on only certain side?

Is there a way to give stroke on only one side of the canvas object? For example I want to give stroke only for top.

When I apply "strokeWidth:1", it's applied on all sides. I haven't found any property or method to resolve my problem.

Upvotes: 5

Views: 2978

Answers (3)

Jai Prakash
Jai Prakash

Reputation: 11

Encountered same issue. Had to override the _render() method and draw lines individually rather than all at once.

let canvas = new fabric.Canvas("my-canvas");
canvas.setBackgroundColor("#ccc");

fabric.RectWithBorders = fabric.util.createClass(fabric.Rect, {
  type: "rectWithBorders",
  borderTop: true,
  borderBottom: true,
  borderLeft: true,
  borderRight: false,

  initialize: function (options, borderOptions) {
    this.callSuper("initialize", options);
    this.borderTop = borderOptions.borderTop;
    this.borderBottom = borderOptions.borderBottom;
    this.borderLeft = borderOptions.borderLeft;
    this.borderRight = borderOptions.borderRight;
 },
 _render: function (ctx) {
    const originalStroke = this.stroke;
    var rx = this.rx ? Math.min(this.rx, this.width / 2) : 0,
    ry = this.ry ? Math.min(this.ry, this.height / 2) : 0,
    w = this.width,
    h = this.height,
    x = -this.width / 2,
    y = -this.height / 2,
    isRounded = rx !== 0 || ry !== 0,
    k = 1 - 0.5522847498;

// Border Top
ctx.beginPath();
this.stroke = this.borderTop ? originalStroke : null;
ctx.moveTo(x + rx, y);
ctx.lineTo(x + w - rx, y);
isRounded &&
  this.borderRight &&
  ctx.bezierCurveTo(x + w - k * rx, y, x + w, y + k * ry, x + w, y + ry);
ctx.moveTo(x + w, y + h - ry);
ctx.closePath();
this._renderPaintInOrder(ctx);

// Border Right
ctx.beginPath();
this.stroke = this.borderRight ? originalStroke : null;
ctx.moveTo(x + w, y + ry);
ctx.lineTo(x + w, y + h - ry);
isRounded &&
  this.borderBottom &&
  ctx.bezierCurveTo(
    x + w,
    y + h - k * ry,
    x + w - k * rx,
    y + h,
    x + w - rx,
    y + h
  );
ctx.moveTo(x + rx, y + h);
ctx.closePath();
this._renderPaintInOrder(ctx);

// Border Bottom
ctx.beginPath();
this.stroke = this.borderBottom ? originalStroke : null;
ctx.moveTo(x + w - rx, y + h);
ctx.lineTo(x + rx, y + h);
isRounded &&
  this.borderLeft &&
  ctx.bezierCurveTo(x + k * rx, y + h, x, y + h - k * ry, x, y + h - ry);
ctx.moveTo(x, y + ry);
ctx.closePath();
this._renderPaintInOrder(ctx);

// Border Left
ctx.beginPath();
this.stroke = this.borderLeft ? originalStroke : null;
ctx.moveTo(x, y + h - ry);
ctx.lineTo(x, y + ry);
isRounded &&
  this.borderTop &&
  ctx.bezierCurveTo(x, y + k * ry, x + k * rx, y, x + rx, y);
ctx.moveTo(x + w - rx, y);
ctx.closePath();

this._renderPaintInOrder(ctx);
}
});

canvas.add(
  new fabric.RectWithBorders({
   width: 150,
   height: 150,
   left: 25,
   top: 25,
   fill: "transparent",
   strokeWidth: 1,
   stroke: "#333"
   }, 
   {borderTop: false, borderBottom: true,
    borderLeft: true, borderRight: true})
 );

Not sure of the performance hit that it takes. Haven't tested fully because later this wasn't needed.

Upvotes: 1

Miron
Miron

Reputation: 1067

I found a solution using strokeDashArray.

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

var border = new fabric.Rect({ 
    width: 200, 
    height: 100, 
    left: 50, 
    top: 40,
    fill: "#FFFFFF",
    strokeWidth: 1,
    stroke: '#333',
    strokeDashArray: [200, 100] // same as [width, height]

});

canvas.add(border);
canvas.renderAll();

jsFiddle answer is here.

You may find solution for any kind of custom borders based on this answer.

Upvotes: 1

ptCoder
ptCoder

Reputation: 2247

There's no method to it, for defined sides. You can add a rectangle behind the image and make it look like a border. For example "top border" width 10px:

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

fabric.Image.fromURL('http://cdn.younghollywood.com/images/stories/newsIMG/wenn/20140901/wenn21338105_46_4145_8.jpg', function(oImg) {
    oImg.scale(1.0).set({
        left: 50,
        top: 50,
        width: 200,
        height: 200
    });

    canvas.add(oImg);
    canvas.renderAll();
});

var border = new fabric.Rect({ 
    width: 200, 
    height: 200+10, 
    left: 50, 
    top: 40,
    fill: "#FFFFFF"
});

canvas.add(border);
canvas.renderAll();

Fiddle: http://jsfiddle.net/q6Y6k/11/

Otherwise, please check this: How to set a stroke-width:1 on only certain sides of SVG shapes?

Upvotes: 2

Related Questions