Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

369
Visualizações
How to prevent a rotated rectangle from moving when adjusting its width?

I have a rectangle rotated around its center, and I'm trying to make it wider. However, because it's rotated around its center, making it wider also visually "moves" the rectangle.

What I'm looking for is a way to make it wider and then adjust its x and y components accordingly in order to make it visually not move. I have created a reproduction of the problem here, so you can see the issue:

const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");

function rotateCanvas(x, y, a) {
  ctx.translate(x, y);
  ctx.rotate(a);
  ctx.translate(-x, -y);
}

function drawRotateRectangle(x, y, w, h, a) {
  rotateCanvas(x + w / 2, y + h / 2, a);
  ctx.fillRect(x, y, w, h);
  rotateCanvas(x + w / 2, y + h / 2, -a);
}

let which = true;

function render() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  const rWidth = which ? 100 : 200;

  drawRotateRectangle(30, 30, rWidth, 30, 0.5);

  which = !which;
}

render();

setInterval(render, 1000);
<canvas></canvas>

As you can see, when it gets wider, it also moves upwards. Effectively, I want the top left of the rectangle to be at the same point before and after the resize occurs.

However, I also want it to still be rotated around its center. That is, I am looking for how much I have to move the rectangle (change its x and y coordinates), to effectively anchor it to the same location, before and after the resize occurs.

Is this possible? If so, how would you calculate the value you have to modify the x and the y of the rectangle by in order to visually keep it locked to its current position?

I recognize this issue would not occur if I instead rotated the rectangle around its top left as opposed to its center, but for the purposes of my application, the rectangle has to be rotated around its center, so I am instead looking for how much I have to modify its x and y components in order to maintain its visual position.

As such, the answer to this question should not involve modifying the rotateCanvas or drawRotateRectangle functions in any way.

An example of the effect I'm looking for: enter image description here

about 4 years ago · Juan Pablo Isaza
2 Respostas
Responde à pergunta

0

To move along a rotated axis. The rotation as 'r' and the distance as 'd'. Assumes that the transform is uniform (ie the x, y scale are the same on this case 1 and there is no skew)

Example to move dx along x axis and dy along y axis

var r = ?; // rotation in radians
var x = ?, y = ?;  // in pixels. coordinate to move
var dx = ?; // distance in pixels along x axis
var dy = ?; // distance in pixels along y axis

const ax = Math.cos(r);
const ay = Math.sin(r);
x += dx * ax - dy * ay
y += dx * ay + dy * ax;

Demo

Expanding a rectangle. The function rect.expand(left, right, top, bottom) changes the size of rectangle adjusting the origin to keep unchanged edges where the are.

const ctx = canvas.getContext("2d");
requestAnimationFrame(renderLoop);
const W = canvas.width, H = canvas.height;
var expanding = 1, expandCount = 0; 
const rect = {
    x: W / 2, 
    y: H / 2,
    r: 0,  
    w: 100,
    h: 50,
    expand(left, right, top, bottom) {
        const ax = Math.cos(this.r) * 0.5;
        const ay = Math.sin(this.r) * 0.5;
        this.w += left + right;
        this.h += top + bottom;
        this.x += -left * ax + right * ax + top * ay - bottom * ay;
        this.y += -left * ay + right * ay - top * ax + bottom * ax;
    },
    draw() {
        const ax = Math.cos(this.r);
        const ay = Math.sin(this.r);
        ctx.setTransform(ax, ay, -ay, ax, this.x, this.y);
        ctx.strokeRect(-this.w * 0.5, -this.h * 0.5, this.w, this.h);
    }
};

function renderLoop() {
    ctx.setTransform(1,0,0,1,0,0);
    ctx.clearRect(0, 0, W, H);
    if (expanding === 1) {
        expandCount += 1;
        expandCount === 50 && (expanding = -1);
    } else if (expanding === -1) {
        expandCount -= 1;
        expandCount === 0 && (expanding = 1);
    }
    
    rect.r += 0.01;
    rect.expand(0, expanding, 0, 0);

    rect.draw();
    requestAnimationFrame(renderLoop);
}


 
canvas {
    border: 1px solid black;
}
   <canvas id = "canvas" width="200" height="200"></canvas>

about 4 years ago · Juan Pablo Isaza Relatório

0

The other answers are nice and elegant, but you said you wanted to keep rotateCanvas and drawRotateRectangle around, right?

We can imitate the transform in your rotateCanvas function using some matrix transformations on a DOMPoint:

  const x = 60;
  const y = 30;
  const h = 30;
  const a = 0.5;
  const tx = rWidth / 2;
  const ty = h / 2;

  // (0, 0) is the upper left of the rectangle
  const pt = new DOMPoint(0, 0);
  // Create transformation matrix based on center of rectangle
  const mtr = new DOMMatrix()
    .translateSelf(-tx, -ty)
    // Important: rotateSelf takes degrees, not radians 
    .rotateSelf(a * 180 / Math.PI)
    .translateSelf(tx, ty);
  // Apply the transform
  const tPt = pt.matrixTransform(mtr);

  // Now the new call looks like this:
  drawRotateRectangle(tPt.x + x, tPt.y + y, rWidth, h, a);

Here's a demo. I drew an extra red dot to show that you can control where you want to start drawing the rectangle using x and y.

const canvas = document.querySelector('canvas');
const ctx = canvas.getContext("2d");

function rotateCanvas(x, y, a) {
  ctx.translate(x, y);
  ctx.rotate(a);
  ctx.translate(-x, -y);
}

function drawRotateRectangle(x, y, w, h, a) {
  rotateCanvas(x + w / 2, y + h / 2, a);
  ctx.fillRect(x, y, w, h);
  rotateCanvas(x + w / 2, y + h / 2, -a);
}

let which = false;

function render() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  const rWidth = which ? 100 : 200;

  const x = 30;
  const y = 30;
  const h = 30;
  const a = Math.PI / 3;
  const tx = rWidth / 2;
  const ty = h / 2;
  
  // Imitate the transform you use to calculate the offset point
  const pt = new DOMPoint(0, 0);
  const mtr = new DOMMatrix()
    .translateSelf(-tx, -ty)
    .rotateSelf(a * 180 / Math.PI)
    .translateSelf(tx, ty);
  const tPt = pt.matrixTransform(mtr);
  drawRotateRectangle(tPt.x + x, tPt.y + y, rWidth, h, a);

  // Just to show you can control the start point
  ctx.fillStyle = 'red';
  ctx.fillRect(x, y, 3, 3);
  ctx.fillStyle = 'black';

  which = !which;
}

render();

setInterval(render, 1000);
<canvas style="border: 1px solid black;"></canvas>

about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda