Jump to content
Search Community

How to access each individual transformation matrix for SVG

jama1017 test
Moderator Tag

Go to solution Solved by GreenSock,

Recommended Posts

Hi!

 

I want to begin by thanking the developers of GSAP for creating this wonderful tool. I have been using it since 2018.

 

My question is pretty straightforward from the title. An example scenario can be found in the CodePen demo. Basically, when I want to rotate a square by 90 degrees around a point (in the demo, it is (300, 200) in SVG coordinate, as indicated by the blue dot), the transformation matrices needed are first a Translation matrix T_{-1} that offsets the object by -300, -200, then a Rotation matrix R that rotates the object by 90, then the inverse of that first Translation matrix T that brings the object back by offseting it with 300, 200. The final aggragated transformation matrix is then the product of (T)(R)(T_{-1})

 

By inspecting the final transformation matrix that GSAP sets for the square element via the transform attribute, I am pretty sure this is how GSAP handles rotation around an arbirtrary point, instead of setting the transform-origin attribute. I wonder then how I can access each of the individual T, R, and T_{-1} matricies? If there is not a direct function call to get these, can you point to me where in the source were these matricies computed?

 

Thanks!

 

See the Pen ExMKoPO by jama1017 (@jama1017) on CodePen

Link to comment
Share on other sites

Hi @jama1017 welcome to the forum and thanks for being a club member 🎉

 

I'm not completely sure what it is you're looking for, that said this was the first thing that sprang to mind https://gsap.com/docs/v3/Plugins/MotionPathPlugin/static.convertCoordinates() with the demo at the bottom of the page. 

 

See the Pen GRJEGzB by GreenSock (@GreenSock) on CodePen

  • Like 1
Link to comment
Share on other sites

12 hours ago, jama1017 said:

I wonder then how I can access each of the individual T, R, and T_{-1} matricies? If there is not a direct function call to get these, can you point to me where in the source were these matricies computed?

I'm a bit confused by the question, but let me explain a few things in case it helps....

  1. In order to work around browser inconsistencies (especially with transform-origin), GSAP always sets transform-origin to 0 and then bakes the real one into the matrix(...) itself. 
  2. GSAP always applies a consistent order of operation in terms of translate, rotate, scale, skew. 
  3. One of the biggest strengths of GSAP is that it allows you to animate each transform component individually (x, y, rotation, scaleX, scaleY, etc.) 
  4. You can get each individual component anytime by using gsap.getProperty(), like gsap.getProperty(element, "x") to get the x translate value. 

Why are you trying to access the matrix values directly? Or maybe I'm misunderstanding. Perhaps it'd help if you clarified your end goal (the "why" behind your question). 

Link to comment
Share on other sites

4 hours ago, GreenSock said:

I'm a bit confused by the question, but let me explain a few things in case it helps....

  1. In order to work around browser inconsistencies (especially with transform-origin), GSAP always sets transform-origin to 0 and then bakes the real one into the matrix(...) itself. 

Hi! Thanks for your reply. Your first point here touches upon exactly what I was asking for. Because GSAP sets transform-origin to 0 and bakes the real one into the matrix, the "baking the real one" operation here involves what I described in my question: in order to rotate around the point (300, 200), the square element needs to be first translated by -300, -200, then rotated by 90, then translated back by 300, 200. These transforamtions are done via matricies, i.e. (T)(R)(T_{-1}).

 

Right now, if I inspect the SVG code, I can see that GSAP updates the transform attribute of the square element with a matrix every frame, and that matrix is the end product of (T)(R)(T_{-1}). I wonder how I can access T, R, T_{-1} individually, as these matricies have to exist at some point in the GSAP code for it to produce the resulting matrix that is being set as the value for the transform attribute.

Link to comment
Share on other sites

  • Solution
33 minutes ago, jama1017 said:

I wonder how I can access T, R, T_{-1} individually, as these matricies have to exist at some point in the GSAP code for it to produce the resulting matrix that is being set as the value for the transform attribute.

That isn't how it works, sorry. GSAP just takes the various components (x, y, rotation, scaleX, scaleY, skewX, skewY) and builds the matrix() accordingly, with the origin factored in too. You referred to "(T)(R)(T_{-1})" but that's a foreign concept in terms of GSAP. It's not as if there's a way to grab the a T variable and an R variable. You can get any of the components via the gsap.getProperty() method, though. 

 

Again, I think it might really help if you explain the "why" behind your question because perhaps there's a much better way to help you. 

 

Are you asking for the formula we're using for calculating the matrix()? If so...

