skew() function in depth

别来无恙 提交于 2020-07-30 02:44:25

问题


I really need to understand how skew(xdeg) function works all research does not seem to explain how the x angle affecting the other points and distorts it like that, I need to know if there any mathematical formula it or a way to be able to expect the result of using a specific degree.

ps. I already read tons of docs which the best one of them was the DevDocs which say

This transformation is a shear mapping (transvection) that distorts each point within an element by a certain angle in the horizontal and vertical directions. The coordinates of each point are modified by a value proportionate to the specified angle and the distance to the origin; thus, the farther from the origin a point is, the greater will be the value added it.

but there is no further explanation for how the given angle will affect those points in an element.

In SVG book it explains skew by saying it pushes a horizontal or a vertical line by specific value but I don't get how deg value is translated to offset one


回答1:


The mathematical operation that is applied on the <angle> is simply tan(<angle>). It is then inserted in the transformation Matrix.

Ok, that doesn't really goes in depth about skew, nor why it makes sense to use angle rather than a numeric factor. So let's take the following ASCII example showing an x only skew.

   skewX(0)            skewX(45deg)
_|         |_         _|         |_ => original box markers
  a o o o o         a o o o o    
  b o o o o           b o o o o
  c o x o o             c o x o o   <-- this line didn't move
  d o o o o               d o o o o
  e o o o z                 e o o o z
 |         |           |         |

So if we apply the tan(45deg) it gives us a skewX factor of 1.
This means that all the horizontal lines will get displaced by 1 * their distance to the transformation origin.

In above example the transformation origin is the center (x) of the 5*5 image.
So the first pixel line (a o o o o) being at a distance of minus two pixels from the origin, it will get translated by 2px on the left.
The last line (e o o o z) being at +2px from the origin, it will get translated by 2px on the right.
The middle line (c o x o o) being on the origin will not be affected by this transform.

Alright, but that still doesn't explain why bother with angles rather than a factor...

Well the angle notation makes sense too, since we could also explain our example as we rotated every column by 45deg using their center point as anchor.

And even if it is just speculations from my part, angles have the added benefit to allow a skewN(90deg) state which couldn't be represented by a numeric factor.




回答2:


To understand how skew works let's compare it with another transformation that uses angle.

Here is an example with rotation, we make the transform origin to be top left and from there we rotate by 45deg:

.box {
  margin:50px;
  width:200px;
  height:200px;
  background:blue;
}
.box > div {
  height:100%;
  width:100%;
  background:rgba(255,0,0,0.5);
  transform-origin:top left;
  transform:rotate(45deg);
}
<div class="box">
  <div></div>
</div>

For this example, it's somehow trivial to find the angle and how it works:

Now let's take the same example and reduce the height of the rotated element to a small value:

.box {
  margin:50px;
  width:200px;
  height:200px;
  background:blue;
}
.box > div {
  height:3px;
  width:100%;
  background:red;
  transform-origin:top left;
  transform:rotate(45deg);
}
<div class="box">
  <div></div>
</div>

It's like we have a rotated line. Now let's replace rotate with skew:

.box {
  margin:50px;
  width:200px;
  height:200px;
  background:blue;
}
.box > div {
  height:3px;
  width:100%;
  background:red;
  transform-origin:top left;
  transform:skewY(45deg);
}
<div class="box">
  <div></div>
</div>

If we compare both result we will notice that we have somehow a rotation in both cases BUT a different size when it comes to skew transformation:

It's more clear now how skew works with angle. The transform is a kind of distortion that rely on an angle to define this distortion. Here is a better illustration:

The blue is our initial element, the cross is the transform origin and the yellow is the angle. If we do a rotation we will obtain the red line where the width remain the same. If we do a skew we will obtain the orange line where the width will change and considering the illustration it will be equal to W / cos(angle) Where W is our initial width (in our previous case cos(45deg) = 1 / sqrt(2) so we will have W * sqrt(2)).


Now what about our intial square, how it will behave with skew?

.box {
  margin:50px;
  width:200px;
  height:200px;
  background:blue;
}
.box > div {
  height:100%;
  width:100%;
  background:red;
  transform-origin:top left;
  transform:skewY(45deg);
}
<div class="box">
  <div></div>
