Rotate the child elements when the parent element is being rotated

I am trying to rotate the parent element along with all the child elements.

Few things to note:-

  • All the child elements are not appended in the parent element. However, their positions are in relative to parent element.
  • Their distances and angles should stay the same from the parent left and top position (x,y) while being rotated. So, if the parent element is rotated to +90° (clockwise), all the child elements should behave as if they were appended inside the parent element. i.e., they should get rotated to +90°. (see example below)

Initial Position

Initial Position

90° Rotated Position

Rotated to 90° clockwise

I have looked at other multiple questions and answers. They do describe this scenario but I’m not able to figure out what is the main issue in my code. This is the code I have.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Rotate and Move Elements</title>
    <style>
      body {
        margin: 0;
        height: 100vh;
        display: flex;
        justify-content: center;
        align-items: center;
        background-color: #f0f0f0;
      }

      #parentElement {
        position: absolute;
        width: 200px;
        height: 200px;
        background-color: #3498db;
        top: 231px;
        left: 960px;
      }

      .childElement {
        position: absolute;
        width: 20px;
        height: 20px;
        background-color: #e74c3c;
        transform-origin: center center;
      }
    </style>
  </head>
  <body>
    <div id="parentElement"></div>
    <div id="0" class="childElement" style="top: 200px; left: 900px"></div>
    <div id="1" class="childElement" style="top: 250px; left: 1000px"></div>
    <div id="2" class="childElement" style="top: 300px; left: 1050px"></div>
    <div id="3" class="childElement" style="top: 350px; left: 1100px"></div>

    <script>
      document.addEventListener("DOMContentLoaded", function () {
        const parentElement = document.getElementById("parentElement");
        const childElements = document.querySelectorAll(".childElement");

        let isDragging = false;
        let initialMouseAngle = 0;
        let initialRotation = 0;
        let initialDistance = {};

        function getMouseAngle(e) {
          const rect = parentElement.getBoundingClientRect();
          const centerX = rect.left + rect.width / 2;
          const centerY = rect.top + rect.height / 2;
          const mouseX = e.clientX - centerX;
          const mouseY = e.clientY - centerY;
          return Math.atan2(mouseY, mouseX) * (180 / Math.PI);
        }

        function getRotationDegrees() {
          const transformValue = window.getComputedStyle(parentElement).getPropertyValue("transform");
          const matrix = new DOMMatrixReadOnly(transformValue);
          return Math.atan2(matrix.b, matrix.a) * (180 / Math.PI);
        }

        function startDrag(e) {
          isDragging = true;
          initialMouseAngle = getMouseAngle(e);
          initialRotation = getRotationDegrees();
          childElements.forEach(child => {
            const parentRect = parentElement.getBoundingClientRect();
            const childRect = child.getBoundingClientRect();
            initialDistance[child.id] = Math.hypot(childRect.left - parentRect.left, childRect.top - parentRect.top);
          });
          console.log(initialDistance);
        }
        function handleDrag(e) {
          if (isDragging) {
            const currentMouseAngle = getMouseAngle(e);
            const rotationChange = currentMouseAngle - initialMouseAngle;
            const newRotation = initialRotation + rotationChange;
            const parentRect = parentElement.getBoundingClientRect();
            const angleInRadians = newRotation * (Math.PI / 180);
            parentElement.style.transform = `rotate(${newRotation}deg)`;

            childElements.forEach(child => {
              const distance = initialDistance[child.id];
              const newX = parentRect.left + distance * Math.cos(angleInRadians);
              const newY = parentRect.top + distance * Math.sin(angleInRadians);
              console.log(newX + newY);
              child.style.left = `${newX}px`;
              child.style.top = `${newY}px`;
              child.style.transform = `rotate(${newRotation}deg)`;

              // console.log("newX", newX, "newY", newY, distance);
            });
          }
        }

        function stopDrag() {
          isDragging = false;
        }

        document.addEventListener("mousedown", startDrag);
        document.addEventListener("mouseup", stopDrag);
        document.addEventListener("mousemove", handleDrag);
      });
    </script>
  </body>
</html>