if (skewY) { //for performance reasons, we combine all skewing into the skewX and rotation values. Remember, a skewY of 10 degrees looks the same as a rotation of 10 degrees plus a skewX of 10 degrees.
  skewY = parseFloat(skewY);
  skewX += skewY;
  rotation += skewY;
}
if (rotation || skewX) {
  rotation *= _DEG2RAD;
  skewX *= _DEG2RAD;
  a11 = Math.cos(rotation) * scaleX;
  a21 = Math.sin(rotation) * scaleX;
  a12 = Math.sin(rotation - skewX) * -scaleY;
  a22 = Math.cos(rotation - skewX) * scaleY;
  if (skewX) {
    skewY *= _DEG2RAD;
    temp = Math.tan(skewX - skewY);
    temp = Math.sqrt(1 + temp * temp);
    a12 *= temp;
    a22 *= temp;
    if (skewY) {
      temp = Math.tan(skewY);
      temp = Math.sqrt(1 + temp * temp);
      a11 *= temp;
      a21 *= temp;
    }
  }
  a11 = _round(a11);
  a21 = _round(a21);
  a12 = _round(a12);
  a22 = _round(a22);
} else {
  a11 = scaleX;
  a22 = scaleY;
  a21 = a12 = 0;
}
if ((tx && !~(x + "").indexOf("px")) || (ty && !~(y + "").indexOf("px"))) {
  tx = _convertToUnit(target, "x", x, "px");
  ty = _convertToUnit(target, "y", y, "px");
}
if (xOrigin || yOrigin || xOffset || yOffset) {
  tx = _round(tx + xOrigin - (xOrigin * a11 + yOrigin * a12) + xOffset);
  ty = _round(ty + yOrigin - (xOrigin * a21 + yOrigin * a22) + yOffset);
}
if (xPercent || yPercent) {
  //The SVG spec doesn't support percentage-based translation in the "transform" attribute, so we merge it into the translation to simulate it.
  temp = target.getBBox();
  tx = _round(tx + xPercent / 100 * temp.width);
  ty = _round(ty + yPercent / 100 * temp.height);
}
temp = "matrix(" + a11 + "," + a21 + "," + a12 + "," + a22 + "," + tx + "," + ty + ")";
target.setAttribute("transform", temp);

I hope that helps.

  • Like 1
Link to comment
Share on other sites

Posted (edited)

Hi Jack,

 

Thanks for sharing the code! Actually I think this is what I was looking for. I now see that GSAP does not explicitly multiply a bunch of transformation matricies together but instead directly build the final aggragated transformation matrix. However, the math works out to be the same based on the code you shared. The (T)(R)(T_{-1}) I was referring to is kind of explained in this link under the section "Rotation around a point":  https://www.alanzucconi.com/2016/02/10/tranfsormation-matrix/.

 

Basically, if you work out the matrix math of (T)(R)(T_{-1}) manually, you would see that the final tx and ty value matches the two lines here, with scaleX = scaleY = 1 and skewX = skewY = 0:

Quote
if (xOrigin || yOrigin || xOffset || yOffset) {
  tx = _round(tx + xOrigin - (xOrigin * a11 + yOrigin * a12) + xOffset);
  ty = _round(ty + yOrigin - (xOrigin * a21 + yOrigin * a22) + yOffset);

 

As for what I am trying to achieve, I was trying to see if I can reverse-engineer the xOrigin and yOrigin values set through the transformOrigin attribute in the GSAP API, assuming that I somehow don't have access to the original GSAP animation code for the animation I showed in the CodePen (i.e. I only have access to the final animation and can call functions on gsap/timeline objects, etc, but not the GSAP code that generates the animation).

 

As a follow-up question, I wonder if there is a straightforward way to get the values of xOrigin, yOrigin, xOffset, and yOffset (and what actually does xOffset and yOffset refer to again)?

Edited by jama1017
Accidentally submitted before I finished
Link to comment
Share on other sites

5 minutes ago, jama1017 said:

I now see that GSAP does not explicitly multiply a bunch of transformation matricies together but instead directly build the final aggragated transformation matrix.

Yep, it's much more performant that way. We tend to obsess about performance since animation is so performance-sensitive. 🙂

 

Glad you got what you need now. 

Link to comment
Share on other sites

8 minutes ago, jama1017 said:

As a follow-up question, I wonder if there is a straightforward way to get the values of xOrigin, yOrigin, xOffset, and yOffset (and what actually does xOffset and yOffset refer to again)?

Sorry I accidentally submitted my reply before actually finished typing this line. Can you help me with this follow-up question also?

 

Thanks!

Link to comment
Share on other sites

10 minutes ago, jama1017 said:

As a follow-up question, I wonder if there is a straightforward way to get the values of xOrigin, yOrigin, xOffset, and yOffset (and what actually does xOffset and yOffset refer to again)?

xOffset and yOffset have to do with the smoothOrigin feature. That's an internal thing - there's not an official way to get those values. And the xOrigin and yOrigin are similar in that regard, but they refer to the origin of course. 🙂

 

Why do you want these values? What practical purpose would they serve for you? Sorry to be annoying - I think this is the 3rd or 4th time I'm asking you to explain the "why" behind all these questions. 🤔

Link to comment
Share on other sites

15 minutes ago, jama1017 said:

As for what I am trying to achieve, I was trying to see if I can reverse-engineer the xOrigin and yOrigin values set through the transformOrigin attribute in the GSAP API, assuming that I somehow don't have access to the original GSAP animation code for the animation I showed in the CodePen (i.e. I only have access to the final animation and can call functions on gsap/timeline objects, etc, but not the actual GSAP code (gsap.to()...)that generates the animation).

You might have missed this but I explained what I was trying to achieve here.

  • Thanks 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...