How to fetch all properties of an object in fabricjs? - fabricjs

I want to know How to fetch all properties of an object in fabricjs?.
I have to apply those properties to another object (I don't want to clone).
Please help me.

I have found answer for my own question.
<canvas id="canvas" width="300" height="300"></canvas> <br/>
<button id="replace"> Replace </button>
<span id="message"></span>
var canvas = ctx = activeObject = text1 = text2 = '';
var textProperties = ['angle', 'backgroundColor', 'clipTo', 'fill', 'fillRule', 'flipX', 'flipY', 'fontFamily', 'fontSize', 'fontStyle', 'fontWeight', 'globalCompositeOperation', 'height', 'id', 'left', 'letterSpace', 'lineHeight', 'opacity', 'originX', 'originY', 'path', 'scaleX', 'scaleY', 'shadow', 'stroke', 'strokeDashArray', 'strokeLineCap', 'strokeLineJoin', 'strokeMiterLimit', 'strokeWidth', 'text', 'textAlign', 'textBackgroundColor', 'textDecoration', 'top', 'transformMatrix', 'useNative', 'visible', 'width'];
console.clear();
canvas = new fabric.Canvas('canvas');
ctx = canvas.getContext('2d');
text1 = new fabric.Text('Text1', {
fill: 'red',
left: 50,
top: 50
});
text2 = new fabric.Text('Text2', {
fill: 'green',
left: 150,
top: 50
});
canvas.add(text1, text2).renderAll().setActiveObject(text1);
activeObject = canvas.getActiveObject();
$(document).on('click', '#replace', function(e) {
e.preventDefault();
for(var i=0; i<textProperties.length; i++) {
var property = textProperties[i];
text2.set(property, activeObject.get(property));
}
$("#message").css({ 'display':'block' }).html('Success..!');
canvas.renderAll().setActiveObject(text2);
});
https://jsfiddle.net/mullainathan/coLcz0zx/

Related

how to remove grid lines with a button click in fabric.js canvas

I have to two buttons, one to add grids and another to remove grids.
When I am clicking add button, I am writing following lines of code:
var gridsize = 5;
var gridoption={ stroke: "#000000", strokeWidth: 1, selectable:false, strokeDashArray: [5, 5],evented:false};
for(var x=1;x<(canvas.width/gridsize);x++)
{
canvas.add(new fabric.Line([100*x, 0, 100*x, 600],gridoption));
canvas.add(new fabric.Line([0, 100*x, 600, 100*x],gridoption));
}
With these codes, the grids appear with a click of button,but I also want to remove the grids once another button is clicked without making any change to the other objects in the canvas. Since I am not selecting any object here. remove() is also not working. Please help.
Create a group of grids then add to canvas, while removing remove the group object;
DEMO
var canvas = new fabric.Canvas('c', {
width: 600,
height: 600
})
var gridGroup;
function addGrid() {
if (gridGroup) return;
var gridsize = 5;
var gridoption = {
stroke: "#000000",
strokeWidth: 1,
strokeDashArray: [5, 5]
};
var gridLines = [];
for (var x = 1; x < (canvas.width); x += 100) {
gridLines.push(new fabric.Line([x, 0, x, canvas.width], gridoption));
}
for (var x = 1; x < (canvas.height); x += 100) {
gridLines.push(new fabric.Line([0, x, canvas.height, x], gridoption));
}
gridGroup = new fabric.Group(gridLines, {
selectable: false,
evented: false
})
gridGroup.addWithUpdate();
canvas.add(gridGroup);
}
function removeGrid() {
gridGroup && canvas.remove(gridGroup);
gridGroup = null;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.22/fabric.js"></script>
<button onclick='addGrid()'>Add</button>
<button onclick='removeGrid()'>Remove</button>
<canvas id="c" style="border:1px solid black"></canvas>

Modify polyline

If I want to add an extra line to an existing polyline, should I remove this existing polyline from the canvas first, modify the points matrix, and add the new polyline? Or is it possible to change the existing polyline, like changing the text of a text object?
You may remove whole polyline and add a new one or else you need to calculate the dimensions(left,top and pathoffset) and set it to polyline.
DEMO
var canvas = new fabric.Canvas('c');
var points = [];
var random = fabric.util.getRandomInt;
points.push(new fabric.Point(random(100,200),random(200,300)));
points.push(new fabric.Point(random(200,300),random(100,200)));
points.push(new fabric.Point(random(200,250),random(150,200)));
var polyLine = new fabric.Polyline(points, {
stroke: 'black',
fill: ''
});
canvas.add(polyLine);
setPolyCoords();
function addPoint(){
polyLine.points.push(new fabric.Point(random(100,400),random(100,400)));
setPolyCoords();
}
function setPolyCoords(){
polyLine._calcDimensions();
polyLine.set({
top : polyLine.minY,
left : polyLine.minX,
pathOffset : {
x: polyLine.minX + polyLine.width / 2,
y: polyLine.minY + polyLine.height / 2
}
});
polyLine.dirty = true;
polyLine.setCoords();
canvas.renderAll();
}
canvas {
border: 1px solid #f00;
margin: 0px;
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.22/fabric.js"></script>
<button onclick='addPoint()'>Add Point</button>
<canvas id="c" width="400" height="400"></canvas>
With Fabric version 2.7.0 this is become easier then in #Durga his answer.
See the new code in the demo below.
You can also skip setting the dirty flag manually by passing objectCaching: false to your polyline during construction:
var polyLine = new fabric.Polyline(points, {
stroke: 'black',
fill: '',
objectCaching: false
});
DEMO
var canvas = new fabric.Canvas('c');
var points = [];
var random = fabric.util.getRandomInt;
points.push(new fabric.Point(random(100,200),random(200,300)));
points.push(new fabric.Point(random(200,300),random(100,200)));
points.push(new fabric.Point(random(200,250),random(150,200)));
var polyLine = new fabric.Polyline(points, {
stroke: 'black',
fill: ''
});
canvas.add(polyLine);
function addPoint(){
polyLine.points.push(new fabric.Point(random(100,400),random(100,400)));
polyLine.dirty = true;
canvas.renderAll();
}
canvas {
border: 1px solid #f00;
margin: 0px;
display: block;
}
<script src="https://rawgit.com/fabricjs/fabric.js/master/dist/fabric.min.js"></script>
<button onclick='addPoint()'>Add Point</button>
<canvas id="c" width="400" height="400"></canvas>

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: Manipulate selected objects

i try to change the color of all selected objects on my canvas. I figured out that i can change properties of the group itself (this.canvas.getActiveGroup().setFill(...)).
Since i want to change different properties depending on the type of the selected object, i can't use this function. Instead i try to iterate over all selected objects and manipulate them.
this.canvas.getActiveGroup().getObjects().forEach(obj =>
{
if(obj instanceof fabric.Path)
{
obj.setStroke(color);
}
else
{
obj.setFill(color);
}
});
this.canvas.renderAll();
The color will be changed, but unfortunately after deselecting the objects all styles will be changed back.
I think the styles will be applied to the group, because when selecting again all elements will appear in the right color...
When i remove the activeGroup (this.canvas.discardActiveGroup()) before, it will work but will bring some other problems.
Btw.: the inspector (dev tools) displays the right color. After resizing a specific element it will also update its color.
Has anyone similar problems and knows a solution?
Best regards
Daniel
DEMO
var color = 'black';
function changeColor() {
var r = getRandomArbitrary(0, 225);
var g = getRandomArbitrary(0, 225);
var b = getRandomArbitrary(0, 225);
color = 'rgb(' + r + ',' + g + ',' + b + ')';
fillColorOb();
}
function getRandomArbitrary(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
var c = new fabric.Canvas('canvas');
c.add(new fabric.Circle({
left: 50,
top: 50,
radius: 50,
originX: 'center',
originY: 'center',
}))
c.add(new fabric.Circle({
left: 50,
top: 150,
radius: 50,
originX: 'center',
originY: 'center',
}))
c.add(new fabric.Circle({
left: 150,
top: 100,
radius: 50,
originX: 'center',
originY: 'center',
}))
c.renderAll();
function fillColorOb() {
var objs = c.getActiveGroup();
if(!objs) return;
objs.forEachObject(function(obj) {
if (obj instanceof fabric.Path) {
obj.setStroke(color);
} else {
obj.setFill(color);
}
c.renderAll();
});
}
fabric.Group.prototype._restoreObjectState = function(object) {
this.realizeTransform(object);
object.setCoords();
object.hasControls = object.__origHasControls;
delete object.__origHasControls;
object.set('active', false);
delete object.group;
object.dirty = true; // it will render on next renderAll() call
return this;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.16/fabric.min.js"></script>
<button type="button" name="button" onclick="changeColor();">color</button><br>
<canvas id="canvas" width="400" height="400"></canvas>
If I am , then this gonna work, check demo, add this function
fabric.Group.prototype._restoreObjectState = function(object) {
this.realizeTransform(object);
object.setCoords();
object.hasControls = object.__origHasControls;
delete object.__origHasControls;
object.set('active', false);
delete object.group;
object.dirty = true; // it will render on next renderAll() call
return this;
}

Fabricjs i-text clone issue

I am having problem in cloning fabricjs i-text. When i change the color of a selected cloned text then the original text color is also changing.
var canvas = new fabric.Canvas('mycanvas');
var itext = new fabric.IText( "New text", { left : 50, top : 50} );
itext.setSelectionStyles({fill: 'red'});
canvas.add(itext).renderAll();
$('#clone').on('click', function(){
var obj = canvas.getActiveObject();
if(obj == null) return;
var obj1 = obj.clone();
obj1.set({
letf : 150,
top : 150
});
canvas.add(obj1).renderAll();
});
$("#colorchange").on('click',function(){
var obj = canvas.getActiveObject();
if(obj == null) return;
if(obj.setSelectionStyles && obj.isEditing)
obj.setSelectionStyles({fill: 'red'});
else
obj.set({fill: 'red'});
canvas.renderAll();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.5.0/fabric.min.js"></script>
<canvas id="c"></canvas>
<script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
<canvas id="mycanvas" width="400" height="300" style="border:solid 1px #ccc;"></canvas><br>
<button id="clone">clone</button>
<button id="colorchange">change color</button>
I made a few changes and I am able to produce the result you need. Let me know if thats what you needed.
var canvas = new fabric.Canvas('mycanvas');
var itext = new fabric.IText( "New text", { left : 50, top : 50} );
itext.setSelectionStyles({fill: 'red'});
canvas.add(itext).renderAll();
$('#clone').on('click', function(){
var gobj = canvas.getActiveObject();
if(gobj == null) return;
var obj1 = gobj.clone();
var vobj = obj1;
vobj.set({
left: 100,
top: 100,
fill: 'blue'
});
canvas.add(vobj).renderAll();
});
$("#colorchange").on('click',function(){
var obj = canvas.getActiveObject();
if(obj == null) return;
if(obj.setSelectionStyles && obj.isEditing)
obj.setSelectionStyles({fill: 'red'});
else
obj.set({fill: 'red'});
canvas.renderAll();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.5.0/fabric.min.js"></script>
<script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
<canvas id="mycanvas" width="400" height="300" style="border:solid 1px #ccc;"></canvas><br>
<button id="clone">clone</button>
<button id="colorchange">change color</button>
I find the solution , guy !
The key to your problem is your clone function do not use callback.
you may use it like this :
obj.clone(function(newobj){
newobj.set({
letf : 150,
top : 150
});
canvas.add(newobj).renderAll();
});

Resources