Just_Paul Just_Paul - 1 month ago 19
Javascript Question

Fabric.js: Properties of group members not updating after scaling

I'm using Fabric.js to create a group of two rectangles that are lying next to each other. I want the left one to change it's color when I'm moving my mouse over it. Therefore I check if the position of the mouse-cursor is within the the boundary of the rectangle or not.
This works fine until I scale the group...
I made a few tests and found out that the properties of the group members don't change. So while the rectangles become larger they still show their old sizes.
This is my code:

farbicCanvas = new fabric.Canvas('c');

farbicCanvas.on('object:scaling', function(e)
{
//Show the sizes
console.log("group width: " + e.target.getWidth());
console.log("rect1 width: " + e.target.item(0).getWidth());
console.log("rect2 width: " + e.target.item(1).getWidth());
});

farbicCanvas.on('mouse:move', function(e)
{
if(e.target !== null)
{
point = new getMouseCoords(farbicCanvas, event);

//Check if cursor is within the boundary of rect2
if(point.posX >= e.target.item(1).getLeft() + e.target.getLeft() + e.target.getWidth()/2
&& point.posX <= e.target.item(1).getLeft() + e.target.getLeft() + e.target.getWidth()/2 + e.target.item(1).getWidth()
&& point.posY >= e.target.getTop()
&& point.posY <= e.target.getTop() + e.target.item(1).getHeight())
{
e.target.item(1).set({ fill: 'rgb(0,0,255)' });
farbicCanvas.renderAll();
}
else
{
farbicCanvas.getObjects()[0].item(1).set({ fill: 'rgb(0,255,0)' });
farbicCanvas.renderAll();
}
}
else
{
farbicCanvas.getObjects()[0].item(1).set({ fill: 'rgb(0,255,0)' });
farbicCanvas.renderAll();
}
});

var rect1 = new fabric.Rect(
{
left: 100,
top: 100,
width: 100,
height: 75,
fill: 'rgb(255,0,0)',
opacity: 0.5
});

var rect2 = new fabric.Rect(
{
left: rect1.getLeft() + rect1.getWidth(),
top: rect1.getTop(),
width: 100,
height: 75,
fill: 'rgb(0,255,0)',
opacity: 0.5
});

group = new fabric.Group([rect1, rect2]);
farbicCanvas.add(group);

function getMouseCoords(canvas, event)
{
var pointer = canvas.getPointer(event.e);
this.posX = pointer.x;
this.posY = pointer.y;
}


I've also made a Fiddle: https://jsfiddle.net/werschon/0uduqfpe/3/
If I make the group larger, my 'mouse-detection' doesn't work anymore, because the properties like
left
,
top
or
width
are not updating.
What do I need to do, to update the properties? Or is there another way of detecting if the mouse-cursor is above the rectangle?

Thanks.

Answer

I found a solution (Thanks to John Morgan): I have to calculate the properties of the group members by myself. With getScaleX() and getScaleY() I can get the scale-factors of the group. Then I need to multiply the properties of the group members with the appropriate scale-factor. As result I get the new values of the group member. In my example I only needed getScaleX() to calculate the width of rect2 so it looks like this: e.target.item(1).getWidth() * e.target.getScaleX(). This is the new code:

farbicCanvas = new fabric.Canvas('c');

farbicCanvas.on('object:scaling', function(e)
{
    console.log("group width: " + e.target.getWidth());
    console.log("rect1 width: " + e.target.item(0).getWidth() * e.target.getScaleX());
    console.log("rect2 width: " + e.target.item(1).getWidth() * e.target.getScaleX());
});

farbicCanvas.on('mouse:move', function(e)
{
    if(e.target !== null)
    {
        point = new getMouseCoords(farbicCanvas, event);

        if(point.posX >= e.target.getLeft() + e.target.getWidth() - e.target.item(1).getWidth() * e.target.getScaleX() 
        && point.posX <= e.target.getLeft() + e.target.getWidth()
        && point.posY >= e.target.getTop() 
        && point.posY <= e.target.getTop() + e.target.getHeight())
        {
            e.target.item(1).set({ fill: 'rgb(0,0,255)' });
            farbicCanvas.renderAll();
        } 
        else
        {
            e.target.item(1).set({ fill: 'rgb(0,255,0)' });
            farbicCanvas.renderAll(); 
        }
    }
    else 
    {
        farbicCanvas.getObjects()[0].item(1).set({ fill: 'rgb(0,255,0)' });
        farbicCanvas.renderAll();
    }
});

farbicCanvas.on('mouse:out', function(e)
{
    farbicCanvas.getObjects()[0].item(1).set({ fill: 'rgb(0,255,0)' });
    farbicCanvas.renderAll();
});

var rect1 = new fabric.Rect(
{
    left: 100,
    top: 100,
    width: 100,
    height: 75,
    fill: 'rgb(255,0,0)',
    opacity: 0.5
});

var rect2 = new fabric.Rect(
{
    left: rect1.getLeft() + rect1.getWidth(),
    top: rect1.getTop(),
    width: 100,
    height: 75,
    fill: 'rgb(0,255,0)',
    opacity: 0.5
});

group = new fabric.Group([rect1, rect2]);
farbicCanvas.add(group);

function getMouseCoords(canvas, event)
{
    var pointer = canvas.getPointer(event.e);
    this.posX = pointer.x;
    this.posY = pointer.y;
}

I've also created a new Fiddle. So now my mouse-detection works even after scaling