Sure, it’s just basic transform code.
The transform function is
function applyTransform(obj, xform)
{
// add to object's "total" transformation
obj.xform = mulm3m3(obj.xform, xform);
// apply only this transformation to the position (only for points)
const p = mulv2m3(
point(obj.x, obj.y),
xform);
obj.x = p.x;
obj.y = p.y;
}
and the transforms are
applyTransform(obj, // move
[[1, 0, x],
[0, 1, y],
[0, 0, 1]]);
applyTransform(obj, // scale
[[sx, 0, 0],
[0, sy, 0],
[0, 0, 1]]);
applyTransform(obj, // rotate
[[ Math.cos(angle), Math.sin(angle), 0],
[-Math.sin(angle), Math.cos(angle), 0],
[ 0, 0, 1]]);
applyTransform(obj, // skew
[[1, sx, 0],
[sy, 1, 0],
[0, 0, 1]]);
Then, when it comes to actually updating the objects, I have two functions:
// figObj is the Figma object I'm updating, this is what is coming out wrong
// genObj is the generated object that I calculated
function setObjectTransform(figObj, genObj) // called for objects
{
// make axis vectors == 1
const scaleX = Math.sqrt(sqr(genObj.xform[0][0]) + sqr(genObj.xform[1][0]));
const scaleY = Math.sqrt(sqr(genObj.xform[0][1]) + sqr(genObj.xform[1][1]));
genObj.xform[0][0] /= scaleX;
genObj.xform[1][0] /= scaleX;
genObj.xform[0][1] /= scaleY;
genObj.xform[1][1] /= scaleY;
// do magic to make object transform correctly ???
figObj.resizeWithoutConstraints(
Math.max(0.01, genObj.width * scaleX),
Math.max(0.01, genObj.height * scaleY));
figObj.relativeTransform =
[
genObj.xform[0],
genObj.xform[1]
];
}
function setPointTransform(figPoint, genPoint) // called for points
{
figPoint.resizeWithoutConstraints(0.01, 0.01);
figPoint.x = genPoint.x;
figPoint.y = genPoint.y;
// no transform here, points are already transformed at every step
// so here I only care about their positions
}
mulm3m3()
and mulv2m3()
multiply vectors and matrices as their names imply.
So, every time I do a transformation, I update the object’s xform
member (my own internal 3x3 matrix), but I also use just the current transformation to transform the object’s position.
On the Figma side, I use the transform if it’s an object and .x and .y if it’s a point. This way the points arrive correctly transformed and I can use them to test object transformation. Right now the result is not the same.
Maybe I’m not understanding the matrix thing correctly. Can’t I just have a complicated compound “final” transform applied to an untransformed object and have it do all the transformations in correct sequence?
Or, now that I think about it some more, do I have to keep an array of transformations, and then resize/transform/skew the object once for each transformation?