user700284
user700284

Reputation: 13620

Updating the transform matrix of one fabric object based on the changes to the transform matrix of another object

I am trying to synchronize the move,resize and rotate operations of two fabric objects.

Consider there are two polygons - Poly1 and Poly2. When Poly1 is modified in any manner, I need to apply the same modification on Poly2 and need to get the updated points for Poly2. Below is the approach being followed :

However, this approach is only working for move operation. If you do resize or rotate on Poly1, the same is not being applied correctly on Poly2. Please let me know what I am doing wrong here.

Thanks in advance for any help!!

Sample code - Blue is Poly1 and Red is Poly2

var oldPoly1Matrix;
var canvas = new fabric.Canvas('c');
var srcOptions = {
  stroke: 'blue',
  fill: '',
  type: 'src'
};
var destOptions = {
  stroke: 'red',
  fill: '',
  selectable: false,
  hasControls: false,
  hasBorders: false,
  type: 'dest'
};
var poly1 = new fabric.Polygon([{
  x: 60,
  y: 40
}, {
  x: 160,
  y: 40
}, {
  x: 160,
  y: 140
}, {
  x: 60,
  y: 140
}], srcOptions);
var poly2 = new fabric.Polygon([{
  x: 60,
  y: 300
}, {
  x: 160,
  y: 300
}, {
  x: 160,
  y: 400
}, {
  x: 60,
  y: 400
}], destOptions);


canvas.add(poly1).add(poly2);
oldPoly1Matrix = poly1.calcTransformMatrix();
var originalPoly2Matrix = poly2.calcTransformMatrix();
poly2.matrix = originalPoly2Matrix;

function updatePoly2() {
  var newPoly1Matrix = poly1.calcTransformMatrix();
  var oldPoly1MatrixInverted = fabric.util.invertTransform(oldPoly1Matrix);
  //newMatrix = oldMatrix * someMatrix
  //therefore,someMatrix = newMatrix / oldMatrix = newMatrix * inverse(oldMatrix);
  var diffMatrix = fabric.util.multiplyTransformMatrices(newPoly1Matrix, oldPoly1MatrixInverted);
  var oldPoly2Matrix = poly2.matrix;
  //Apply the same someMatrix to find out the new transform matrix for poly2.
  var newPoly2Matrix = fabric.util.multiplyTransformMatrices(oldPoly2Matrix, diffMatrix);

  var updatedPoints = poly2.get('points')
    .map(function(p) {
      return new fabric.Point(p.x - poly2.minX - poly2.width / 2, p.y - poly2.minY - poly2.height / 2);
    })
    .map(function(p) {
      return fabric.util.transformPoint(p, newPoly2Matrix);
    });

  oldPoly1Matrix = newPoly1Matrix;
  poly2.remove();
  poly2 = new fabric.Polygon(updatedPoints, destOptions);
  poly2.matrix = newPoly2Matrix;
  canvas.add(poly2);
}
canvas {
  border: 1px solid;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.19/fabric.js"></script>
<canvas id="c" height="500" width="600"></canvas>

<button id="update" onclick="updatePoly2()">
  Update red shape
</button>

jsfiddle - https://jsfiddle.net/btxp0ck6/

Upvotes: 2

Views: 1777

Answers (1)

user700284
user700284

Reputation: 13620

It is working fine after changing the translateX and translateY calculation from matrix mulplication to simple subtraction.Posting the code here for reference.

var oldPoly1Matrix;
var canvas = new fabric.Canvas('c');
var srcOptions = {
  stroke: 'blue',
  fill: '',
  type: 'src'
};
var destOptions = {
  stroke: 'red',
  fill: '',
  selectable: false,
  hasControls: false,
  hasBorders: false,
  type: 'dest'
};
var poly1 = new fabric.Polygon([{
  x: 60,
  y: 40
}, {
  x: 160,
  y: 40
}, {
  x: 160,
  y: 140
}, {
  x: 60,
  y: 140
}], srcOptions);
var poly2 = new fabric.Polygon([{
  x: 60,
  y: 300
}, {
  x: 160,
  y: 300
}, {
  x: 160,
  y: 400
}, {
  x: 60,
  y: 400
}], destOptions);


canvas.add(poly1).add(poly2);
oldPoly1Matrix = poly1.calcTransformMatrix();
var originalPoly2Matrix = poly2.calcTransformMatrix();
poly2.matrix = originalPoly2Matrix;

function updatePoly2() {
  var newPoly1Matrix = poly1.calcTransformMatrix();
  var oldPoly1MatrixInverted = fabric.util.invertTransform(oldPoly1Matrix);
  //newMatrix = oldMatrix * someMatrix
  //therefore,someMatrix = newMatrix / oldMatrix = newMatrix * inverse(oldMatrix);
  var diffMatrix = fabric.util.multiplyTransformMatrices(newPoly1Matrix, oldPoly1MatrixInverted,true);
  diffMatrix[4] = newPoly1Matrix[4] - oldPoly1Matrix[4];
  diffMatrix[5] = newPoly1Matrix[5] - oldPoly1Matrix[5];
  var oldPoly2Matrix = poly2.calcTransformMatrix();
  //Apply the same someMatrix to find out the new transform matrix for poly2.
  var newPoly2Matrix = fabric.util.multiplyTransformMatrices(oldPoly2Matrix, diffMatrix,true);
  newPoly2Matrix[4] = oldPoly2Matrix[4] + diffMatrix[4];
  newPoly2Matrix[5] = oldPoly2Matrix[5] + diffMatrix[5];
  var updatedPoints = poly2.get('points')
    .map(function(p) {
      return new fabric.Point(p.x - poly2.minX - poly2.width / 2, p.y - poly2.minY - poly2.height / 2);
    })
    .map(function(p) {
      return fabric.util.transformPoint(p, newPoly2Matrix);
    });

  oldPoly1Matrix = newPoly1Matrix;
  poly2.remove();
  poly2 = new fabric.Polygon(updatedPoints, destOptions);
  poly2.matrix = newPoly2Matrix;
  canvas.add(poly2);
}
canvas {
  border: 1px solid;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.19/fabric.js"></script>
<canvas id="c" height="500" width="600"></canvas>

<button id="update" onclick="updatePoly2()">
  Update red shape
</button>

Jsfiddle - https://jsfiddle.net/btxp0ck6/1/

Upvotes: 3

Related Questions