Tengo un rectángulo girado alrededor de su centro y estoy tratando de hacerlo más ancho. Sin embargo, debido a que se gira alrededor de su centro, lo que lo hace más ancho también "mueve" visualmente el rectángulo.
Lo que estoy buscando es una manera de hacerlo más ancho y luego ajustar sus componentes x e y en consecuencia para que visualmente no se mueva. He creado una reproducción del problema aquí, para que pueda ver el problema:
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>Como puede ver, cuando se ensancha, también se mueve hacia arriba. Efectivamente, quiero que la parte superior izquierda del rectángulo esté en el mismo punto antes y después de que se produzca el cambio de tamaño.
Sin embargo, también quiero que todavía se gire alrededor de su centro. Es decir, busco cuánto tengo que mover el rectángulo (cambiar sus coordenadas x e y) para anclarlo efectivamente en la misma ubicación, antes y después de que se produzca el cambio de tamaño.
es posible? Si es así, ¿cómo calcularía el valor por el que tiene que modificar la x y la y del rectángulo para mantenerlo bloqueado visualmente en su posición actual?
Reconozco que este problema no ocurriría si, en cambio, girara el rectángulo alrededor de su parte superior izquierda en lugar de su centro, pero para los fines de mi aplicación, el rectángulo debe girarse alrededor de su centro, por lo que estoy buscando cuánto tiene que modificar sus componentes x e y para mantener su posición visual.
Como tal, la respuesta a esta pregunta no debería involucrar la modificación de las funciones de rotateCanvas o drawRotateRectangle de ninguna manera.
Para moverse a lo largo de un eje girado. La rotación como 'r' y la distancia como 'd'. Supone que la transformación es uniforme (es decir, la escala x, y es la misma en este caso 1 y no hay sesgo)
Ejemplo para mover dx a lo largo del eje x y dy a lo largo del eje y
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; Expandiendo un rectángulo. La función rect.expand(left, right, top, bottom) cambia el tamaño del rectángulo ajustando el origen para mantener los bordes sin cambios donde están.
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>Las otras respuestas son bonitas y elegantes, pero dijiste que querías seguir con drawRotateRectangle rotateCanvas ¿verdad?
Podemos imitar la transformación en su función de rotateCanvas usando algunas transformaciones de matriz en unDOMPoint :
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); Aquí hay una demostración. Dibujé un punto rojo adicional para mostrar que puedes controlar dónde quieres comenzar a dibujar el rectángulo usando x e 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>