pin_drop当前位置:知识文库 ❯ 图文
多媒体:绘制矩形 - 完整教程与代码示例
一、教程简介
矩形是 Canvas 中最基础的图形,也是唯一一种可以直接通过 API 绘制的形状(其他形状都需要通过路径绘制)。Canvas 提供了三个矩形绘制方法:fillRect 用于填充矩形、strokeRect 用于描边矩形、clearRect 用于清除矩形区域。本教程将详细介绍这三个方法的使用,以及相关的样式属性设置。
二、核心概念
三种矩形操作
相关样式属性
矩形与路径的区别
矩形方法不会影响当前路径,它们是独立的绘图操作,不需要 beginPath() 和 closePath()。
三、语法与用法
fillRect - 填充矩形
代码示例
ctx.fillRect(x, y, width, height);strokeRect - 描边矩形
代码示例
ctx.strokeRect(x, y, width, height);
参数与 fillRect 相同。
clearRect - 清除矩形
代码示例
ctx.clearRect(x, y, width, height);
将指定矩形区域内的像素清除为透明黑色(rgba(0,0,0,0))。
fillStyle 与 strokeStyle
代码示例
// 使用颜色字符串
ctx.fillStyle = 'red';
ctx.fillStyle = '#ff0000';
ctx.fillStyle = 'rgb(255, 0, 0)';
ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';
// 使用渐变(后续教程详细介绍)
const gradient = ctx.createLinearGradient(0, 0, 200, 0);
ctx.fillStyle = gradient;
// 使用图案(后续教程详细介绍)
const pattern = ctx.createPattern(image, 'repeat');
ctx.fillStyle = pattern;四、代码示例
示例1:三种矩形操作演示
代码示例
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>三种矩形操作演示</title>
<style>
body {
margin: 0;
padding: 20px;
background: #0d1117;
color: #c9d1d9;
font-family: 'Segoe UI', sans-serif;
display: flex;
flex-direction: column;
align-items: center;
}
canvas {
border: 1px solid #30363d;
border-radius: 8px;
background: #161b22;
}
.legend {
display: flex;
gap: 30px;
margin-top: 15px;
font-size: 14px;
}
.legend-item {
display: flex;
align-items: center;
gap: 8px;
}
.legend-color {
width: 20px;
height: 20px;
border-radius: 3px;
}
</style>
</head>
<body>
<h1>三种矩形操作演示</h1>
<canvas id="myCanvas" width="700" height="400"></canvas>
<div class="legend">
<div class="legend-item">
<div class="legend-color" style="background:#58a6ff;"></div>
<span>fillRect 填充</span>
</div>
<div class="legend-item">
<div class="legend-color" style="border:2px solid #f78166;"></div>
<span>strokeRect 描边</span>
</div>
<div class="legend-item">
<div class="legend-color" style="background:#161b22;border:1px dashed #8b949e;"></div>
<span>clearRect 清除</span>
</div>
</div>
<script>
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
// === 1. fillRect 填充矩形 ===
ctx.fillStyle = '#58a6ff';
ctx.fillRect(30, 30, 180, 120);
ctx.fillStyle = '#3fb950';
ctx.fillRect(30, 170, 180, 120);
// 半透明填充
ctx.fillStyle = 'rgba(210, 153, 34, 0.6)';
ctx.fillRect(30, 310, 180, 70);
// === 2. strokeRect 描边矩形 ===
ctx.strokeStyle = '#f78166';
ctx.lineWidth = 3;
ctx.strokeRect(250, 30, 180, 120);
ctx.strokeStyle = '#d2a8ff';
ctx.lineWidth = 5;
ctx.strokeRect(250, 170, 180, 120);
ctx.strokeStyle = 'rgba(139, 148, 158, 0.8)';
ctx.lineWidth = 2;
ctx.strokeRect(250, 310, 180, 70);
// === 3. clearRect 清除矩形 ===
// 先绘制一个填充矩形
ctx.fillStyle = '#da3633';
ctx.fillRect(470, 30, 200, 350);
// 在红色矩形中清除区域
ctx.clearRect(490, 50, 80, 60);
ctx.clearRect(590, 50, 60, 60);
ctx.clearRect(490, 130, 160, 80);
ctx.clearRect(490, 230, 70, 130);
ctx.clearRect(580, 230, 70, 130);
// 添加标签文字
ctx.fillStyle = '#c9d1d9';
ctx.font = 'bold 16px sans-serif';
ctx.textAlign = 'center';
ctx.fillText('fillRect', 120, 22);
ctx.fillText('strokeRect', 340, 22);
ctx.fillText('clearRect', 570, 22);
</script>
</body>
</html>示例2:矩形组合绘制与样式应用
代码示例
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>矩形组合绘制</title>
<style>
body {
margin: 0;
padding: 20px;
background: #1a1a2e;
color: #eee;
font-family: 'Segoe UI', sans-serif;
display: flex;
flex-direction: column;
align-items: center;
}
canvas {
border: 1px solid #333;
border-radius: 8px;
}
</style>
</head>
<body>
<h1>矩形组合绘制 - 像素风城堡</h1>
<canvas id="myCanvas" width="600" height="400"></canvas>
<script>
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
// 天空渐变
const skyGrad = ctx.createLinearGradient(0, 0, 0, 280);
skyGrad.addColorStop(0, '#0f0c29');
skyGrad.addColorStop(0.5, '#302b63');
skyGrad.addColorStop(1, '#24243e');
ctx.fillStyle = skyGrad;
ctx.fillRect(0, 0, 600, 280);
// 地面
ctx.fillStyle = '#2d5016';
ctx.fillRect(0, 280, 600, 120);
ctx.fillStyle = '#3a6b1e';
ctx.fillRect(0, 280, 600, 8);
// 星星
ctx.fillStyle = '#fff';
const stars = [[50,30],[120,60],[200,20],[350,50],[450,35],[520,70],[80,100],[280,80],[400,90],[550,40]];
stars.forEach(([x, y]) => {
ctx.fillRect(x, y, 2, 2);
});
// 月亮
ctx.fillStyle = '#f5f5dc';
ctx.beginPath();
ctx.arc(500, 60, 25, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#302b63';
ctx.beginPath();
ctx.arc(510, 55, 22, 0, Math.PI * 2);
ctx.fill();
// 城堡主体
const wallColor = '#4a4a6a';
const wallLight = '#5a5a7a';
const wallDark = '#3a3a5a';
const windowColor = '#ffd700';
const doorColor = '#2a1a0a';
// 城堡底座
ctx.fillStyle = wallColor;
ctx.fillRect(150, 180, 300, 100);
// 城墙砖纹
ctx.fillStyle = wallLight;
for (let row = 0; row < 5; row++) {
for (let col = 0; col < 15; col++) {
const offset = (row % 2) * 10;
ctx.fillRect(152 + col * 20 + offset, 182 + row * 20, 18, 18);
}
}
// 城门
ctx.fillStyle = doorColor;
ctx.fillRect(270, 230, 60, 50);
ctx.fillStyle = '#5a3a1a';
ctx.fillRect(275, 235, 22, 40);
ctx.fillRect(303, 235, 22, 40);
// 城门拱顶
ctx.fillStyle = wallDark;
ctx.fillRect(265, 225, 70, 10);
// 左塔
ctx.fillStyle = wallColor;
ctx.fillRect(150, 120, 60, 160);
ctx.fillStyle = wallDark;
ctx.fillRect(145, 110, 70, 15);
// 左塔城垛
for (let i = 0; i < 4; i++) {
ctx.fillStyle = wallLight;
ctx.fillRect(147 + i * 18, 95, 14, 18);
}
// 右塔
ctx.fillStyle = wallColor;
ctx.fillRect(390, 120, 60, 160);
ctx.fillStyle = wallDark;
ctx.fillRect(385, 110, 70, 15);
// 右塔城垛
for (let i = 0; i < 4; i++) {
ctx.fillStyle = wallLight;
ctx.fillRect(387 + i * 18, 95, 14, 18);
}
// 中塔
ctx.fillStyle = wallDark;
ctx.fillRect(260, 100, 80, 80);
ctx.fillStyle = wallColor;
ctx.fillRect(265, 105, 70, 70);
// 中塔城垛
for (let i = 0; i < 5; i++) {
ctx.fillStyle = wallLight;
ctx.fillRect(262 + i * 16, 85, 12, 18);
}
// 旗帜
ctx.fillStyle = '#8b0000';
ctx.fillRect(298, 50, 4, 38);
ctx.fillStyle = '#e94560';
ctx.fillRect(302, 52, 25, 16);
ctx.fillStyle = '#ff6b81';
ctx.fillRect(302, 52, 25, 5);
// 窗户
ctx.fillStyle = windowColor;
ctx.fillRect(165, 140, 15, 20);
ctx.fillRect(195, 140, 15, 20);
ctx.fillRect(165, 175, 15, 20);
ctx.fillRect(195, 175, 15, 20);
ctx.fillRect(405, 140, 15, 20);
ctx.fillRect(435, 140, 15, 20);
ctx.fillRect(405, 175, 15, 20);
ctx.fillRect(435, 175, 15, 20);
ctx.fillRect(280, 120, 15, 20);
ctx.fillRect(305, 120, 15, 20);
// 窗户十字框
ctx.fillStyle = wallDark;
// 左塔窗户十字
[[165,140],[195,140],[165,175],[195,175]].forEach(([x,y]) => {
ctx.fillRect(x + 6, y, 3, 20);
ctx.fillRect(x, y + 8, 15, 3);
});
// 右塔窗户十字
[[405,140],[435,140],[405,175],[435,175]].forEach(([x,y]) => {
ctx.fillRect(x + 6, y, 3, 20);
ctx.fillRect(x, y + 8, 15, 3);
});
// 中塔窗户十字
[[280,120],[305,120]].forEach(([x,y]) => {
ctx.fillRect(x + 6, y, 3, 20);
ctx.fillRect(x, y + 8, 15, 3);
});
// 城墙城垛
for (let i = 0; i < 8; i++) {
ctx.fillStyle = wallLight;
ctx.fillRect(215 + i * 18, 168, 14, 15);
}
// 护城河
ctx.fillStyle = '#1a3a5c';
ctx.fillRect(100, 290, 400, 15);
ctx.fillStyle = '#2a5a8c';
ctx.fillRect(100, 290, 400, 5);
// 护城河倒影
ctx.globalAlpha = 0.3;
ctx.fillStyle = wallColor;
ctx.fillRect(150, 295, 300, 10);
ctx.globalAlpha = 1.0;
</script>
</body>
</html>五、浏览器兼容性
矩形绘制方法属于 Canvas 2D API 的基础部分,所有支持 Canvas 的浏览器均完整支持。
六、注意事项与最佳实践
1. 矩形方法不依赖路径
代码示例
// 矩形方法不需要 beginPath()
ctx.fillStyle = 'red';
ctx.fillRect(10, 10, 100, 50); // 直接绘制
// 路径中的 rect() 才需要 beginPath()
ctx.beginPath();
ctx.rect(10, 70, 100, 50);
ctx.fill();2. 描边线宽对尺寸的影响
lineWidth 为奇数时,描边会向两侧各延伸 0.5 像素,导致抗锯齿模糊:
代码示例
// 推荐:使用偶数线宽
ctx.lineWidth = 2;
ctx.strokeRect(10, 10, 100, 50);
// 或者偏移 0.5 像素
ctx.lineWidth = 1;
ctx.strokeRect(10.5, 10.5, 100, 50);3. clearRect 的透明效果
clearRect 将像素设为完全透明,如果 Canvas 背景是 CSS 设置的,清除后会显示 CSS 背景:
代码示例
// 清除整个画布
ctx.clearRect(0, 0, canvas.width, canvas.height);4. 负值宽高
宽度和高度可以为负值,矩形会向反方向绘制:
代码示例
ctx.fillRect(100, 100, -50, -30);
// 等同于
ctx.fillRect(50, 70, 50, 30);5. 填充与描边的顺序
先填充再描边,描边会覆盖在填充之上:
代码示例
ctx.fillStyle = 'blue';
ctx.fillRect(10, 10, 100, 50);
ctx.strokeStyle = 'red';
ctx.lineWidth = 3;
ctx.strokeRect(10, 10, 100, 50);七、代码规范示例
代码示例
// 推荐:封装矩形绘制函数
function drawFilledRect(ctx, x, y, w, h, color) {
ctx.fillStyle = color;
ctx.fillRect(x, y, w, h);
}
function drawStrokedRect(ctx, x, y, w, h, color, lineWidth) {
ctx.strokeStyle = color;
ctx.lineWidth = lineWidth || 1;
ctx.strokeRect(x, y, w, h);
}
function drawBothRect(ctx, x, y, w, h, fillColor, strokeColor, lineWidth) {
ctx.fillStyle = fillColor;
ctx.fillRect(x, y, w, h);
ctx.strokeStyle = strokeColor;
ctx.lineWidth = lineWidth || 1;
ctx.strokeRect(x, y, w, h);
}
// 推荐:清除画布的标准写法
function clearCanvas(ctx, canvas) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
// 推荐:使用对象参数
function drawRect(ctx, options) {
const {
x, y, width, height,
fill = null,
stroke = null,
lineWidth = 1
} = options;
if (fill) {
ctx.fillStyle = fill;
ctx.fillRect(x, y, width, height);
}
if (stroke) {
ctx.strokeStyle = stroke;
ctx.lineWidth = lineWidth;
ctx.strokeRect(x, y, width, height);
}
}
// 使用示例
drawRect(ctx, {
x: 10, y: 10, width: 100, height: 50,
fill: '#58a6ff',
stroke: '#1f6feb',
lineWidth: 2
});八、常见问题与解决方案
常见问题
为什么描边的矩形看起来模糊?
原因:lineWidth 为奇数时,描边在像素边界上产生抗锯齿。
解决方案:
代码示例
// 方案1:使用偶数线宽
ctx.lineWidth = 2;
// 方案2:坐标偏移 0.5 像素
ctx.lineWidth = 1;
ctx.strokeRect(10.5, 10.5, 100, 50);如何绘制圆角矩形?
原因:Canvas 没有直接的圆角矩形 API。
解决方案:使用路径绘制(后续教程详细讲解):
代码示例
function roundRect(ctx, x, y, w, h, r) {
ctx.beginPath();
ctx.moveTo(x + r, y);
ctx.lineTo(x + w - r, y);
ctx.quadraticCurveTo(x + w, y, x + w, y + r);
ctx.lineTo(x + w, y + h - r);
ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
ctx.lineTo(x + r, y + h);
ctx.quadraticCurveTo(x, y + h, x, y + h - r);
ctx.lineTo(x, y + r);
ctx.quadraticCurveTo(x, y, x + r, y);
ctx.closePath();
}
// 使用
roundRect(ctx, 10, 10, 100, 50, 8);
ctx.fillStyle = '#58a6ff';
ctx.fill();
ctx.strokeStyle = '#1f6feb';
ctx.lineWidth = 2;
ctx.stroke();clearRect 后为什么不是白色?
原因:clearRect 将像素设为透明(rgba(0,0,0,0)),不是白色。如果 Canvas 没有设置 CSS 背景,透明区域显示为页面背景色。
解决方案:
代码示例
// 如果需要白色背景
ctx.fillStyle = '#ffffff';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 或者通过 CSS 设置
// canvas { background: white; }如何绘制带边框和填充的矩形?
解决方案:
代码示例
// 先填充再描边
ctx.fillStyle = '#58a6ff';
ctx.fillRect(10, 10, 100, 50);
ctx.strokeStyle = '#1f6feb';
ctx.lineWidth = 2;
ctx.strokeRect(10, 10, 100, 50);矩形绘制性能如何?
解决方案:矩形绘制是 Canvas 中最高效的绘图操作之一。对于大量矩形绘制,建议:
代码示例
// 批量绘制相同颜色的矩形
ctx.fillStyle = '#58a6ff';
ctx.fillRect(10, 10, 50, 50);
ctx.fillRect(70, 10, 50, 50);
ctx.fillRect(130, 10, 50, 50);
// 只需设置一次 fillStyle九、总结
矩形是 Canvas 绘图的基础操作,核心要点:
-
三种操作:
fillRect填充、strokeRect描边、clearRect清除 -
独立于路径:矩形方法不影响当前路径,无需
beginPath() -
样式控制:通过
fillStyle和strokeStyle控制颜色,支持颜色字符串、渐变和图案 -
线宽注意:奇数
lineWidth会导致模糊,建议使用偶数或偏移 0.5 像素 -
清除效果:
clearRect产生透明区域,不是白色 -
性能优势:矩形绘制是最高效的 Canvas 操作之一
下一教程将介绍如何使用路径绘制更复杂的图形。
本文涉及AI创作
内容由AI创作,请仔细甄别