What impact does the sequence of transforms have? The outcome of rotate/scale differs from that of scale/rotate

After going through the SVG specification, as well as resources like this and this, I'm finding it difficult to fully grasp how chaining transforms function.

Selected Relevant Quotations

By applying the transform attribute to an SVG element, that element essentially receives a duplicate of the current user coordinate system in use.

Additionally:

When transformations are chained together, the key thing to keep in mind is that similar to HTML element transformations, each transformation impacts the coordinate system after it has been transformed by preceding transformations.

In addition:

To illustrate, if you intend to apply a rotation followed by a translation to an element, the translation occurs based on the updated coordinate system, not the original non-rotated one.

Lastly:

The order of transformations holds significance. The order in which the transformation functions appear within the transform attribute determines the sequence in which they affect the shape.

Code Example

The first rectangle's current coordinate system undergoes scaling first and then rotation (pay attention to the sequence). Meanwhile, the second rectangle's current coordinate system experiences rotation prior to scaling.

svg {
  border: 1px solid green;
}
<svg xmlns="http://www.w3.org/2000/svg">
  <style>
    rect#s1 {
      fill: red;
      transform: scale(2, 1) rotate(10deg);
    }
  </style>
  <rect id="s1" x="" y="" width="100" height="100" />
</svg>

<svg xmlns="http://www.w3.org/2000/svg">
  <style>
    rect#s2 {
      fill: blue;
      transform: rotate(10deg) scale(2, 1);
    }
  </style>
  <rect id="s2" x="" y="" width="100" height="100" />
</svg>

Question

We're aware that when linking transforms, a duplicate of the current coordinate system in use for that element is created, and then the transforms are executed according to the specified order.

When we have a scaled user coordinate system and add a rotation to it, the rectangle is essentially skewed (as noted by the changed angles). However, this effect is avoided when the two transforms are done inversely (rotate first, then scale).

I would greatly appreciate expert insights into exactly how the scaled current coordinate system is rotated. I am seeking to comprehend, from a technical perspective, why the skewing occurs in the initial rectangle.

Thank you.

Answer №1

To demonstrate the functionality, let's take a look at an animation showcasing how the rotation changes with the scaling effect.

.red {
  width:80px;
  height:20px;
  background:red;
  margin:80px;
  transform-origin:left center;
  animation: rotate 2s linear infinite;
}
@keyframes rotate {
  from{transform:rotate(0)}
  to{transform:rotate(360deg)}

}
<div class="container">
<div class="red">
</div>
</div>

Looking at the above, we can observe that the rotation results in a perfect circle shape.

Now, let's adjust the scale of the container and see the impact:

.red {
  width:80px;
  height:20px;
  background:red;
  margin:80px;
  transform-origin:left center;
  animation: rotate 5s linear infinite;
}
@keyframes rotate {
  from{transform:rotate(0)}
  to{transform:rotate(360deg)}

}
.container {
  display:inline-block;
  transform:scale(3,1);
  transform-origin:left center;
}
<div class="container">
<div class="red">
</div>
</div>

It is evident that instead of a circle, we now have an ellipse after applying the scaling, resembling a stretched circle leading to a skew effect inside our rectangle.


If we reverse the order by first applying a scale transformation followed by a rotation, we eliminate any skewing.

.red {
  width:80px;
  height:20px;
  background:red;
  margin:80px;
  animation: rotate 2s linear infinite;
}
@keyframes rotate {
  from{transform:scale(1,1)}
  to{transform:scale(3,1)}

}
.container {
  display:inline-block;
  transform:rotate(30deg);
  transform-origin:left center;
}
<div class="container">
<div class="red">
</div>
</div>

In simpler terms, when you apply a rotation, it maintains the aspect ratio between both X and Y axes, preventing any negative effects upon subsequent scaling. However, if you only scale along one axis, the ratio gets distorted resulting in distortions when rotating.


You might want to refer to this link for detailed insights on chaining transforms and matrix calculation: https://www.w3.org/TR/css-transforms-1/#transform-rendering. Although referring to HTML elements, SVG specifications iterate similar practices.

Highlighted excerpts:

Transformations accumulate, rendering each element within its parent's coordinate system.

A user's perspective sees an element incorporating the transform properties of ancestors alongside local transformations applied directly to it.


