2023-03-22

Get DOM element exact position recursively including parent rotations and translations

Context

I'm trying to create a formula that allow me to get the exact position of a DOM element in the highest ancestor landmark. There are some specific rules in my probleme. Each element are absolute positionned and all element have a known top and left value in pixels. Each element can also have a rotation transform with a known value in degres. The rotation transform is also performed from the top left corner of the element.

To make it more understandable there is an exemple as an image just below.

enter image description here

In this exemple we have an arborescence composed of 3 elements. The element C is child of element B and element B is child of element A. To make it as simple as possible consider those 3 elements as simple <div> tag. Each of these elements have a known position and rotation angle in the parent landmark.

The probleme

I know the top and left value of each div element in its direct parent landmark. But i want to find the top left corner position of the element C in the general landmark representated as the landmark of the element A.

To achieve that i used homogenous transformation matrix. I calculate the general transform matrix of each element combining the translation and rotation matrix.

The rotation matrix of an element explained as :

enter image description here

With t the angle in radient of a given element in its parent landmark.

The translation matrix of an element explained as :

enter image description here

With top, left respectively the offset of the element from its parent origin top left corner.

Let's call Mr.x the rotation matrix of the element x.

Let's call Mt.x the translation matrix of the element x.

Let's call Mg.x the global transformation matrix of the element x. Obtained by doing Mr.x * Mt.x.

Let's call Cx.y the coordinates of the top left element x in the y element landmark.

The calcul

So i know Cc.b, Cb.a and Ca.g with g the general landmark. And i want Cc.g or the coordinates of the top left of element C in the general landmark.

So what i first did is accumulating all the transformation matrix of all parents elements starting with a 3 dimensions identity matrix. let's call this matrix Gtm for general transformation matrix.

The calcul is :

Gtm = Gtm * Mg.a

Gtm = Gtm * Mg.b

Then i create a "homogenous" point with the offset of the element C in the element B like below:

p = (6, 1.5, 0)

Then i multiply my point with the general transform matrix Gtm to get this point in the general landmark.

point = p * Gtm.

But that given point isn't correct and isn't integrating all the offsets of the parent correctly i don't get the correct coordinates and i don't know what i'm missing on here.

Sorry my Math and representations are approximatives. Ask me anything to get more informations if i'm not clear enough. And thank for any time spent on this.

Edit 1

Consider a Js object which a reference to a dom element and a reference to it's parent object.

let elA = {
  DOM_element = /* The <div> A */
  parent = null;
}
let elB = {
  DOM_element = /* The <div> B */
  parent = elA;
}
let elC = {
  DOM_element = /* The <div> C */
  parent = elB;
}

Consider that each of these objects have three methods respectively called getTranslationMatrix, getRotationMatrix, and getTransformMatrix, and that each of these objects have an attribute named rotation with a rotation value in degree

The code :

  /**
  * Get the translation matrix of the element 
  */
  getTranslationMatrix() {
    // Create the translation matrix of the element
    let translationMatrix = matrix([
      [1, 0, this.DOM_element.offsetLeft],
      [0, 1, this.DOM_element.offsetTop],
      [0, 0, 1],
    ]);

    return translationMatrix;
  }

  /**
  * Get the rotation matrix of the element 
  */
  getRotationMatrix() {
    // Create the rotation matrix of the element
    let rotationMatrix = matrix([
      [Math.cos(this.rotation * (Math.PI/180)), Math.sin(this.rotation * (Math.PI/180)), 0],
      [-Math.sin(this.rotation * (Math.PI/180)), Math.cos(this.rotation * (Math.PI/180)), 0],
      [0, 0, 1],
    ]);

    return rotationMatrix;
  }

  /**
  * Get the transform matrix of the element 
  */
  getTransformMatrix() {
    // Multiply all transform matrixes
    return multiply(this.getRotationMatrix(), this.getTranslationMatrix());
  }

matrix and multiply are fonctions provided by the mathjs library.

Now the code executed in the object elC :

// Get the reversed context stack
    let contextStack = [];
    let context = this.parent;
    while(context) {
      contextStack.unshift(context);
      context = context.parent;
    }

    // Create the transform matrix
    let transformMatrix = matrix([
      [1, 0, 0],
      [0, 1, 0],
      [0, 0, 1]
    ]);
    contextStack.forEach(context => {
      transformMatrix = multiply(context.getTransformMatrix(), transformMatrix);
    });

    // Create the origin point
    let origin = [
      this.DOM_element.offsetLeft,
      this.DOM_element.offsetTop,
      1
    ];

    // Apply the transform matrix
    origin = multiply(origin, transformMatrix);

And i should get the correct coordinates in the origin point but that is not the case.



No comments:

Post a Comment