Fabric.js rectangle is not showing up - fabricjs

Why the rectangle is not showing up? I've found the examples at GitHub, official site etc. But they're not working for me.
<script type="text/javascript">
var fCanvas;
window.onload = function (){
var oldCanvas = document.getElementById('canvas');
fCanvas = new fabric.Canvas('canvas',
{
width: oldCanvas.parentNode.clientWidth,
height: oldCanvas.parentNode.clientHeight
});
}
function CreateGraphicObject(id){
//...
var rect = new fabric.Rect({
left: 100,
top: 100,
fill: 'red',
width: 20,
height: 20
});
fCanvas.add(rect);
//fCanvas.renderAll(); - did not help
}
</script>
Thanks.

I had created a fiddle. I hope it will help you.
https://jsfiddle.net/mullainathan/hgnvaqej/

You have created function but never called it, so the rectangle never gets created.
You just need to call the function, in your code I suppose the best place to call it after creating the canvas:
window.onload = function (){
var oldCanvas = document.getElementById('canvas');
fCanvas = new fabric.Canvas('canvas',
{
width: oldCanvas.parentNode.clientWidth,
height: oldCanvas.parentNode.clientHeight
});
CreateGraphicObject(); //I didn't pass any "id" because it makes no sense in the given code
}
function CreateGraphicObject(){
var rect = new fabric.Rect({
left: 100,
top: 100,
fill: 'red',
width: 20,
height: 20
});
fCanvas.add(rect);
fCanvas.renderAll();
}

Related

If a FabricJS object is moved by code, the mouse selection does not appear to work

If I move an object by code, when the mouse is used to select the object, the selection seems to select the object based on its old position. In the example below, the object can be selected by its old position, and not in its current position.
Am I doing something wrong, or is this a bug in FabricJS?
var canvas = window._canvas = new fabric.Canvas('c');
var rect = new fabric.Rect({
left: 50,
top: 50,
width: 50,
height: 50,
fill: 'rgba(255,0,0,0.5)',
});
canvas.add(rect);
var rect_json = rect.toJSON();
rect_json.left += 100;
rect.set(rect_json);
See this fiddle to see it in action.
You need to call setCoords in order to make the control positions recalculate.
Please check this link When to call setCoords.
var canvas = window._canvas = new fabric.Canvas('c');
var rect = new fabric.Rect({
left: 50,
top: 50,
width: 50,
height: 50,
fill: 'rgba(255,0,0,0.5)',
});
canvas.add(rect);
rect.set({ left: 300 }).setCoords()

fabric.js rotate object around canvas center smoothly

I try to rotate an object around the canvas center smoothly using a slider,
I use fabric.util.rotatePoint to find the new center point and set the new angle,but it seems not exactly around the center point and the object position is jumping.
https://jsfiddle.net/j0g1tLsb/26/
here is my code doing this:
const canvas = new fabric.Canvas('c', { width: innerWidth, height: innerHeight });
canvas.controlsAboveOverlay = true;
canvas.preserveObjectStacking = true;
const rect = new fabric.Rect({
width: 300,
height: 150,
left: 400,
top: 400,
fill: "lightgray",
originX: 'center',
originY: 'center'
});
const centerPoint = new fabric.Circle({
originX: 'center',
originY: 'center',
top: innerHeight/2,
left: innerWidth/2,
radius: 10,
fill: 'red',
hasControls: false,
selectable:false
});
const log = new fabric.Text('', {
left: 30,
top: 30,
originX: 'left',
originY: 'top',
fontSize: 18,
evented: false,
selectable: false
});
canvas.add(rect, centerPoint, log);
document.getElementById('img-rotation').oninput = function() {
rect.set('angle', this.value);
var posNewCenter = fabric.util.rotatePoint(
rect.getCenterPoint(),
canvas.getVpCenter(),
fabric.util.degreesToRadians(this.value)
);
rect.set({
left: posNewCenter.x,
top: posNewCenter.y,
angle: this.value
});
log.set('text', `angle: ${Math.round(rect.angle)} \nleft: ${rect.left} \ntop: ${rect.top}`);
canvas.requestRenderAll();
};
rect.on('modified', () => {
log.set('text', `angle: ${Math.round(rect.angle)} \nleft: ${rect.left} \ntop: ${rect.top}`);
canvas.renderAll();
});
Your problem is in getting center point from the rectangle every time. You need just set new Point from the original rectangle position.
var posNewCenter = fabric.util.rotatePoint(
new fabric.Point(400, 400), //here is your mistake
canvas.getVpCenter(),
fabric.util.degreesToRadians(this.value)
);
rect.set({
left: posNewCenter.x,
top: posNewCenter.y,
angle: this.value
});
Working fiddle
UPDATE:
In order of the modification of the Rectangle you need to use object:modified event to reassign top and left coordinates.
First of all declare top and left variables and use them inside rectangle object:
let top = 400;
let left = 400;
const rect = new fabric.Rect({
...
left: left,
top: top,
...
targetObj: 'rectangle' //you can use any value or ID, it's only for targeting purpose
});
Then you need to check when object is modified. If event is fired then check if it is rectangle.
canvas.on('object:modified', (e) => {
if (e.target.hasOwnProperty('targetObj') && e.target.targetObj === 'rectangle') {
left = e.target.get('left');
top = e.target.get('top');
}
})
Finally, use left and top variables inside oninput event of the slider:
var posNewCenter = fabric.util.rotatePoint(
new fabric.Point(left, top),
canvas.getVpCenter(),
fabric.util.degreesToRadians(this.value)
);
Working updated fiddle