Let's delve into some mathematical calculations to discern the disparities between these transformations. Focusing on matrix multiplication and limiting our scope to 2D linear transformations using ℝ² for ease1.

Given scale(2, 1) rotate(10deg), computation yields:

 |2 0|   |cos(10deg) -sin(10deg)|   |2*cos(10deg) -2*sin(10deg) |
 |0 1| x |sin(10deg) cos(10deg) | = |1*sin(10deg) 1*cos(10deg)  |

Subsequent application of this matrix on ((Xi,Yi)) produces (Xf,Yf):

 Xf =  2*Xi*cos(10deg) - Yi*sin(10deg)
 Yf =  Xi*sin(10deg) + Yi*cos(10deg)

Note the additional multiplier affecting Xf, ultimately generating the skew. Altering the behavior of Xf while preserving Yf.

Now considering rotate(10deg) scale(2, 1):

 |cos(10deg) -sin(10deg)|   |2 0|   |2*cos(10deg) -1*sin(10deg) |
 |sin(10deg) cos(10deg) | x |0 1| = |2*sin(10deg) 1*cos(10deg)  |

Resulting in:

 Xf =  2*Xi*cos(10deg) - Yi*sin(10deg)
 Yf =  2*Xi*sin(10deg) + Yi*cos(10deg)

Here, treating 2*Xi as Xt, reflects a rotated element (Xt,Yi) initially scaled along the X-axis.


1CSS implements affine transformations (e.g., translate), thus operating solely on ℝ² (Cartesian coordinates) may not suffice, mandating consideration of ℝℙ² (Homogeneous coordinates). In instances involving translations combined with other transformations like scale(2, 1) translate(10px,20px), envisage the following:

 |2 0 0|   |1 0 10px|   |2 0 20px|
 |0 1 0| x |0 1 20px| = |0 1 20px|
 |0 0 1|   |0 0 1   |   |0 0  1  |

Resulting in:

Xf =  2*Xi + 20px;
Yf =  Yi + 20px;
1  =  1 

Answer №2

Temani Afif's explanation of coordinate systems and transformations is like a journey through different spaces on the canvas. Starting from the viewport, each coordinate system builds upon the last, creating a unique perspective that may not always follow cartesian principles. These systems are constructed in the DOM tree from the outside inward, and when applied in an attribute, they unfold from left to right.

Alternatively, you can visualize the transformation process in reverse: beginning with a rectangle in its original cartesian userspace coordinates, then applying a series of scales, rotations, and other adjustments until it morphs into something new within the viewport coordinate system.

However, when viewing transformations in this alternate way, the order of operations becomes crucial. For example,

transform: scale(2, 1) rotate(10deg)
instructs the system to first rotate the rectangle by 10 degrees before scaling it horizontally.

In essence, the direction in which you approach transformations determines how they are interpreted:

  • When working in a transformed coordinate system, apply transforms left-to-right to establish the correct positioning.
  • On the other hand, when dealing with a transformed graphic in the original coordinate system, arrange the transforms right-to-left for accurate visualization.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best way to align elements within a row/column layout in Angular Material when working with divs?

To set up two div blocks in a row, I'm utilizing the code below: <div layout="column" layout-gt-xs="row" layout-align="center center" id="row"> <div id="a">a</div> <div id="b">b</div> </div> The CSS for this ...

What is the best way to apply a datepicker to all textboxes with a specific class using jQuery?

I have enclosed multiple fields within div elements in order to specify them with a datepicker for a better user experience. For example: <div class="need-date" > <label>Appointment Date</label> <input id="id_appointment_date" ty ...

Tips for aligning ticks to the left on a d3 bar chart

i recently finished creating a stacked bar graph with varying tick lengths on the y-axis side. my goal is to align the text within the ticks to the left, similar to this example: http://jsfiddle.net/2khbceut/2/ here is the HTML: <title>Diverging Sta ...

The scroll bar is visible on the scroll box, but unfortunately it is not functional in Internet Explorer 8

http://example.com/code <div style="width:625px;height:220px;overflow-y:hidden;overflow-x:scroll;z-index:10;"> <table width="1000" height="114" border="1"> <tr> <td width ...

I'm unsure of the steps to take to complete this task. Thank you

