Search code examples
google-apps-scriptgoogle-slides-apigoogle-slides

Google Slides Rotate Rectangle 35 degrees


I am trying to understand the Google Slides API Rotate function.

3000000 is the Object width and Height. If we wanted to rotate Rectangle 35 degrees Counter clockwise,

Trying to understand example parameters in documentation, and how to rotate https://developers.google.com/slides/samples/transform

  1. What is -0.5 below and 0.3? How are they derived?
  2. Additionally, what is -2000000 and -550000?

Last curious if there any shorthand method of doing this? Three requests for 15 lines, just to rotate a rectangle?

{
  "requests": [
    {
      "updatePageElementTransform": {
          "objectId": pageElementId,
          "applyMode": "RELATIVE",
          "transform": {
              "scaleX":  1,
              "scaleY":  1,
              "translateX": -2000000 - 0.5 * 0.3  * 3000000,
              "translateY":  -550000 - 0.5 * 0.12 * 3000000,
              "unit": "EMU"
          }
      }
    },
    {
      "updatePageElementTransform": {
        "objectId": pageElementId,
        "applyMode": "RELATIVE",
        "transform": {
            "scaleX":  cos(35 * (pi/180)),
            "scaleY":  cos(35 * (pi/180)),
            "shearX":  sin(35 * (pi/180)),
            "shearY": -sin(35 * (pi/180)),
            "unit": "EMU"
        }
      }
    },
    {
      "updatePageElementTransform": {
        "objectId": pageElementId,
        "applyMode": "RELATIVE",
        "transform": {
            "scaleX":  1,
            "scaleY":  1,
            "translateX":  2000000 + 0.5 * 0.3  * 3000000,
            "translateY":   550000 + 0.5 * 0.12 * 3000000,
            "unit": "EMU"
        }
      }
    }
  ]
}

By the way, just opened feature request for shorthand rotate, will try to figure it out for now https://issuetracker.google.com/u/2/issues/183986639


Solution

  • Answer:

    When completing transformations on shapes in Slides, all operations are done from the frame of reference of the origin of the page. This point is the top-left point of the page.

    More Information:

    At the top of the page on Transform Operations, it states that the examples on the page assume the existence of a defined arrow shape:

    For these examples, assume that there exists an example arrow shape page element with the following size and transform data (which can be found with a presentations.pages.get request):

    {
      "objectId": pageElementId,
      "size": {
        "width": {
          "magnitude": 3000000,
          "unit": "EMU"
        },
        "height": {
          "magnitude": 3000000,
          "unit": "EMU"
        }
      },
      "transform": {
        "scaleX": 0.3,
        "scaleY": 0.12,
        "shearX": 0,
        "shearY": 0,
        "translateX": 2000000,
        "translateY":  550000,
        "unit": "EMU"
      },
      "shape": {
        "shapeType": "RIGHT_ARROW"
      }
    }
    

    So to answer your first two questions:

    • The 0.3 is taken from the sclaing factor of the arrow.
    • The -2000000 and -550000 are used to translate the shape to the origin of the page
    • The -0.5 is used to halve the translation distance (as we are doing the rotation from the shape's centre rather than its vertex)

    Also, from the documentation on Sizing and Positioning Page Elements (emphasis my own):

    Rotation transforms rotate a page element around a point, using the scaling and shear parameters. The basic rotation transform matrix has the following form, where the angle of rotation (in radians) is measured from the X-axis, moving counterclockwise:

    enter image description here

    As with scaling, you can use this matrix form directly as a RELATIVE transform to rotate an element, but this causes the element to be rotated about the origin of the page. To rotate the element about its center or a different point, shift to that reference frame.

    So simple answer: yes you can do it in one request, but you will have to do the calculations for shifting to the element's reference frame yourself and send that request to the API instead.

    References: