Canvas client size in fabric js - fabricjs

In a usual canvas css width and client width could be not equal to each other, how to get this on Fabricjs? As an example: I want 640*360px canvas on a page with 1280*720px image inside.
I know I could scale image, but dataUrl will give me a smaller picture, isn't it?

There is a solution. You could init Fabric.js with CSS sizes and then setDimensions with backstoreOnly flag or init with desired client size and use setDimensions with cssOnly flag.
Example #1:
var canvas = new fabric.Canvas('c', {width: 640, height: 360});
canvas.setDimensions({width: 1280, height: 720}, {backstoreOnly: true});
Example #2:
var canvas = new fabric.Canvas('c', {width: 1280, height: 720});
canvas.setDimensions({width: '640px', height: '360px'}, {cssOnly: true});

You can change the size of the canvas using the setWidth/setHeight properties of the canvas http://fabricjs.com/docs/fabric.StaticCanvas.html#setWidth
e.g.
canvas = new fabric.Canvas('c');
canvas.setWidth(640);
canvas.setHeight(360);
Though you should clarify what you mean.

Related

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();

how to stretch image size to match fabric.Image object

I am using fabricjs to implement image editing and I try to use a fabric.Image object as the background image of canvas to store the data. And the following is the code:
var canvas = new fabric.Canvas('canvasId');
var imageObject = new fabric.Image($originImage);
canvas.add(imageObject);
but I found the $originImage's size is much larger than canvas' size and also imageObject's size, so the canvas can only show part of the image. I want to know how to stretch the $originImage to adapt the canvas then canvas can display all of the $originImage?
Here what I have done
$canvas.width = $originImage.clientWidth;
$canvas.height = $originImage.clientHeight;
var fabricCanvas = new fabric.Canvas('canvasId');
// canvas.setFabricCanvas(fabricCanvas);
var imageObject = new fabric.Image($originImage);
// fabricCanvas.add(imageObject);
// fabricCanvas.isDrawingMode = true;
fabricCanvas.setBackgroundImage(imageObject, fabricCanvas.renderAll.bind(fabricCanvas), {
scaleX: fabricCanvas.width / $originImage.naturalWidth,
scaleY: fabricCanvas.height / $originImage.naturalHeight
});
the upper is my related code and below is the display:
it is solved, and the previous question is because I resize the $originImage first, so when I input the image src as setBackgroundImage's parameter, it can display normally.
For version 2.0 of fabricjs, they have changed the way to handle width/height compared to previous version. If you apply width/height, then it basically crop the image to that particular size compared to the original image size. In order to resize it to a proper size, you have to switch to use scaleX/scaleY like other people have suggested.
For example, I use image.fromUrl to load an image and set it to be the background:
fabric.Image.fromURL(imgUrl, function(img) {
img.set({
scaleX: currentWidth / img.width,
scaleY: currentHeight / img.height,
top: topPosition,
left: leftPosition
originX: 'left', originY: 'top'
});
canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas));
});
where currentWidth/currentHeight can be your canvas size if you want full background or they can be a specific width/height that you want (in my project, I want to do letter-boxed image instead so I set the width and height based on my letter-boxing algorithm), and top/left is the location that you want to place your image in the canvas (leave it none if you want to be full background image). Do not set any width and height since that will crop the scaled image rather than setting the image to be the exact size.
If this does not work, check the backgroundImage object from the canvas and see if its dimension and scale properties are different compared to a manual calculation. If you take a look, you will see the width and height properties are your natural image width and height, but it will have scaleX and scaleY less than 1 if your canvas size is less than the image size or more than 1 if it is bigger.
Also I see you are loading image directly into an image object. That might be different compared to load the data and set it directly using setBackgroundImage.
canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas), {
scaleX: canvas.width / $originalImg.naturalWidth,
scaleY: canvas.width / $originalImg.naturalHeight
});
use scaleX,scaleY to resize.
(function() {
var $originalImg = $('#originalImage')[0];
console.dir($originalImg)
var canvas = this.__canvas = new fabric.Canvas('c');
var img = new fabric.Image($originalImg);
canvas.setBackgroundImage(img,canvas.renderAll.bind(canvas),{
scaleX:canvas.width/$originalImg.naturalWidth,
scaleY:canvas.width/$originalImg.naturalHeight
});
})();
canvas{
border-width: 1pz;
border-style: solid;
border-color: #000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.0.0-rc.3/fabric.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<img id='originalImage'src='http://fabricjs.com/assets/pug_small.jpg'>
<canvas id='c' width=200 height=200></canvas>
I am using the following script to ensure the image is no larger than the canvas width:
var aspect = image.width / image.height; //Aspect ratio of image
new fabric.Image(image, {
scaleX: canvas.width / image.width,
scaleY: canvas.width / (image.height * aspect)
});

Image clipping with visible overflow in 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>

Adding text over images in fabricjs

developing this app in which there several images on a canvas and i am using using fabricjs.
i want to add text overlaid on an image and then be able to remove it as well.
is a way to directly write over the image or do i have to create another layer and write onto it.
there is text related like
var text = new fabric.Text('hello world', { left: 100, top: 100 });
canvas.add(text);
the problem with the above approach is that if the image moves the text will not, so is it possible that the text could be written directly above the image?
any ideas of how this could be done? i revived several discussions where it's not as clear, how it could be done.
any pointers would be most appreciated.
This could be achieved by creating an image and a text object, then adding both the objects to a group and finally adding that group to the canvas.
Here's an example, showing that in action ...
var canvas = new fabric.Canvas('canvas');
// load image
fabric.Image.fromURL('https://i.imgur.com/Q6aZlme.jpg', function (img) {
img.scaleToWidth(100);
img.scaleToHeight(100);
// create text
var text = new fabric.Text('hello world', {
left: 10,
top: 5,
fontSize: 15,
fontFamily: 'Verdana',
fill: 'white'
});
// add image and text to a group
var group = new fabric.Group([img, text], {
left: 50,
top: 50,
});
// add the group to canvas
canvas.add(group);
});
canvas{border:1px solid #ccc}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.11/fabric.min.js"></script>
<canvas id="canvas" width="200" height="200"></canvas>
I am not quite clear of what exactly is your requirement.
Regardless of it, i have created a JS Fiddle for you.
https://jsfiddle.net/xpntggdo/9/
textBox=new fabric.Textbox("Enter Text",{
fontSize: 16,
fontFamily: 'Arial',
textAlign: 'left',
width: 180, // for 20 characters
top:arrowTop,
left:arrowLeft
});
canvas.add(textBox);
canvas.renderAll();
This might be of a little help at least. Comment on this answer and I will try to help you more on it if that is possible for me.

Draw text on canvas using fabric.js

I want to draw text on canvas., how to do it any sample example?
The canvas already contains some shape drawn, i want to show text on the top of that shape on canvas
How can i do it?
Also be aware that you need to actually have loaded a cufon font. There is no default font when using Fabric.js.
<script src="fabric.js"></script>
<script src="cufon.calibri.js"></script>
There are so many fonts available from http://www.cufonfonts.com/
This being the case the author is planning on removing the need for cufon. Discussed here: Fabric.js + Google Fonts
If you're wanting to render a block, then some text inside of that block. I would do something like this.
//Render the block
var block = canvas.add(new fabric.Rect({
left: 100,
top: 100,
fill: 'blue'
}));
//Render the text after the block (so that it is in front of the block)
var text = canvas.add(new fabric.Text('I love fabricjs', {
left: block.left, //Take the block's position
top: block.top,
fill: 'white'
}));
//Render the text and block on the canvas
//This is to get the width and height of the text element
canvas.renderAll();
//Set the block to be the same width and height as the text with a bit of padding
block.set({ width: text.width + 15, height: text.height + 10 });
//Update the canvas to see the text and block positioned together,
//with the text neatly fitting inside the block
canvas.renderAll();
Take a look at How to render text tutorial.
It's as simple as:
canvas.add(new fabric.Text('foo', {
fontFamily: 'Delicious_500',
left: 100,
top: 100
}));
Also worth noting that you might need to adjust Cufon's offsetLeft to help correctly position the text. Something like:
Cufon.fonts[your-fontname-in-lowercase-here].offsetLeft = 120;
The kitchen sink demo of fabric uses this:
http://kangax.github.com/fabric.js/lib/font_definitions.js

Resources