svg 图像在 canvas 中无法居中,通常是因为在图像未加载完成时就提前读取了其 width/height 属性(此时为 0),导致计算出的绘制坐标错误;本文提供可靠解决方案与完整示例代码。
svg 图像在 canvas 中无法居中,通常是因为在图像未加载完成时就提前读取了其 width/height 属性(此时为 0),导致计算出的绘制坐标错误;本文提供可靠解决方案与完整示例代码。
在 HTML Canvas 中绘制并居中 SVG 图像(如 )与 PNG/JPEG 不同:SVG 图像的 width 和 height 属性在未加载完成前始终为 0。你在 Game 构造函数中立即使用 this.image.width 和 this.image.height 计算 this.x 和 this.y,此时图像尚未触发 load 事件,因此 x = centerX - 0 = centerX,y = centerY - 0 = centerY——看似居中,实则 Canvas 默认将图像左上角锚点置于 (centerX, centerY),最终图像右下部分被“挤”到画布右下角。
✅ 正确做法是:将位置计算和绘制逻辑延迟至图像加载完成后执行。以下是优化后的完整实现:
window.addEventListener('load', function () {
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth - 100;
canvas.height = window.innerHeight - 100;
class Game {
constructor(gameWidth, gameHeight, imgSrc) {
this.width = gameWidth;
this.height = gameHeight;
this.image = new Image();
this.image.src = imgSrc;
// 关键:等待图像加载完成后再初始化尺寸与位置
this.image.onload = () => {
this.imgWidth = this.image.width;
this.imgHeight = this.image.height;
this.x = (this.width - this.imgWidth) / 2;
this.y = (this.height - this.imgHeight) / 2;
this.isLoaded = true; // 标记已就绪
};
this.isLoaded = false; // 初始未加载
}
draw(context) {
if (this.isLoaded) {
context.drawImage(this.image, this.x, this.y, this.imgWidth, this.imgHeight);
}
// 可选:加载中显示占位提示(提升体验)
else {
context.fillStyle = '#eee';
context.fillText('Loading...', this.width / 2 - 40, this.height / 2);
}
}
update() {}
}
// 替换为你的 SVG 路径,例如 'assets/logo.svg'
const game = new Game(canvas.width, canvas.height, option.introImage);
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height); // 清屏防重叠
game.update();
game.draw(ctx);
requestAnimationFrame(animate);
}
animate();
});
⚠️ 补充注意事项:
- 不要依赖 naturalWidth/naturalHeight 在 onload 外读取:即使设置 image.crossOrigin = 'anonymous',未加载时它们仍为 0;
-
Canvas 绘制 SVG 的兼容性:现代浏览器均支持直接绘制 SVG(作为
),但若 SVG 内含外部资源(如
)或使用 viewBox 未显式设宽高,建议在 SVG 源文件中添加 width 和 height 属性(如 - 响应式场景:若窗口大小变化,需监听 resize 并重新计算 x/y(注意避免重复绑定 onload);
- 替代方案(更健壮):对 SVG 使用 fetch + URL.createObjectURL() 加载为 Blob,再创建 Image 实例,可更好控制加载流与错误处理。
总结:居中 SVG 的核心不是“算法错误”,而是生命周期误判。始终将图像尺寸获取、坐标计算、绘制动作统一置于 image.onload 回调内,即可彻底解决偏移问题。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











