Loading...
First, you need to clarify some concepts, such as bounding boxes, coordinates, anchor points, transform centers, etc. Understanding them helps to better use the specific API. Understanding them helps to better use the specific API.
In scene graph we learned that it is possible to construct parent-child relationships between graphs, and that such parent-child relationships can sometimes be counter-intuitive, for example adding a child node text (Text) to a line (Line).
line.appendChild(text);
But essentially this hierarchy just defines a parent-child relationship that is taken into account when computing the transformation. For example, we don't need to move the line and the text separately anymore, based on this parent-child relationship, we can just move the line and the text will follow it. During the transformation, the position of the text relative to the line remains unchanged, i.e., the coordinates of the text in the local coordinate system of the parent line remain unchanged.
To simplify the calculation, we need to wrap the figure in a regular geometry, usually using [axis-aligned bounding boxes](https://developer.mozilla.org/zh-CN/docs/Games/Techniques/3D_collision_detection#axis- aligned_bounding_boxes%EF%BC%88aabb%E5%8C%85%E5%9B%B4%E7%9B%92%EF%BC%89) (Axis Aligned Bounding Box), which is a non-rotating cube, and the following figure from
We use the following definitions.
interface AABB {center: [number, number, number]; // 中心坐标halfExtents: [number, number, number]; // 长宽高的一半min: [number, number, number]; // 左上角坐标max: [number, number, number]; // 右下角坐标}
AABB boxes have different meanings in different situations. Let's first look at what a wraparound box represents for a single figure. The figure below shows a circle with a radius of 100 and a border width of 20. For better illustration we have set the border to be translucent and it also has a shadow effect.
For the user, it is often desirable to use the geometric definition of the shape, e.g. the size of the circle is 100 * 100
, and we don't want the circle to be picked up even if the mouse slides over the shaded area.
And for rendering pipelines, these style properties obviously need to be taken into account, e.g.
It is easy to define geometric enclosing boxes based on different types of graphs.
Once a node has child nodes, it should be considered in the calculation of the enclosing box. For example, if we want to rotate it as a whole, we need to find the center of the enclosing box as the center of rotation. Therefore, the following enclosing boxes are considered for the hierarchy.
In the figure below, ul1 has two word nodes, li1 and li2, which are not considered in the calculation of its own Geometry Bounds, but are needed in the calculation of Bounds. Since ul1 also has shadows, its Render Bounds are one turn larger.
How should the anchor point (origin) of a graph be defined? We can define it based on Geometry Bounds, with the value range [0, 0] ~ [1, 1]
, where [0, 0]
represents the upper left corner of Geometry Bounds and [1, 1]
represents the lower right corner. And the default anchor points for different shapes due to different geometry definitions are as follows.
[0.5, 0.5]
[0, 0]
.[0, 0]
.Sometimes we want to change the definition of the origin of a base graph, for example by defining the anchor of Rect as the center instead of the top left corner, example:
rect.style.anchor = [0.5, 0.5];
Does that anchor point change affect the coordinates of the drawing in the local/world coordinate system? The answer is no. We just put the origin of the graph in these coordinates, and no matter how the definition of the origin is changed, the "location" coordinates remain unchanged.
rect.getPosition(); // [200, 200]rect.style.anchor = [0.5, 0.5];rect.getPosition(); // [200, 200]
When scaling or rotating a drawing, you need to specify a transformation center. For example, if you use scale(2)
as the center of a circle, you will get a completely different result than if you use the upper left corner of the Geometry Bounds of a circle as the center of the transformation. In a library like gl-matrix
, the RTS transformation matrix is usually obtained by specifying the transformation center.
mat4.fromRotationTranslationScaleOrigin();
In some scenarios, it is easier to use some literal or percentage definitions. CSS, for example, provides the transform-origin
property, which is defined exactly relative to Bounds. The image below is from: https://developer.mozilla.org/en-US/docs/Web/CSS/transform-origin.
When we want to achieve "rotation around the center", we only need to use literal amounts or percentages, so that we can avoid having to do Bounds fetching.
group.style.transformOrigin = 'center';group.style.transformOrigin = 'center center';group.style.transformOrigin = '50% 50%';