HTML5 Canvas 的width/height 与style.width/height

本文深入探讨了HTML5 Canvas元素中width和height属性的区别,解释了为何给Canvas设置width和height后绘图成功,以及它们与CSS设置的width和height之间的联系与区别。

HTML5 中Canvas元素的width和height属性如果不搞清楚就很容易犯些莫名其妙的错误。

先看这段代码:

<!DOCTYPE html>
<html>
	<head>
		<script type="text/javascript">
			window.onload=function(){
				var myCanvas = document.getElementById("myCanvas");
				var ctx = myCanvas.getContext("2d");
				ctx.fillStyle="yellow";
				ctx.fillRect(0,0,20,20);
			}
		</script>
		<style type="text/css">
			*{
				padding: 0;
				margin:0;
			}
			#myCanvas{
				display: block;
				margin-left: auto;
				margin-right: auto;
				width: 400px;
				height: 400px;
				border: 1px solid #000000;
			}
		</style>
	</head>
	<body>
		<canvas id="myCanvas"></canvas>
	</body>
</html>


代码很简单,目的本来是想要在Canvas里绘制一个宽20,长20的黄色矩形(其实也就是个正方形),但是结果出来却是:


画出的居然不是正方形,修改代码,将

<canvas id="myCanvas" ></canvas>
改为

<canvas id="myCanvas" width="400" height="400"></canvas>
绘图成功


为什么给加上width和height之后就成功了,而之前的代码里明明也给canvas设置了width和height,难道没起作用么。做引在于在css中设置的width&height与在canvas中设置的内联width和height并不是一个东西。简单的说,style里设置的width和height(带单位的)是设置canvas的实际像素大小的,为了方便查看,我给canvas加了一个边框,这个canvas大小为400px * 400 px。而在canvas内联属性设置的width和height则是相对更抽象一点的大小,可以理解为是把canvas分割成width列,height行,如果没有对它进行设置,默认值是width:300,height:150,再回头看开始的那张图,画出的黄色矩形高正好是宽的两倍,因为实际宽= 20 / 300 * 400px, 高=20/150*400px。不适用内联方式也可以设置canvas的width&height。

myCanvas.width=400;
myCanvas.height=600;

而在canvas的style里设置的width&height通过JS的设置方法是:
myCanvas.style.width="400px";
myCanvas.style.height="600px";

这是一个非常常见的问题:**Canvas 上的“加载中”提示没有显示出来**。 ### ❗️根本原因分析: 你已经正确设置了“加载中”文字的绘制逻辑,但 `canvas.width` 和 `canvas.height` 在 `canvas` 初始状态时是 `0`,所以: ```javascript ctx.fillText("加载中...", canvas.width / 2, canvas.height / 2); ``` 这行代码其实绘制在了 `(0, 0)` 的位置,也就是左上角,**你可能没看到文字是因为 canvas 初始大小是 0,导致文字不可见或位置不对**。 --- ## ✅ 正确的解决方案: 你需要在绘制“加载中”提示时,**手动设置 canvas 的宽高**,或者使用固定的宽高绘制提示文字。 --- ### ✅ 修改建议:设置默认 canvas 尺寸 ```javascript function displaySingleImageDetection(item) { const canvas = document.getElementById("imageCanvas"); const ctx = canvas.getContext("2d"); const conversationDiv = document.getElementById("conversation"); // 设置默认 canvas 大小 const defaultWidth = 600; const defaultHeight = 400; canvas.width = defaultWidth; canvas.height = defaultHeight; // 清空画布并显示“加载中...” ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.font = "20px Arial"; ctx.fillStyle = "gray"; ctx.textAlign = "center"; ctx.fillText("加载中...", canvas.width / 2, canvas.height / 2); // 清空对话框 conversationDiv.innerHTML = ""; const imagePath = item.src; const img = new Image(); img.crossOrigin = "Anonymous"; img.src = `/image?bucket=${bucketSelect.value}&path=${imagePath}`; img.onload = () => { // 加载完成后重置 canvas 大小为图片大小 canvas.width = img.width; canvas.height = img.height; ctx.drawImage(img, 0, 0); // 绘制 bounding boxes if (item.boxes && item.boxes.length > 0) { item.boxes.forEach(box => { const [x_min, y_min, x_max, y_max] = box.coords; const label = box.label; ctx.strokeStyle = "red"; ctx.lineWidth = 2; ctx.strokeRect(x_min, y_min, x_max - x_min, y_max - y_min); ctx.fillStyle = "red"; ctx.font = "16px Arial"; ctx.fillText(label, x_min + 5, y_min + 20); }); } }; img.onerror = () => { ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = "red"; ctx.fillText("加载失败", canvas.width / 2, canvas.height / 2); console.error("图片加载失败"); }; // 更新对话框内容 item.conversation.forEach(msg => { const div = document.createElement("div"); div.className = "message " + (msg.from === "human" ? "human" : "gpt"); div.textContent = `${msg.from}: ${msg.value.replace(/\n/g, '')}`; conversationDiv.appendChild(div); }); } ``` --- ### ✅ 效果说明: - 使用固定尺寸的 canvas 显示“加载中...”提示; - 加载完成后自动调整 canvas 尺寸以匹配图片; - 文字位置居中,不会因为初始尺寸为 0 而看不见。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值