fabricjs - matrix hierarchy

Get canvas space coordinates of group child object

by mmalex

HTML

<script src="https://rawgithub.com/kangax/fabric.js/master/dist/fabric.js"></script>
<button onclick="getCoords();">Get Yellow Rect Coords</button>
<button onclick="recenterCanvas()">Pan canvas to red dot</button>
<p id="output">yellow rect coords: {}</p>
<canvas id="c" width="400" height="400"></canvas>
<p>
  Hint: Move and rotate fabricJs group of objects.<br>Click the button to calculate coordinates of yellow rectangle.
</p>

CSS

canvas {
  border: 1px solid #999;
  display: inline-block;
}

button {
  margin-top: 20px;
}

body {
  font-family: sans-serif;
  font-size: 10pt;
}

#output {
  font-family: consolas;
}

JavaScript

// 1. arrange canvas layout with group of two rectangles
    var canvas = new fabric.Canvas(document.getElementById('c'));
    canvas.setBackgroundImage("http://mbnsay.com/rayys/images/bricks_background.jpg", canvas.renderAll.bind(canvas));

    var rect = new fabric.Rect({
      width: 100,
      height: 100,
      left: 50,
      top: 50,
      fill: 'rgba(255,0,0,0.25)'
    });
    var smallRect = new fabric.Rect({
      width: 12,
      height: 12,
      left: 150 - 12,
      top: 50 + 50 - 12 / 2 - 10,
      fill: 'rgba(250,250,0,0.5)'
    });

    // 2. add a position marker (red dot) for visibility and debug reasons
    var refRect = new fabric.Rect({
      width: 3,
      height: 3,
      left: 100,
      top: 100,
      fill: 'rgba(255,0,0,0.75)'
    });

    var group = new fabric.Group([rect, smallRect], {
      originX: 'center',
      originY: 'center'
    });
    canvas.add(group);
    canvas.add(refRect);
    canvas.renderAll();
    
    function panTo(canvas, obj) {
      let w = canvas.getWidth();
      let h = canvas.getHeight();

      let targetX = obj.left + obj.width / 2;
      let targetY = obj.top + obj.height / 2;

    	canvas.absolutePan(new fabric.Point(-w/2+targetX, -h/2+targetY))
    }
    
    function recenterCanvas() {
    	panTo(canvas, refRect);
      canvas.bringToFront(refRect);
      canvas.renderAll();
    }

    // 3. calculate coordinates of child object in canvas space coords
    function getCoords() {
      // get transformation matrixes for object and group individually
      var mGroup = group.calcTransformMatrix(true);

      // flag true means that we need local transformation for the object,
      // i.e. how object is positioned INSIDE the group
      var mObject = smallRect.calcTransformMatrix(true);

      console.log("group: ", fabric.util.qrDecompose(mGroup));
      console.log("rect: ", fabric.util.qrDecompose(mObject));

      // get total transformattions that were applied to the child object,
      // the...