Make sure to create a container DIV with the CSS class of "menu". Inside this .menu DIV, there should be 4 additional DIV elements, each having a class of "item". Every .item DIV needs to have an IMAGE element that displays a placeholder image from , and ...

I am curious as to why the Bootstrap 4 dropright selected menu appears as a default browser button in Chrome, while it functions seamlessly in Firefox

An issue has been identified that is specific to Chrome. The dropright selected menu appears differently in Chrome compared to Firefox, where it displays correctly with a white background. !https://i.sstatic.net/BulRA.jpg The Bootstrap version being used ...

What is the best way to load specific CSS in an rhtml file?

In the world of website development, we often find several pages that are generated from the same layout.rhtml file. Along with a global css file, each page may also have its own unique css file - such as page1.css for page1.rhtml and page2.css for page2.r ...

Webpage with visual representation

Currently in the process of redesigning my university's drama department website, I'm looking to incorporate three images side by side with spacing and captions. The captions need to have a header that's styled differently from the caption i ...

Tips for creating various column widths within a single row

Hey there, I'm currently working on a web application using Bootstrap and running into an issue with the grid system. Whenever I add elements to a column, all the columns in the same row stretch together, which is not the desired behavior. Take a look ...

What is the best way to position a bigger character directly above a smaller container?

My goal is to center a single character, using CSS, in a span that is smaller than the character itself. The setup I have is: <span id="A">X</span><span id="B">Y</span><span id="C">Z</span> All three spans are styled ...

Encase children within a view component in React Native

I've been working on the following code: renderActionButtons(actionButtons){ let actionButtonsContent = actionButtons.map((button, i) => { return <TouchableHighlight key={i} onPress={() => {this.updateConversation(button);}} style= ...

Guide to adding customized CSS and JavaScript to a specific CMS page on Magento

I'm trying to incorporate a lightbox for video playback on a specific page of my CMS. I've placed my CSS file in JS/MY THEME/JQUERY/PLUGIN/VENOBOX/CSS/myfile.css and the JS files in JS/MY THEME/jquery/plugins/venobox/js/myfile.js, but it doesn&ap ...

Unwanted bottom padding appears in Bootstrap 4 alerts outside of containers

Struggling to design a sleek fixed bootstrap 4 alert? The issue I'm facing is that the alert displays unwanted bottom padding when it's not placed inside a container. However, since it needs to be fixed and auto-centered, placing it within a con ...

What is the best way to conceal overflowing text with ellipsis by utilizing dynamic Bootstrap columns?

I'm having trouble aligning a text alongside an icon within a card. The card is enclosed in the Bootstrap "col" class, which dynamically adjusts its size based on the number of items in a row. When there isn't enough space, the text wraps and ap ...

Using padding and float properties in the a tag of HTML does not result in the expected behavior

I am attempting to display the menu in a left-to-right fashion, however I am encountering issues with using padding and float in HTML. Here is my current code: .main-nav ul li a { padding-right: 15px; float: left; } <div class="main-nav"> &l ...

How can I eliminate the border appearance from a textfield fieldset component in Material-UI?

I have been struggling to remove the border using CSS code I found on Stack Overflow, but unfortunately, the issue persists. If anyone could kindly assist me in fixing this problem, I would be extremely grateful. Can someone please advise me on the specif ...

Automatically expand the input field as text is typed

In my HTML code, users can enter comments for a specific question. If the comments are lengthy, I want the text box to automatically increase in height. Here is my current HTML code: <label class="label-reports">Comments</label> <input @( ...

What techniques can I use to maximize efficiency in my code by consolidating common styles across multiple cards?

I have included my css and html code below. I am trying to apply certain styles to all the cards, while changing only the color of the top border individually for each card. I am struggling to find a way to select multiple classes at the same time. My curr ...

I prefer to have the links activate when the mouse hovers over them, rather than when hovering over empty

Is there a way to prevent the bottom links (music, contact, archive) from being highlighted when the mouse hovers over the empty space between them and not just on the actual links themselves? I want the mouse to only react to the links it hovers over and ...

What is the Process of Rendering CSS/HTML in Web Browsers?

I have a simple question that I haven't been able to find an answer for despite my efforts on Google and Wikipedia. Perhaps I'm not wording it correctly. My query is regarding how the combination of CSS and HTML is displayed on-screen and in a b ...