I thought I had pretty decent understanding of SVG, including the viewport, viewBox and the user coordinate system.
In the first example below, we use a viewBox with the same aspect ratio as the viewport. As expected, the user coordinate system rotation does not distort any angles.
In example two, we set the viewbox to a different aspect ratio, compared to the viewport. In other words, when mapping the viewBox to the viewport, the shapes' aspect ratios are not maintained. The bottom-right angle is not distorted from this scaling, which makes sense since the coordinate system origin is at (0,0).
When we rotate the user coordinate system in example two, however, the bottom right angle is distorted. This does not happen in example one.
Edit 1: Just to be clear, the issue is with regards to the bottom right angle in the last example. Before rotating, but after stretching with viewBox, the angle is 90%. After rotating however, it is no longer 90%.
Why does a non-uniformly scaled triangle loose its angles when rotating?
Example One (uniform scale)
body {
height: 500px;
}
svg {
width: 400px;
height: 400px;
border: 1px solid red;
}
<svg id="s1" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 200 200" preserveAspectRatio="none">
<style>
polygon {
transform: translate(100px, 0px);
animation: 2s ease-in 1s 1 normal forwards rotate-down;
fill: green;
}
@keyframes rotate-down {
0% {
transform: translate(100px, 0px) rotate(0deg);
}
100% {
transform: translate(100px, 0px) rotate(45deg);
}
}
</style>
<polygon points="100,100 100,0 0,100" />
</svg>
Example Two (non-uniform scale)
body {
height: 500px;
}
svg {
width: 600px;
height: 400px;
border: 1px solid red;
}
<svg id="s1" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 200 400" preserveAspectRatio="none">
<style>
polygon {
transform: translate(100px, 0px);
animation: 2s ease-in 1s 1 normal forwards rotate-down;
fill: green;
}
@keyframes rotate-down {
0% {
transform: translate(100px, 0px) rotate(0deg);
}
100% {
transform: translate(100px, 0px) rotate(45deg);
}
}
</style>
<polygon points="100,100 100,0 0,100" />
</svg>
EDIT 2 (images to clarify):
Below we see the triangle after viewBox has been added (thus scaled and translated), but before rotating. The bottom right angle is 90 degrees.
Below we see the triangle after viewBox has been added (thus scaled and translated), and after rotating. The bottom right angle is no longer 90 degrees.
EDIT 3:
I eventually got to the bottom of this.
Below is an answer explaining the details and linking to relevant resources.