You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

HTML Canvas变换与旋转:正方形旋转中心偏移及通用计算方法

问题:Canvas正方形旋转未以中心为轴的原因及通用解决方法

问题描述

想要绘制一个正方形并将其旋转45deg,当前代码可运行,但旋转变换并未以正方形中心为轴(偏移约72px),请问为何会出现这种情况?如何通过编程计算任意尺寸正方形所需的变换参数?

现有代码

var canvas = document.querySelector('canvas');
canvas.width = 300;
canvas.height = 400;
let rotate = false;
let clear = true; // if set to false then compare the two squares.
let ctx = canvas.getContext('2d')
    setInterval(() => {
      ctx.fillStyle = 'white';
      clear && ctx.fillRect(0,0,canvas.width,canvas.height);
      ctx.fillStyle = 'black';
      ctx.save();
      rotate = !rotate;

      if ( rotate ) {
          ctx.translate(150,128); // the center of the square is 150 / 200 ?? 
          ctx.rotate(45 * Math.PI / 180); // 45 deg
      } else {
          ctx.translate(100,150); // top left of square
      }
      
      ctx.fillRect(0,0,100,100);
      ctx.restore();
    },1000)
<canvas style="border: 1px solid red"></canvas>

问题原因

  1. 旋转中心坐标错误:未旋转状态下,正方形的左上角是(100,150),尺寸为100x100,因此它的中心坐标应为100+100/2=150,150+100/2=200,即(150,200)。你当前旋转时使用的translate(150,128)并非正确的中心位置,直接导致旋转轴偏移。
  2. 变换与绘制的逻辑不匹配:Canvas的旋转变换是以当前原点为轴的。你在平移到目标点后,直接从(0,0)绘制正方形,此时正方形的左上角对齐原点,旋转轴落在正方形的左上角而非中心,这是旋转后整体偏移的核心原因。

解决方法与通用参数计算

核心逻辑

要实现图形绕自身中心旋转,需遵循平移原点到图形中心 → 旋转 → 以原点为中心绘制图形的顺序:

  1. 计算目标正方形的中心坐标;
  2. 将Canvas原点平移到该中心;
  3. 执行旋转变换;
  4. 以原点为中心绘制正方形(即绘制的起始坐标为负的半宽、半高)。

任意尺寸正方形的参数计算

假设正方形的:

  • 目标左上角坐标为(x, y);
  • 宽度/高度为size(正方形宽高相等);

则:

  • 中心坐标:centerX = x + size/2,centerY = y + size/2;
  • 绘制时的起始坐标:(-size/2, -size/2)(确保正方形中心与原点重合);

修改后的代码

var canvas = document.querySelector('canvas');
canvas.width = 300;
canvas.height = 400;
let rotate = false;
let clear = true;
let ctx = canvas.getContext('2d')

const squareX = 100; // 正方形左上角X
const squareY = 150; // 正方形左上角Y
const squareSize = 100; // 正方形尺寸

setInterval(() => {
  ctx.fillStyle = 'white';
  clear && ctx.fillRect(0,0,canvas.width,canvas.height);
  ctx.fillStyle = 'black';
  ctx.save();
  rotate = !rotate;

  if (rotate) {
    // 计算中心坐标
    const centerX = squareX + squareSize / 2;
    const centerY = squareY + squareSize / 2;
    // 平移到中心
    ctx.translate(centerX, centerY);
    // 旋转45度
    ctx.rotate(45 * Math.PI / 180);
    // 以原点为中心绘制正方形
    ctx.fillRect(-squareSize/2, -squareSize/2, squareSize, squareSize);
  } else {
    // 正常绘制(左上角对齐目标点)
    ctx.translate(squareX, squareY);
    ctx.fillRect(0,0,squareSize,squareSize);
  }
  
  ctx.restore();
}, 1000)

内容的提问来源于stack exchange,提问作者user3094755

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 18:45:32