pin_drop当前位置:知识文库 ❯ 图文

多媒体:绘制矩形 - 完整教程与代码示例

一、教程简介

矩形是 Canvas 中最基础的图形,也是唯一一种可以直接通过 API 绘制的形状(其他形状都需要通过路径绘制)。Canvas 提供了三个矩形绘制方法:fillRect 用于填充矩形、strokeRect 用于描边矩形、clearRect 用于清除矩形区域。本教程将详细介绍这三个方法的使用,以及相关的样式属性设置。


二、核心概念

三种矩形操作

方法 功能 说明
fillRect(x, y, w, h) 填充矩形 使用当前 fillStyle 填充
strokeRect(x, y, w, h) 描边矩形 使用当前 strokeStyle 描边
clearRect(x, y, w, h) 清除矩形 将指定区域变为透明

相关样式属性

属性 说明 默认值
fillStyle 填充样式(颜色、渐变、图案) #000000
strokeStyle 描边样式(颜色、渐变、图案) #000000
lineWidth 描边线宽 1
globalAlpha 全局透明度 1.0

矩形与路径的区别

矩形方法不会影响当前路径,它们是独立的绘图操作,不需要 beginPath()closePath()


三、语法与用法

fillRect - 填充矩形

代码示例

ctx.fillRect(x, y, width, height);
参数 说明
x 矩形左上角 X 坐标
y 矩形左上角 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>

五、浏览器兼容性

浏览器 支持版本 备注
Chrome 1+ 完整支持
Firefox 1.5+ 完整支持
Safari 2+ 完整支持
Edge 12+ 完整支持
IE 9+ 完整支持

矩形绘制方法属于 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()

  • 样式控制:通过 fillStylestrokeStyle 控制颜色,支持颜色字符串、渐变和图案

  • 线宽注意:奇数 lineWidth 会导致模糊,建议使用偶数或偏移 0.5 像素

  • 清除效果clearRect 产生透明区域,不是白色

  • 性能优势:矩形绘制是最高效的 Canvas 操作之一

下一教程将介绍如何使用路径绘制更复杂的图形。

标签: Canvas矩形 fillRect strokeRect clearRect Canvas绘图 矩形绘制

本文涉及AI创作

内容由AI创作,请仔细甄别

list快速访问

上一篇: 多媒体:Canvas简介 - 完整教程与代码示例 下一篇: 多媒体:绘制路径 - 完整教程与代码示例

poll相关推荐