Front end · deeply understand the calculation principle of transform function

When it comes to front-end graphics, it can hardly be avoided   transform   Property. ...
① transform: matrix(a, b, c, d, e, f)
② transform: translate(x)
③ transform: translate(x, y)
④ transform: scale(s)
⑤ transform: scale(sx, sy)
⑥ transform: rotate(a)
⑦ transform: rotate(a, x, y)
⑧ transform: skewX(a)
⑨ transform: skewY(a)

When it comes to front-end graphics, it can hardly be avoided   transform   Property.

and   transform   There are five built-in functions in different categories (matrix deformation, translation, scaling, rotation and tilt, and there are nine specific details). Developers are often confused by the combination and transformation of different functions.

When facing the demand for accurate positioning, if   transform   If you don't understand the calculation principle thoroughly, it will lead to lengthy code, increased complexity and rapid decline in readability.

In fact, in the front end   transform   There are many kinds, such as   CSS and   In SVG   transform   Properties are slightly different. However, all changes are inseparable from their religion, and their underlying mathematical principles are generally consistent.

Therefore, for the convenience of description, this article uses   Mainly SVG transform.

First, it can be avoided   There are a lot of different unit conversions in CSS, and many details unrelated to the principle are arranged;
Second, as a vector format   SVG is concise enough to describe the mathematical calculation method, and vectorization parameters have inherent advantages;

① transform: matrix(a, b, c, d, e, f)

When it comes to graphics, it must involve matrix operation.

matrix   Function can be said to be the most original existence. If you imagine the front-end page as a canvas, matrix   Is the reformer of this canvas. You only need to set different parameters   matrix   Transform the graphics at will.

At the same time, matrix   Function is also the core of the other four types of function functions. These four types are translation, scaling, rotation and tilt, and their implementation methods can be used   matrix   Equivalent substitution.

matrix   The argument to the function is a   3x3   The length of the explicit parameter list in the function declaration is   6.

The matrix form is as follows (assuming   M):

$$ M = \begin a & c & e \\ b & d & f \\ 0 & 0 & 1 \\ \end $$

How?
The answer is: matrix multiplication

Suppose there is a point on the page   point_old   The coordinates of are   (oldX, oldY), new point after conversion   point_new   Coordinates are   (newX, newY).

During the operation, the matrix description of points is as follows:

$$ point_ = \begin oldX \\ oldY \\ 1 \end \\ point_ = \begin newX \\ newY \\ 1 \end $$

The calculation method is:

$$ point_ = M * point_ $$

$$ \begin newX \\ newY \\ 1 \\ \end = \begin a & c & e \\ b & d & f \\ 0 & 0 & 1 \\ \end \begin oldX \\ oldY \\ 1 \\ \end = \begin a*oldX+c*oldY+e \\ b*oldX+d*oldY+f \\ 1 \\ \end $$

So:

$$ point_ \begin newX = a*oldX + c*oldY + e \\ newY = b*oldX + d*oldY + f \\ \end $$

Among the six parameters, e and f   Mainly responsible for offset, others   a,b,c,d   Represents different magnification.

Now we know that different effects can be achieved by controlling these six parameters.

For example, in the default state, matrix(1, 0, 0, 1, 0, 0)   It means nothing, because applying the above calculation formula,

$$ \begin newX \\ newY \\ 1 \\ \end = \begin 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \\ \end \begin oldX \\ oldY \\ 1 \\ \end = \begin 1*oldX+0*oldY+0 \\ 0*oldX+1*oldY+0 \\ 1 \\ \end = \begin oldX \\ oldY \\ 1 \\ \end $$

As a result, it can be found that there is no transformation of point coordinates.

Here, transform   Core function of   matrix()   It should be clear how it is calculated.

Then let's see how all the other functions are implemented and implemented   matrix   Converted.

<h1>default</h1> <svg x="0px" y="0px" width="600px" height="300px"> <line label="axisX" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="600" y2="0" /> <line label="axisY" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="0" y2="300" /> <rect x="0" y="0" width="200" height="100" fill="red" opacity="0.9"></rect> </svg>

② transform: translate(x)

translate   It is a translation function. When there is only one parameter, it indicates how far the graph has moved horizontally.
Namely:

$$ newX = x + oldX $$

