Reputation: 433
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
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
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
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