How to align object by bounding box in FabricJS?

Wondering if there is a way to align objects in FabricJs by their bounding box?
I'm using obj.getBoundingRect() function to determine objects bounders, then compare them with a bounding box (BB) coordinates of an Active one (that one which I move). If I see that something falls between some gap (let's say 10px) I assign an active object top to be the same top as a comparable element by using a .setTop() property.
The problem is that TOP is not a right attribute to use, since the top of the bounding box may differ between elements. For example, 2 elements with the same top but different angle will have different Bounding Box Top...
Hope you see my point...
https://jsfiddle.net/redlive/hwcu1p4f/
var canvas = this.__canvas = new fabric.Canvas('canvas');
//fabric.Object.prototype.transparentCorners = false;
var red = new fabric.Rect({
id: 1,
left: 100,
top: 50,
width: 100,
height: 100,
fill: 'red',
angle: 0,
padding: 10
});
canvas.add(red);
var green = new fabric.Rect({
id: 2,
left: 250,
top: 180,
width: 100,
height: 100,
fill: 'green',
angle: 45,
padding: 10
});
canvas.add(green);
canvas.renderAll();
canvas.on("object:moving", function(e){
const draggableObj = e.target;
const draggableObjBound = draggableObj.getBoundingRect();
canvas.forEachObject(function(obj) {
if (obj.id !== draggableObj.id) {
var bound = obj.getBoundingRect();
if (draggableObjBound.top > bound.top - 10 && draggableObjBound.top < bound.top + 10) {
draggableObj.setTop(obj.getTop());
}
}
});
});
canvas.forEachObject(function(obj) {
var setCoords = obj.setCoords.bind(obj);
obj.on({
moving: setCoords,
scaling: setCoords,
rotating: setCoords
});
});
canvas.on('after:render', function() {
canvas.contextContainer.strokeStyle = '#555';
canvas.forEachObject(function(obj) {
var bound = obj.getBoundingRect();
canvas.contextContainer.strokeRect(
bound.left,
bound.top,
bound.width,
bound.height
);
})
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.0.0-rc.3/fabric.js"></script>
<canvas id="canvas" width="800" height="500" style="border:1px solid #ccc"></canvas>
You should use the center to align them, that is not gonna change.
to align the bounding box at left 5 for example:
1) calculate bounding box.
2) set the position of the object to 5 + bb.width/2 considering center.
In this case the bounding rects get aligned.
var canvas = this.__canvas = new fabric.Canvas('canvas');
//fabric.Object.prototype.transparentCorners = false;
var red = new fabric.Rect({
id: 1,
left: 100,
top: 50,
width: 100,
height: 100,
fill: 'red',
angle: 0,
padding: 10
});
canvas.add(red);
var green = new fabric.Rect({
id: 2,
left: 250,
top: 180,
width: 100,
height: 100,
fill: 'green',
angle: 45,
padding: 10
});
canvas.add(green);
//ALIGN EVERYTHING TO 5
canvas.forEachObject(function(object) {
var bb = object.getBoundingRect();
object.setPositionByOrigin({ x: 5 + bb.width/2, y: bb.top }, 'center', 'center');
object.setCoords();
});
canvas.renderAll();
canvas.on("object:moving", function(e){
const draggableObj = e.target;
const draggableObjBound = draggableObj.getBoundingRect(true, true);
canvas.forEachObject(function(obj) {
if (obj.id !== draggableObj.id) {
var bound = obj.getBoundingRect(true, true);
if (draggableObjBound.top > bound.top - 10 && draggableObjBound.top < bound.top + 10) {
draggableObj.setPositionByOrigin({ x: draggableObj.left, y: bound.top + draggableObjBound.height/2 }, draggableObj.originX, 'center');
}
}
});
});
canvas.forEachObject(function(obj) {
var setCoords = obj.setCoords.bind(obj);
obj.on({
moving: setCoords,
scaling: setCoords,
rotating: setCoords
});
});
canvas.on('after:render', function() {
canvas.contextContainer.strokeStyle = '#555';
canvas.forEachObject(function(obj) {
var bound = obj.getBoundingRect(true, true);
canvas.contextContainer.strokeRect(
bound.left,
bound.top,
bound.width,
bound.height
);
})
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.0.0-rc.3/fabric.js"></script>
<canvas id="canvas" width="800" height="500" style="border:1px solid #ccc"></canvas>

FabricJS. How to add dimensions displaying in controls?

How to add dimensions displaying in controls like on screenshot?
Create a text object and set it hidden. And when you are scalling object set the scale width and height to hidden text and make visible. On object modified set visible false to the text.
DEMO
var canvas = new fabric.Canvas("c");
canvas.setHeight(200);
canvas.setWidth(300);
var dimText = new fabric.Text("demo", {
fontSize: 15,
visible: false
});
canvas.add(dimText);
var circle = new fabric.Circle({
left: 15,
top: 15,
radius: 20,
fill:'',
stroke: 'red'
});
canvas.add(circle);
var text = new fabric.Text("2018", {
padding: 30,
lineHeight: 30
});
canvas.add(text);
canvas.centerObject(text);
text.setCoords();
canvas.on('object:scaling', function(option) {
var object = option.target;
var pointer = canvas.getPointer(option.e);
dimText.set({
left: pointer.x - 20,
top: pointer.y - 20,
text: parseInt(object.width * object.scaleX) + 'x' + parseInt(object.height * object.scaleY),
visible: true
})
});
canvas.on('object:modified', function(option) {
dimText.set('visible', false);
});
canvas {
border: 1px solid #dddddd;
margin-top: 10px;
border-radius: 3px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.7/fabric.min.js"></script>
<canvas id="c"></canvas>

fabric js object manage with another object

My canvas has two objects. The first one is selectable true and the second one is selectable false. I am looking to manage the second object through the first object's action.
If the first object moves, then the second objects need to move in the same direction. If the first one rotates, then the second one rotates at the same angle in the second one's position.
I have tried adding events (moving,rotating) to the first selectable object, and then getting the required values from the first object and setting it to second object, but rotating is not working properly. My code is as follows:
imageOne.on('rotating', function (evt) { imageThree.angle = imageOne.getAngle(); });
var canvas = new fabric.Canvas('c');
var evented = false;
var rect1 = new fabric.Rect({
left: 50,
top: 60,
fill: 'blue',
width: 150,
height: 150,
});
var rect2 = new fabric.Rect({
left: 210,
top: 60,
fill: 'magenta',
width: 150,
height: 150,
selectable: false
});
canvas.add(rect1,rect2);
function rect1MouseDown(option){
this.mousesDownLeft = this.left;
this.mousesDownTop = this.top;
this.rect2Left = rect2.left;
this.rect2Top = rect2.top;
}
function rect1Move(option){
rect2.left = this.rect2Left+ this.left - this.mousesDownLeft ;
rect2.top = this.rect2Top+ this.top- this.mousesDownTop;
rect2.setCoords();
}
function rect1Rotating(options){
rect2.setAngle(this.angle);
}
register();
function register(){
if(evented) return;
rect1.on('moving', rect1Move);
rect1.on('mousedown', rect1MouseDown);
rect1.on('rotating', rect1Rotating);
evented = true;
}
function unRegister(){
rect1.off('moving');
rect1.off('mousedown');
rect2.on('rotating');
evented = false;
}
canvas {
border: blue dotted 2px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.19/fabric.min.js"></script>
<button onclick='register()'>Register Event</button>
<button onclick='unRegister()'>Unregister Event</button><br>
<canvas id="c" width="400" height="400"></canvas>
You can use obj.setAngle() for version <1.7.19 and obj.rotate() for version 2 , to set angle to an object.

Resources