Text always displays under image in Fabric.js - fabricjs

I have the following problem. I have been using Fabric.js for a project and find it easy to use. However I have the following problem that i just don't seem able to solve. I am probably missing the obvious but its time to ask for help.
I can't get a text layar to display ontop of a loaded image. here is the code :
<canvas id="c" height=600 width=800></canvas>
var canvas = new fabric.StaticCanvas('c');
fabric.Image.fromURL('http://mozorg.cdn.mozilla.net/media/img/products/badge- firefoxos.jpg?2013-06', function(img) {
var imgX = img.set({
top: 0,
left: 0,
});
canvas.add(imgX);
});
var text = new fabric.Text("This text always gets burried", {
top : 0,
left : 0,
fontSize : 50,
fontFamily : 'Delicious_500'
});
canvas.add(text);
canvas.BringToFront(text);
canvas.renderAll();
I also created a fiddle : http://jsfiddle.net/NkqWL/9/
Any advice is greatly appreciated.

I have updated your fiddle
Fiddle Link:- Click Here
Send your image to back using canvas.sendToBack(imgX);
fabric.Image.fromURL('http://mozorg.cdn.mozilla.net/media/img/products/badge-firefoxos.jpg?2013-06', function(img) {
var imgX = img.set({
top: 0,
left: 0,
});
canvas.add(imgX);
canvas.sendToBack(imgX);
});

Related

fabricjs limiting object drag

Referring to the code below, I can drag the red line back and forth within the canvas box and have it stop at the left limit. But the line doesn't stop at the right limit - it disappears beyond the box and reappears if I drag left. I have looked at fabricjs demos (Standalone Controls, PerPixel Drag and Drop, Stickman) and notice that it is possible to drag objects "out of sight" in a similar manner. Is this a characteristic of fabricjs, or is there some way I can fix my code so that the red line cannot be dragged beyond the right limit?
var canvas = new fabric.Canvas('cnvs');
var leftLimit = 20;
var rightLimit = 400;
var redLine = new fabric.Line([leftLimit, 0, leftLimit, canvas.height], {
stroke: 'red',
strokeWidth: 2,
borderColor: 'white',
hasControls: false
});
canvas.add(redLine);
canvas.renderAll();
canvas.on('object:moving', function(e) {
redLine = e.target;
redLine.set({
top: 0
});
if (redLine.left < leftLimit) {
redLine.set({
left: leftLimit
});
}
if (redLine > rightLimit) {
redLine.set({
left: rightLimit
});
}
canvas.renderAll();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.3/fabric.js"></script>
<canvas id="cnvs" width="500" height="200" style="border:1px solid #000000"></canvas>
I'm not sure if you made a typo or not, but (redLine > rightLimit) makes no sense. You should compare left:
if (redLine.left > rightLimit) {
redLine.set({ left: rightLimit });
}
Or, since your line has some width to it, you can make it stop without ever overlapping the boundary:
if (redLine.left + redLine.strokeWidth > rightLimit) {
redLine.set({ left: rightLimit - redLine.strokeWidth });
}

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.

FabricJS double click new techniques?

could someone please point me in the direction for how to enable double click on fabric images? i came across this solution
FabricJS double click on objects
I am trying to not use FabicjsEx
but i am unable to get anything to work correctly. can someone please let me know the best way to accomplish this?
The best way to accomplish this, is to use fabric.util.addListener method.
Using that you could add a double click event for the canvas element and to restrict it to any particular object ( ie. image ), you would have to check whether you clicked on an image object or not before performing any action.
ᴅᴇᴍᴏ
var canvas = new fabric.Canvas('canvas');
// add image
fabric.Image.fromURL('https://i.imgur.com/Q6aZlme.jpg', function(img) {
img.set({
top: 50,
left: 50
})
img.scaleToWidth(100);
img.scaleToHeight(100);
canvas.add(img);
});
// add rect (for demo)
var rect = new fabric.Rect({
left: 170,
top: 50,
width: 100,
height: 100,
fill: '#07C'
});
canvas.add(rect);
// mouse event
fabric.util.addListener(canvas.upperCanvasEl, 'dblclick', function(e) {
if (canvas.findTarget(e)) {
const objType = canvas.findTarget(e).type;
if (objType === 'image') {
alert('double clicked on a image!');
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.9/fabric.js"></script>
<canvas id="canvas" width="320" height="200"></canvas>

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.

how to set height and width of image in fabric.js?

I had loaded image in canvas using fabric.Image.fromURL and working fine with default image width and height.
Now I want to minimize width and height of an image.
How to do this?
Thanks in advance.
Hope this will help
var src; //Image source here
fabric.Image.fromURL(src, function(oImg) {
oImg.scaleToWidth(50);
oImg.scaleToHeight(50);
});
We can use scalex / scaley to set height / width as below.
fabric.util.loadImage(imgsrc, function (img) {
var legimg = new fabric.Image(img, {
left: 30,
top: marker.top,
scaleX: 20 / img.width,
scaleY: 20 / img.height
});
canvas.add(legimg);
canvas.renderAll();
});
Thanks
var canvas = new fabric.Canvas('canvas');
document.getElementById('file').addEventListener("change", function (e) {
var file = e.target.files[0];
var reader = new FileReader();
reader.onload = function (f) {
var data = f.target.result;
fabric.Image.fromURL(data, function (img) {
var oImg = img.set({left: 0, top: 0, angle: 00,width:100, height:100}).scale(0.9);
canvas.add(oImg).renderAll();
var a = canvas.setActiveObject(oImg);
var dataURL = canvas.toDataURL({format: 'png', quality: 0.8});
});
};
reader.readAsDataURL(file);
});
canvas{
border: 1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.min.js"></script>
<input type="file" id="file"><br />
<canvas id="canvas" width="450" height="450"></canvas>
We can set width and height.
Check this JSfiddle: https://jsfiddle.net/varunPes/8gt6d7op/5/
This working code I have tested:
fabric.Image.fromURL(el.src, function(image) {
image.set({
left: left,
top: top,
angle: 0,
padding: 10,
cornersize: 10,
hasRotatingPoint:true
});
image.scaleToHeight(100);
image.scaleToWidth(200);
canvas.add(image);
});
Work with the image scale properties and not the image size. This worked for me. When I had set the image width and height, and not the scale, when I applied a filter it reset back to original width and height because the scale was 1.0. Hope this helps.
Well I am not sure how are you trying to do it but you could while
adding the image use canvas object in the editor and pass it the Image
in a function called centerObject. Here is the code that worked for
me.
My ReactJS code centers a shirt image in the canvas as given below
const { editor, onReady } = useFabricJSEditor()
const add_image = () => {
fabric.Image.fromURL('assets/custom/shirt_green.png',(oImg) => {
oImg.scaleToHeight(240)
oImg.scaleToWidth(240)
editor.canvas.add(oImg)
editor.canvas.centerObject(oImg)
})
}
Over to the frontend UI we render using
<div>
<FabricJSCanvas className={styles.canvas} onReady={onReady} />
</div>

Resources