So it's very simple to construct a matrix   matrix(1, 0, 0, 1, x, 0)   Can be achieved   translate(x)   Effect of:

$$ \begin newX \\ newY \\ 1 \\ \end = \begin 1 & 0 & x \\ 0 & 1 & 0 \\ 0 & 0 & 1 \\ \end \begin oldX \\ oldY \\ 1 \\ \end = \begin 1*oldX+0*oldY+x \\ 0*oldX+1*oldY+0 \\ 1 \\ \end = \begin x + oldX\\ oldY \\ 1 \\ \end $$

<div> <h1>transform: translate(x)</h1> <svg x="0px" y="0px" width="600px" height="300px"> <line label="axisX" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="600" y2="0" /> <line label="axisY" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="0" y2="300" /> <rect x="0" y="0" width="200" height="100" fill="red" opacity="0.9" transform="translate(100)"></rect> </svg> <h1>transform: matrix(1, 0, 0, 1, x, 0)</h1> <svg x="0px" y="0px" width="600px" height="300px"> <line label="axisX" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="600" y2="0" /> <line label="axisY" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="0" y2="300" /> <rect x="0" y="0" width="200" height="100" fill="red" opacity="0.9" transform="matrix(1,0,0,1,100,0)"></rect> </svg> </div>

③ transform: translate(x, y)

It can be regarded as a single parameter   Overloaded function of translate function, second parameter   y   Value representing y in a two-dimensional plane in Cartesian coordinates   Translational motion in the axis direction.

Namely:

$$ \begin newX = x + oldX \\ newY = y + oldY \end $$

Similarly, a matrix can be constructed   matrix(1, 0, 0, 1, x, y)   realization   translate(x, y)   Effect of:

$$ \begin newX \\ newY \\ 1 \\ \end = \begin 1 & 0 & x \\ 0 & 1 & y \\ 0 & 0 & 1 \\ \end \begin oldX \\ oldY \\ 1 \\ \end = \begin 1*oldX+0*oldY+x \\ 0*oldX+1*oldY+y \\ 1 \\ \end = \begin x + oldX \\ y + oldY \\ 1 \\ \end $$

<div> <h1>transform: translate(x, y)</h1> <svg x="0px" y="0px" width="600px" height="300px"> <line label="axisX" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="600" y2="0" /> <line label="axisY" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="0" y2="300" /> <rect x="0" y="0" width="200" height="100" fill="red" opacity="0.9" transform="translate(100,50)"></rect> </svg> <h1>transform: matrix(1, 0, 0, 1, x, y)</h1> <svg x="0px" y="0px" width="600px" height="300px"> <line label="axisX" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="600" y2="0" /> <line label="axisY" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="0" y2="300" /> <rect x="0" y="0" width="200" height="100" fill="red" opacity="0.9" transform="matrix(1,0,0,1,100,50)"></rect> </svg> </div>

④ transform: scale(s)

scale   It is a scaling function. When there is only one parameter, it indicates that the graph is on the horizontal and vertical axes to achieve equal scale magnification and reduction.

Namely:

$$ \begin newX = s*oldX \\ newY = s*oldY \end $$

Since this is proportional amplification, the transformation matrix can be obtained   matrix(s, 0, 0, s, 0, 0):

$$ \begin newX \\ newY \\ 1 \\ \end= \begin s & 0 & 0 \\ 0 & s & 0 \\ 0 & 0 & 1 \\ \end \begin oldX \\ oldY \\ 1 \\ \end= \begin s*oldX+0*oldY+0 \\ 0*oldX+s*oldY+0 \\ 1 \\ \end = \begin s*oldX \\ s*oldY \\ 1 \\ \end $$

<div> <h1>transform: scale(s)</h1> <svg x="0px" y="0px" width="600px" height="300px"> <line label="axisX" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="600" y2="0" /> <line label="axisY" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="0" y2="300" /> <rect x="0" y="0" width="200" height="100" fill="red" opacity="0.9" transform="scale(2)"></rect> </svg> <h1>transform: matrix(s, 0, 0, s, 0, 0)</h1> <svg x="0px" y="0px" width="600px" height="300px"> <line label="axisX" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="600" y2="0" /> <line label="axisY" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="0" y2="300" /> <rect x="0" y="0" width="200" height="100" fill="red" opacity="0.9" transform="matrix(2,0,0,2,0,0)"> </rect> </svg> </div>

