1
votes

I need to center an object in a canvas based on its rotation. I can't figure out the maths.

enter image description here

What information do I have?

  • x, and y coordinates of the top left corner (see red circle of image)
  • width and height of the object
  • the rotation value in degrees

What have i tried so far?

// center horizontally 
if (curretElement === null) return;
curretElement.x((canvas.width() / 2) - ((curretElement.width() * curretElement.scaleX()) / 2));
canvas.draw();

// center vertically
curretElement.y((canvas.height() / 2) - ((curretElement.height() * curretElement.scaleY()) / 2));
canvas.draw();

This centers the image when it's not rotated.

currentElement is the selected object.

canvas is the room where the object should be centered in.

2
I assume the x,y coords of the top left corner is the info you want to calculate, as opposed to the info you have? In other words, the object's position anchor is the top left corner, regardless of the angle? - Chris G
Right, so to do this, you need to first calculate the vector from the object's center to its top-left corner. That's (-width * scale / 2, -height * scale / 2), as you already calculate. Add that to the canvas center, and you have the coordinates for angle = 0, again as you already do. For a different angle, all you need to do is rotate the vector before adding it to the canvas center. You can use a 2D rotation matrix for that. - Chris G
This looks like you are using FabricJs ... can you post a complete but minimal code snippet of your project - Helder Sepulveda
i am using konvajs - David

2 Answers

1
votes

You can calculate the coordinates this way:

  1. imagine that you have your object centered on the canvas
  2. calculate the coordinates of the top left corner relative to the center of the canvas
  3. rotate the object around the center of the canvas and calculate where the top left corner ends up relative to the center of the canvas
  4. translate the relative coordinates of the top left corner back to absolute coordinates

Here is a function that does the calculation:

function calculateXY(canvasWidth, canvasHeight, width, height, angle) {
    //calculate where the top left corner of the object would be relative to center of the canvas
    //if the object had no rotation and was centered
    const x = -width / 2;
    const y = -height / 2;

    //rotate relative x and y coordinates by angle degrees
    const sinA = Math.sin(angle * Math.PI / 180);
    const cosA = Math.cos(angle * Math.PI / 180);
    const xRotated = x * cosA - y * sinA;
    const yRotated = x * sinA + y * cosA;

    //translate relative coordinates back to absolute
    const canvasCenterX = canvasWidth / 2;
    const canvasCenterY = canvasHeight / 2;
    const finalX = xRotated + canvasCenterX;
    const finalY = yRotated + canvasCenterY;

    return { x: finalX, y: finalY };
}
0
votes

UPDATE :first try is really bad so i update code. which actually work and keep your left corner in center of container, just fill angle input

i want to comment and ask more but i can't and this thing(bounty) is tempting

Not heavy depend on java script. may be it what you need second attempt.

Corner is container and content in before. Rotate but it remains there. does it help? comment it.

    <!DOCTYPE html>
    <html lang="en">
    <body>
        <style>
        body{
          margin:0;
        }
        #container{
          display :flex;
          position: absolute;
          width:100%;
          height:100%;
        }
        #ram{
          display:flex;
          background-color:black;
          position:absolute;
          margin:auto;
          top:50%;
          right:50%;
        }
        #ram::before{
          content: "";
          position:absolute;
          height:40px;
          width:400px;
          background-color: #000;
        }
        </style>
        <input type="number" id="a" onchange = "forf()">
        <div id = "container">
        <div id = "ram">
        </div>
        </div>
        <script>
        function forf(){
          var a = document.getElementById("a").value;
        document.getElementById("ram").style.transform = "rotate(" + a + "deg)";
        }
        </script>
    </body>
    </html>