Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fabric.js: what is the difference between `add()` and `addWithUpdate()`?

var canvas = new fabric.Canvas('canvas');
var a = new fabric.Rect({ width: 20, height: 20 });
var g = new fabric.Group([a]);
canvas.add(g);

var b = new fabric.Rect({ width: 20, height: 20, left: 30 });
g.add(b);
canvas.renderAll();

I expect this code to give me two squares horizontally separated by 30 pixels. Instead, it gives me this:

squares not aligned!

When I replace g.add() above with g.addWithUpdate(), I get the expected result. Why? I don't think I understand the docs; they say that addWithUpdate()

Adds an object to a group; Then recalculates group's dimension, position.

I don't see what the group's dimensions or positions has to do with this. Can anyone shed some light? The real problem I'm having is more complicated than the one above, but I think is basically because I don't understand addWithUpdate().

like image 896
Eli Rose Avatar asked Dec 25 '22 10:12

Eli Rose


1 Answers

I would say is a bug, but is more a docs issue. fabric.Group inherits from fabric.Collection and fabric.Object. The .add method comes from the .Collection and is created more for the canvas and compatible with the .Group.

The point is that in the Group every object gets positioned relative to group center. top and left of every object get subtracted with the group center.

What addWithUpdate does is:

ungroup all objects restore their original top and left add the new object regroup them all --when regrouping: --check bounding boxes of all objects, --make a bounding box of the bounding boxes --derive top,left,width and height of the group, --subtract to every object top and left half the the height and the width.

What add does is: put the object in the _objects array of the group

So as of now adding objects to group with just .add is really wrong.

Less wrong is:

create empty Group, add all objects with .add(), call an empty .addWithUpdate() and .setCoords() finally as shown in the fiddle.

You should consider this only if you are adding lot of objects without any user interaction between each other call of .add() method to save on some calculation.

var canvas = new fabric.Canvas('canvas');
var a = new fabric.Rect({ width: 20, height: 20});
var g = new fabric.Group();
canvas.add(g);

var b = new fabric.Rect({ width: 20, height: 20, left: 30, top:0 });
var c = new fabric.Rect({ width: 20, height: 20, left: 60, top:0 });
g.add(b);
g.add(c);
g.add(a);
g.addWithUpdate();
g.setCoords();
canvas.renderAll();
<script src="http://www.fabricjs.com/lib/fabric.js"></script>
<canvas id='canvas'></canvas>
like image 58
AndreaBogazzi Avatar answered Feb 15 '23 11:02

AndreaBogazzi