⑤ transform: scale(sx, sy)

Here, similarly, it is also an overloaded function with two parameters, so that the scaling magnification of different axes can be controlled separately.

Namely:

$$ \begin newX = sx*oldX \\ newY = sy*oldY \end $$

Similarly, the transformation matrix can be obtained   matrix(sx, 0, 0, sy, 0, 0):

$$ \begin newX \\ newY \\ 1 \\ \end= \begin sx & 0 & 0 \\ 0 & sy & 0 \\ 0 & 0 & 1 \\ \end \begin oldX \\ oldY \\ 1 \\ \end = \begin sx*oldX+0*oldY+0 \\ 0*oldX+sy*oldY+0 \\ 1 \\ \end = \begin sx*oldX \\ sy*oldY \\ 1 \\ \end $$

<div> <h1>transform: scale(sx, sy)</h1> <svg x="0px" y="0px" width="600px" height="300px"> <line label="axisX" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="600" y2="0" /> <line label="axisY" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="0" y2="300" /> <rect x="0" y="0" width="200" height="100" fill="red" opacity="0.9" transform="scale(0.5,2)"></rect> </svg> <h1>transform: matrix(sx, 0, 0, sy, 0, 0)</h1> <svg x="0px" y="0px" width="600px" height="300px"> <line label="axisX" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="600" y2="0" /> <line label="axisY" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="0" y2="300" /> <rect x="0" y="0" width="200" height="100" fill="red" opacity="0.9" transform="matrix(0.5,0,0,2,0,0)"></rect> </svg> </div>

⑥ transform: rotate(a)

rotate   Is a rotation function, when the number of parameters is   one   When, it indicates that the origin of the current element coordinate system is the rotation point and the rotation angle is   a   Degrees.

It should be noted in advance that the unit here is   deg, angle system.

And then converted into   matrix   Trigonometric functions are needed in the process of.

Therefore, in terms of numerical value, it is necessary to convert the angle system into radian system:

$$ a'=\frac{\pi}*a $$

In addition, under the two-dimensional plane rotation motion, the distance from any point to the center of the rotation circle remains unchanged. Therefore, for the convenience of calculation, we use the polar coordinate system to deduce the motion mode of the object in the Cartesian coordinate system.

According to the polar coordinate system, we use ordinal pairs   ( ρ, θ)   Represents any point   P   Coordinates of, ρ  Represents the polar diameter, θ**  Represents the polar angle (radian system).

Record as   P( ρ, θ)

So, any point rotates   a   Angle (a '   The coordinate after radian) is: P( ρ, θ + a')**

Using the mapping relationship between coordinate systems:

$$ \begin X = \rho*cos(\theta) \\ Y = \rho*sin(\theta) \\ \end $$

Available:

