Image clipping with visible overflow in Fabricjs - fabricjs

I want to clip image, BUT default clipping behaviour just hiding a part of image which out of border. Is there a way to make it visible and set less opacity for overflowed content?
There's one of old clipping examples I told about. It also using lodash to bind clip name to object:
return _.bind(clipByName, pug)(ctx)
Is there a way to replace this functionality with vanilla es5?

I found unclear solution. Again.
Background color of canvas could make an opacity and background image could be clipping object (w/o clipping by itself).
Also, loaded image shoul define globalCompositeOperation set to source-atop.
var canvas = new fabric.Canvas('c');
var clipingRect = new fabric.Rect({
originX: 'left',
originY: 'top',
top: 50,
left: 50,
height: 300,
width: 300,
fill: 'white',
selectable: false
});
canvas.backgroundColor = 'rgba(255,255,0,0.5)';
canvas.setBackgroundImage(clipingRect);
fabric.Image.fromURL('http://placeimg.com/640/480/any', function(fimg) {
canvas.add(fimg.set({
left: 0,
top: 0,
width: canvas.getWidth(),
height: canvas.getHeight(),
globalCompositeOperation: 'source-atop'
}));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.12/fabric.min.js"></script>
<canvas id="c" width="400" height="400"></canvas>

Related

Fabric.js: dashed line with clipping looks different on large canvas size

I use a clipping area with fabric.js to create a graph. However, the grid lines look different on a canvas size bigger than about 1000px. It only occurs with imageSmoothingEnabled: false. See the image. Note: the size of the frames have nothing to do with the size of the canvas.
To create the grid lines, I create one original that is wider than the area, and then clone them. The cloned lines are added to the clipArea object. Here is the relevant code.
HTML:
<canvas id="canvas" width="966" height="520"></canvas>
Javascript:
var canvas = new fabric.StaticCanvas('canvas', {
imageSmoothingEnabled: false
});
var rect = new fabric.Rect({
originX: 'left',
originY: 'top',
fill: 'transparent',
width: x1-x0,
height: y1-y0
});
var clipArea = new fabric.Group([rect], {
originX: 'left',
originY: 'top',
width: canvas.width*2,
height: canvas.height*2,
left: -canvas.width,
top: -canvas.height
});
rect=clipArea.item(0)
rect.set({left: x0,top: y0});
clipArea.clipPath = rect;
canvas.add(clipArea);
var yline = new fabric.Line([0, 0, 1200, 0], {
originX: 'left',
originY: 'center',
stroke: myFrameColor,
strokeWidth: 2,
strokeDashArray: [1, 3.4]
});
// clipArea.add(yline)
Of course I could draw the gridlines in a different way without using clipping, but I need a clipping area anyway. And I'd like to understand why this is happening.

How to force proportional scaling using Fabricjs?

There has been multiple changes in the Fabricjs API that affect the way scaling points behave. One of the latest changes in version 4 (http://fabricjs.com/v4-breaking-changes) states that uniformScaling is now the way to go to force proportional scaling.
This is my test canvas:
<canvas id="c" width="400" height="400" style="border:1px solid #ccc"></canvas>
And this is my simple code snippet:
const canvas = (this.__canvas = new fabric.Canvas("c"));
canvas.uniformScaling = true;
const Add = () => {
const rect = new fabric.Rect({
left: 100,
top: 100,
fill: "yellow",
width: 200,
height: 100,
stroke: "lightgreen",
});
canvas.add(rect);
canvas.setActiveObject(rect);
};
Add();
See a codepen illustrating the issue.
Why are the control points for resizing horizontally and vertically still there? What am I doing wrong?
The uniformScaling property only determines the behavior of the corner resize controls. You can hide the side controls using the setControlsVisibility method.
http://fabricjs.com/docs/fabric.Object.html#setControlsVisibility
fabric.Rect.prototype.setControlsVisibility({
ml: false,
mt: false,
mr: false,
mb: false
});

Create a clipping mask using an object in Fabric.js

I'm trying to create a T-Shirt editor using Fabric. I set a shirt as a background image on the canvas. Now I'm trying to get an area in the middle of the T-shirt that will act as a clipping mask. I only want objects that are inside this area to be visible.
Here's my code: http://jsfiddle.net/mtb2p3Lx/4/
var canvas = new fabric.Canvas('c');
// set background
fabric.Image.fromURL('https://qstomizr.s3.amazonaws.com/11102-9LDAQLKA1585254870.5083.jpg', (img) => {
canvas.setBackgroundImage(img, null, {
originX: 'center',
originY: 'center',
top: canvas.getCenter().top,
left: canvas.getCenter().left,
stroke: 'black',
strokeWidth: 1,
});
canvas.renderAll();
});
// set masking area
var area = new fabric.Rect({
originX: 'center',
originY: 'center',
top: this.canvas.getCenter().top,
left: this.canvas.getCenter().left + 10,
width: 250,
height: 300,
selectable: false,
fill: 'transparent',
stroke: 'black',
strokeWidth: 2,
});
canvas.add(area)
// set example rect
var rect = new fabric.Rect({
originX: 'center',
originY: 'center',
top: this.canvas.getCenter().top + 50,
left: this.canvas.getCenter().left + 150,
height: 100,
width: 100,
fill: 'pink',
});
canvas.add(rect)
I tried adding a clip path to the area rect, also tried playing around with globalCompositeOperation, but I couldn't get anything to work without having to sacrifice the background image.
Is there a way to get the transparent area rect to act as a clipping mask for the other objects in the canvas?
As you can see on this site https://printio.ru/tees/new_v2. For implementing background image was used img tag without setBackgroundImage. And I make an example for you here
https://jsfiddle.net/RamanNikitsenka/4suna7yo/1/

how to make a hole through only overlay Rectangle using fabric js?

I am working on image cropper using fabric js version 1.7.22.
As usually, every cropper display black transparent overlay over the image (where image look like dull), and also display one Rect. (crop Area where image look full with color).
we can create this functionality using fabric js with background image and fabric.Rect object.
My problem is that when I use GlobalCompositeOperation with destination-out property to fabric.Rect object. It will make hole through canvas.
In simple word :
when I add globalCompositeOperation to destination-out, it will make hole through canvas also.
Expected result of canvas:
Current Result of canvas:
I have made one codepen for demonstration :
https://codepen.io/mayurkukadiya0/pen/zYYWOGL?editors=0110
I have found one codepen also for do same but they are add multiple canvas for display image in separate layer and rect and overlay in separate layer
Is there any way to do this without add external any canvas or css image behind canvas ?
Here is that reference : https://codepen.io/s0nnyv123/pen/eravaN
try using setOverlayImage
here'a demonstration, based on your codepen
var canvas = new fabric.Canvas('canvas', {preserveObjectStacking: 'true'});
canvas.setHeight(300);
canvas.setWidth(300);
canvas.setOverlayImage('https://images.pexels.com/videos/856973/free-video-856973.jpg?auto=compress&cs=tinysrgb&dpr=1&w=500', canvas.renderAll.bind(canvas), {
top: 0,
left: 0,
width: 300,
height:300,
lockMovementX: true,
lockMovementY: true,
lockRotation: true,
selectable: false,
globalCompositeOperation: 'destination-atop',
});
var overlay = new fabric.Rect({
left: 0,
top: 0,
width: 300,
height: 300,
fill: '#00000050',
selectable: false,
globalCompositeOperation: 'source-over'
});
canvas.add(overlay);
var rect = new fabric.Rect({
left: 100,
top: 100,
width: 100,
height: 100,
fill: '#451245',
globalCompositeOperation: 'destination-out'
});
canvas.add(rect);
canvas.renderAll();

Fabricjs How to scale object but keep the border (stroke) width fixed

I'm developing a diagram tool based on fabricjs. Our tool has our own collection of shape, which is svg based. My problem is when I scale the object, the border (stroke) scale as well. My question is: How can I scale the object but keep the stroke width fixed. Please check the attachments.
Thank you very much!
Here is an easy example where on scale of an object we keep a reference to the original stroke and calculate a new stroke based on the scale.
var canvas = new fabric.Canvas('c', { selection: false, preserveObjectStacking:true });
window.canvas = canvas;
canvas.add(new fabric.Rect({
left: 100,
top: 100,
width: 50,
height: 50,
fill: '#faa',
originX: 'left',
originY: 'top',
stroke: "#000",
strokeWidth: 1,
centeredRotation: true
}));
canvas.on('object:scaling', (e) => {
var o = e.target;
if (!o.strokeWidthUnscaled && o.strokeWidth) {
o.strokeWidthUnscaled = o.strokeWidth;
}
if (o.strokeWidthUnscaled) {
o.strokeWidth = o.strokeWidthUnscaled / o.scaleX;
}
})
canvas {
border: 1px solid #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.4/fabric.min.js"></script>
<canvas id="c" width="600" height="600"></canvas>
There is a property called: strokeUniform
Use it like this
shape.set({stroke: '#f55b76', strokeWidth:2, strokeUniform: true })
I have found what feels like an even better solution, works really well with SVG paths.
You can override fabricjs' _renderStroke method and add ctx.scale(1 / this.scaleX, 1 / this.scaleY); before ctx.stroke(); as shown below.
fabric.Object.prototype._renderStroke = function(ctx) {
if (!this.stroke || this.strokeWidth === 0) {
return;
}
if (this.shadow && !this.shadow.affectStroke) {
this._removeShadow(ctx);
}
ctx.save();
ctx.scale(1 / this.scaleX, 1 / this.scaleY);
this._setLineDash(ctx, this.strokeDashArray, this._renderDashedStroke);
this._applyPatternGradientTransform(ctx, this.stroke);
ctx.stroke();
ctx.restore();
};
You may also need to override fabric.Object.prototype._getTransformedDimensions to adjust the bounding box to account for the difference in size.
Also a more complete implementation would probably add a fabric object property to conditionally control this change for both overridden methods.
Another way is to draw a new object on scaled and remove the scaled one.
object.on({
scaled: function()
{
// store new widht and height
var new_width = this.getScaledWidth();
var new_height = this.getScaledHeight();
// remove object from canvas
canvas.remove(this);
// add new object with same size and original options like strokeWidth
canvas.add(new ...);
}
});
Works perfect for me.

Resources