</div>

It will behave exactly like we described previously line by line. We will also have the same result if we apply skew in the other direction:

.box {
  margin:50px;
  width:200px;
  height:200px;
  background:blue;
}
.box > div {
  height:100%;
  width:100%;
  background:red;
  transform-origin:top left;
  transform:skewX(45deg);
}
<div class="box">
  <div></div>
</div>

The same logic is applied but to vertical lines and considering the height. As a side note, skewX(V) is the same as skew(V)ref.

Now if we apply skew in both direction:

.box {
  margin:50px;
  width:200px;
  height:200px;
  background:blue;
}
.box > div {
  height:100%;
  width:100%;
  background:red;
  transform-origin:top left;
  transform:skew(45deg,10deg);
}
<div class="box">
  <div></div>
</div>

It's like we first apply skewX to distort the vertical lines then we apply skewY to the new shape to distort the horizontal lines (or the opposite). Here is an animation to illustrate the magic result of skew(45deg,45deg):

.box {
  margin:50px;
  width:200px;
  height:200px;
  background:blue;
}
.box > div {
  height:100%;
  width:100%;
  background:red;
  transform-origin:top left;
  transform:skew(45deg,10deg);
  animation:change 5s infinite alternate linear;
}
@keyframes change {
  from {
    transform:skew(0deg,0deg);
  }
  50% {
    transform:skew(45deg,0deg);
  }
  to {
    transform:skew(45deg,45deg);
  }
}
<div class="box">
  <div></div>
</div>

And what about origin? Nothing will change for the transformation, only the reference will change. In other words, the fixed point will move:

.box {
  margin:50px;
  width:200px;
  height:200px;
  background:blue;
}
.box > div {
  height:100%;
  width:100%;
  background:red;
  transform-origin:center;
  transform:skew(45deg,10deg);
  animation:change 5s infinite alternate linear;
}
@keyframes change {
  from {
    transform:skew(0deg,0deg);
  }
  50% {
    transform:skew(45deg,0deg);
  }
  to {
    transform:skew(45deg,45deg);
  }
}
<div class="box">
  <div></div>
</div>

We may also notice that if we do skew in one direction only one parameter of transform-origin will be considered.

So for skewX, transform-origin: X Y will be the same whataver the value of X is. This somehow explain the line by line transformation as when we have on line we have one dimension.

.box {
  margin:50px;
  width:200px;
  height:200px;
  background:blue;
}
.box > div {
  height:100%;
  width:100%;
  background:red;
  transform:skewX(45deg);
  animation:change 5s infinite alternate linear;
}
@keyframes change {
  from {
    transform-origin:0 0;
  }
  50% {
    transform-origin:100% 0;/*nothing will happen between 0 and 50%*/
  }
  to {
    transform-origin:100% 100%;
  }
}
<div class="box">
  <div></div>
</div>

More in depth

Now let's consider the matrix calculation to understand how it's used and how tan(angle) is also used.

If we refer to the documentation we have:

This matrix is used to define the coordinates of the transformed element based on the coordinate of the initial element point by point. Considering this definition we will have these equations

Xf = Xi + Yi * tan(ax)
Yf = Xi * tan(ay) + Yi

If we consider skewY only it's clear that ax will be 0 thus tan(0) will be 0 and X won't change which is the case with our first example where we only had distortion in the Y axis (same logic if we apply only skewY).

Now, why we have Yf = Xi * tan(ay) + Yi?

Let's re-take the previous illustration:

The green point is the initial point defined by Xi,Yi and the red point is the tranformed one defined by Xf,Yf. It's trivial that Xf=Xi and the distance between the two points will be Yf-Yi.

Considering the illustration we can clearly say that tan(ay) = (Yf-Yi)/Xi = (Yf-Yi)/Xf thus we will have:

Xf = Xi 
Yf = Xi * tan(ay) + Yi

We apply the same logic if we have skew in the other direction.



来源:https://stackoverflow.com/questions/52088000/skew-function-in-depth

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!