$$ newP = oldP(\rho,\theta + a') $$

$$ \begin newX = \rho*cos(\theta+a') \\ newY = \rho*sin(\theta+a') \\ \end $$

Further expansion can be obtained:

$$ \begin newX &= \rho*cos(\theta+a') \\ &= \rho*cos(\theta)*cos(a')-\rho*sin(\theta)*sin(a') \\ &= oldX*cos(a')-oldY*sin(a') \\ &= cos(a')*oldX + (-1)*sin(a')*oldY \\ \end $$

$$ \begin newY & = \rho*sin(\theta+a') \\ & = \rho*sin(\theta)*cos(a')+\rho*cos(\theta)*sin(a') \\ & = oldY * cos(a') + oldX * sin(a') \\ & = sin(a') * oldX + cos(a') * oldY \end $$

According to the above formula, it can be deduced that the transformation matrix is   matrix(cos(a'), sin(a'), -sin(a'), cos(a'), 0, 0)

$$ \begin \begin newX \\ newY \\ 1 \\ \end & = \begin cos(a') & -sin(a') & 0 \\ sin(a') & cos(a') & 0 \\ 0 & 0 & 1 \\ \end \begin oldX \\ oldY \\ 1 \\ \end \\ & = \begin cos(a')*oldX-sin(a')*oldY+0 \\ sin(a')*oldX+cos(a')*oldY+0 \\ 1 \\ \end \\ & = \begin \rho*cos(a')*cos(\theta)-\rho*sin(a')*sin(\theta) \\ \rho*sin(a')*cos(\theta)+\rho*cos(a')*sin(\theta) \\ 1 \\\end \\ & = \begin \rho*cos(\theta + a') \\ \rho*sin(\theta + a') \\ 1 \\ \end \end $$

<div> <h1>transform: rotate(a)</h1> <svg x="0px" y="0px" width="600px" height="300px"> <line label="axisX" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="600" y2="0" /> <line label="axisY" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="0" y2="300" /> <rect x="0" y="0" width="200" height="100" fill="red" opacity="0.9" transform="rotate(30)"></rect> </svg> <h1>transform: matrix(cos(a'), sin(a'), -sin(a'), cos(a'), 0, 0)</h1> <svg x="0px" y="0px" width="600px" height="300px"> <line label="axisX" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="600" y2="0" /> <line label="axisY" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="0" y2="300" /> <rect x="0" y="0" width="200" height="100" fill="red" opacity="0.9" transform="matrix(0.866025,0.5,-0.5,0.866025,0,0)"></rect> </svg> </div>

⑦ transform: rotate(a, x, y)

When   rotate   The situation is a little more complicated when the function is specified with a rotation point.

Since the function essentially controls the canvas itself, it can also be understood as the coordinate system itself.

Therefore, if you want a figure in the coordinate system to rotate around a specific point, you need the following three steps:

First, move the rotation point from the origin of the coordinate system to the specified point;
Second, the specified point defaults to the origin of the coordinate system and starts rotation;
Third, in order to keep other patterns unchanged during rotation, move the origin of the coordinate system from the specified point back to the initial point.

Therefore, the rotation of the specified point is usually adopted   < translate(x, y)><rotate(a)><translate(-x, -y)>   The way.

translate   Parameters in   x,y   mean   rotate(a, x, y)   Coordinates of the specified point in the.

In this case, how should we use it   matrix   What about the description?

We assume that the above three transformation matrices are:

$$ \begin translate(x,y)= T_1 = \begin 1 & 0 & x \\ 0 & 1 & y \\ 0 & 0 & 1 \\ \end \\ rotate(a) = R = \begin cos(a') & -sin(a') & 0 \\ sin(a') & cos(a') & 0 \\ 0 & 0 & 1 \\ \end \\ translate(-x,-y)=T_2= \begin 1 & 0 & -x \\ 0 & 1 & -y \\ 0 & 0 & 1 \\ \end \end $$

Then, according to the function execution method, the matrix calculation method is:

$$ \begin newX \\ newY \\ 1 \\ \end = T_1 * R * T_2 * \begin oldX \\ oldY \\ 1 \\ \end $$

Namely:

$$ \begin M & = T_1 * R * T_2 \\ & = \begin 1 & 0 & x \\ 0 & 1 & y \\ 0 & 0 & 1 \\ \end \begin cos(a') & -sin(a') & 0 \\ sin(a') & cos(a') & 0 \\ 0 & 0 & 1 \\ \end \begin 1 & 0 & -x \\ 0 & 1 & -y \\ 0 & 0 & 1 \\ \end \\ &= \begin cos(a') & -sin(a') & x \\ sin(a') & cos(a') & y \\ 0 & 0 & 1 \\ \end \begin 1 & 0 & -x \\ 0 & 1 & -y \\ 0 & 0 & 1 \\ \end \\ &= \begin cos(a') & -sin(a') & -x*cos(a')+y*sin(a')+x \\ sin(a') & cos(a') & -x*sin(a')-y*cos(a')+y \\ 0 & 0 & 1 \end \end $$

That is, the transformation matrix is:
matrix(cos(a'), sin(a'), -sin(a'), cos(a'), -xcos(a')+ysin(a')+x, -xsin(a')-ycos(a')+y)

$$ \begin newX \\ newY \\ 1 \end = \begin cos(a') & -sin(a') & -x*cos(a')+y*sin(a')+x \\ sin(a') & cos(a') & -x*sin(a')-y*cos(a')+y \\ 0 & 0 & 1 \end \begin oldX \\ oldY \\ 1 \\ \end $$

<div> <h1>transform: rotate(a, x, y)</h1> <svg x="0px" y="0px" width="600px" height="300px"> <line label="axisX" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="600" y2="0" /> <line label="axisY" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="0" y2="300" /> <rect x="0" y="0" width="200" height="100" fill="red" opacity="0.9" transform="rotate(30,0,100)"></rect> </svg> <h1>transform: matrix(cos(a'), sin(a'), -sin(a'), cos(a'), -x*cos(a')+y*sin(a')+x, -x*sin(a')-y*cos(a')+y)</h1> <svg x="0px" y="0px" width="600px" height="300px"> <line label="axisX" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="600" y2="0" /> <line label="axisY" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="0" y2="300" /> <rect x="0" y="0" width="200" height="100" fill="red" opacity="0.9" transform="matrix(0.866025, 0.5, -0.5, 0.866025, 50.0, 13.39746)"></rect> </svg> </div>

⑧ transform: skewX(a)

skewX means   x   For the inclination in the axis direction, the trigonometric function will also be used here. Similarly, there is the following in radian system:

$$ a'=\frac{\pi}*a $$

Because tilting only occurs in   x   Axial direction, from which:

$$ \begin newX = \Delta x + oldX = tan(a')*oldY + oldX\\ newY = oldY \end $$

Therefore, the transformation function is   matrix(1, 0, tan(a'), 1, 0, 0)

$$ \begin \begin newX \\ newY \\ 1 \\ \end & = \begin 1 & tan(a') & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \\ \end \begin oldX \\ oldY \\ 1 \\ \end \\ & = \begin 1*oldX+tan(a')*oldY+0 \\ 0*oldX+1*oldY+0 \\ 1 \\ \end\\ &= \begin tan(a')*oldY + oldX\\ oldY \\ 1 \\ \end \end $$

<div> <h1>transform: skewX(a)</h1> <svg x="0px" y="0px" width="600px" height="300px"> <line label="axisX" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="600" y2="0" /> <line label="axisY" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="0" y2="300" /> <rect x="0" y="0" width="200" height="100" fill="red" opacity="0.9" transform="skewX(30)"></rect> </svg> <h1>transform: matrix(1, 0, tan(a'), 1, 0, 0)</h1> <svg x="0px" y="0px" width="600px" height="300px"> <line label="axisX" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="600" y2="0" /> <line label="axisY" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="0" y2="300" /> <rect x="0" y="0" width="200" height="100" fill="red" opacity="0.9" transform="matrix(1,0,0.577350,1,0,0)"></rect> </svg> </div>

⑨ transform: skewY(a)

skewY indicates the inclination in the y-axis direction. The principle is the same as above:

$$ \begin newX = oldX \\ newY = \Delta y + oldY = tan(a')*oldX + oldY \\ \end $$

The transformation function matrix(1, tan(a'), 0, 1, 0, 0) can be obtained

$$ \begin \begin newX \\ newY \\ 1 \\ \end & = \begin 1 & 0 & 0 \\ tan(a') & 1 & 0 \\ 0 & 0 & 1 \\ \end \begin oldX \\ oldY \\ 1 \\ \end \\ & = \begin 1*oldX + 0*oldY + 0 \\ tan(a')*oldX+1*oldY + 0 \\ 1 \\ \end\\ &= \begin oldX\\ tan(a')*oldX+oldY \\ 1 \\ \end \end $$

<div> <h1>transform: skewY(a)</h1> <svg x="0px" y="0px" width="600px" height="300px"> <line label="axisX" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="600" y2="0" /> <line label="axisY" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="0" y2="300" /> <rect x="0" y="0" width="200" height="100" fill="red" opacity="0.9" transform="skewY(30)"></rect> </svg> <h1>transform: matrix(1, tan(a'), 0, 1, 0, 0)</h1> <svg x="0px" y="0px" width="600px" height="300px"> <line label="axisX" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="600" y2="0" /> <line label="axisY" fill="none" stroke="black" stroke-width="10" x1="0" y1="0" x2="0" y2="300" /> <rect x="0" y="0" width="200" height="100" fill="red" opacity="0.9" transform="matrix(1,0.577350,0,1,0,0)"></rect> </svg> </div>

To sum up, it is   transform   The calculation of all functions.

Or it can also be regarded as its matrix operation description.

Of course, the code may be optimized to reduce unnecessary matrix operation, but it is very useful to understand its operation principle and understand the underlying calculation logic.

[this article is original, welcome to forward, no handling]

16 November 2021, 02:39 | Views: 8332

Add new comment

For adding a comment, please log in
or create account

0 comments