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

Javascript旋转canvas出现拉伸问题 仅2:1宽高比显示正常如何解决

问题产生原因

  • Canvas存在两套独立的尺寸体系:
    1. 绘图缓冲区尺寸:由<canvas>元素自带的width、height属性控制,默认值为300px * 150px,宽高比固定为2:1,决定了绘图的像素坐标空间
    2. 页面显示尺寸:由CSS规则的width、height属性控制,仅决定canvas元素在页面中的展示大小
  • 你没有显式设置canvas的width、height属性,使用了默认2:1的缓冲区比例。当CSS设置的显示比例刚好为2:1时,缓冲区内容会等比缩放适配显示尺寸,所以显示正常;其余比例下,缓冲区内容会被强制拉伸适配显示尺寸,因此出现变形。

优化实现方案

1. 解决拉伸问题

首先对齐canvas的绘图缓冲区尺寸和显示尺寸比例,推荐直接将缓冲区尺寸设置为和显示尺寸完全一致,从根源避免拉伸:

const canvas = document.getElementById('canvas');
// 显式设置绘图缓冲区尺寸,和显示尺寸匹配
canvas.width = 400;
canvas.height = 400;
// 设置页面显示尺寸,也可以直接写在CSS文件中
canvas.style.width = '400px';
canvas.style.height = '400px';
canvas.style.border = '2px solid black';

2. 简化旋转动画逻辑

常规的“绕固定点旋转图形”不需要手动计算相对坐标和角度,按照平移坐标系到目标点 -> 旋转坐标系 -> 绘制中心在原点的图形的顺序调用变换接口即可,逻辑更简洁不易出错:

const ctx = canvas.getContext('2d');
const w = canvas.width / 4;
const h = canvas.width / 4;
let relativeAngle = 0;
// 固定旋转中心为canvas正中间
const targetX = canvas.width / 2;
const targetY = canvas.height / 2;
ctx.fillStyle = 'red';

function draw() {
  relativeAngle += 3;
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.save();
  // 先将坐标系原点平移到目标旋转中心
  ctx.translate(targetX, targetY);
  // 绕当前原点旋转
  ctx.rotate(relativeAngle * Math.PI / 180);
  // 绘制中心和原点重合的矩形
  ctx.fillRect(-w / 2, -h / 2, w, h);
  ctx.restore();
  requestAnimationFrame(draw);
}
draw();

该方案适配任意canvas宽高比,只要提前对齐缓冲区和显示尺寸比例,就不会出现拉伸问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 17:45:05