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

多媒体:图案 - 完整教程与代码示例

一、教程简介

Canvas 图案(Pattern)允许使用图像、Canvas 或视频作为重复填充或描边的素材。通过 createPattern 方法,可以将一张小图片平铺为背景图案,类似于 CSS 中的 background-repeat。本教程将详细讲解图案的创建、重复模式和使用方法。


二、核心概念

图案来源

createPattern 支持以下来源:

  • HTMLImageElement<img> 标签加载的图片

  • HTMLCanvasElement:另一个 Canvas 元素

  • HTMLVideoElement<video> 标签的视频帧

  • ImageBitmap:位图对象

重复模式

模式 说明
repeat 水平和垂直方向都重复(默认)
repeat-x 仅水平方向重复
repeat-y 仅垂直方向重复
no-repeat 不重复,仅显示一次

三、语法与用法

createPattern

代码示例

const pattern = ctx.createPattern(image, repetition);
参数 说明
image 图像源(img、canvas、video 等)
repetition 重复模式:repeatrepeat-xrepeat-yno-repeat

使用图案

代码示例

const img = new Image();
img.src = 'pattern.png';
img.onload = function() {
  const pattern = ctx.createPattern(img, 'repeat');
  ctx.fillStyle = pattern;
  ctx.fillRect(0, 0, canvas.width, canvas.height);
};

四、代码示例

示例1:图案重复模式与离屏 Canvas 图案

代码示例

<!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;
    }
  </style>
</head>
<body>
  <h1>图案重复模式演示</h1>
  <canvas id="myCanvas" width="750" height="500"></canvas>

  <script>
    const canvas = document.getElementById('myCanvas');
    const ctx = canvas.getContext('2d');

    // === 创建离屏 Canvas 图案 ===

    // 图案1:棋盘格
    function createCheckerPattern() {
      const pc = document.createElement('canvas');
      pc.width = 20; pc.height = 20;
      const pctx = pc.getContext('2d');
      pctx.fillStyle = '#1f2937';
      pctx.fillRect(0, 0, 20, 20);
      pctx.fillStyle = '#374151';
      pctx.fillRect(0, 0, 10, 10);
      pctx.fillRect(10, 10, 10, 10);
      return pc;
    }

    // 图案2:圆点
    function createDotPattern() {
      const pc = document.createElement('canvas');
      pc.width = 20; pc.height = 20;
      const pctx = pc.getContext('2d');
      pctx.fillStyle = '#1a1a2e';
      pctx.fillRect(0, 0, 20, 20);
      pctx.fillStyle = '#58a6ff';
      pctx.beginPath();
      pctx.arc(10, 10, 3, 0, Math.PI * 2);
      pctx.fill();
      return pc;
    }

    // 图案3:斜线
    function createDiagonalPattern() {
      const pc = document.createElement('canvas');
      pc.width = 10; pc.height = 10;
      const pctx = pc.getContext('2d');
      pctx.strokeStyle = '#3fb950';
      pctx.lineWidth = 1;
      pctx.beginPath();
      pctx.moveTo(0, 10);
      pctx.lineTo(10, 0);
      pctx.stroke();
      pctx.beginPath();
      pctx.moveTo(-2, 2);
      pctx.lineTo(2, -2);
      pctx.stroke();
      pctx.beginPath();
      pctx.moveTo(8, 12);
      pctx.lineTo(12, 8);
      pctx.stroke();
      return pc;
    }

    // 图案4:十字
    function createCrossPattern() {
      const pc = document.createElement('canvas');
      pc.width = 16; pc.height = 16;
      const pctx = pc.getContext('2d');
      pctx.fillStyle = '#1a1a2e';
      pctx.fillRect(0, 0, 16, 16);
      pctx.strokeStyle = '#e9456080';
      pctx.lineWidth = 1;
      pctx.beginPath();
      pctx.moveTo(8, 2); pctx.lineTo(8, 14);
      pctx.moveTo(2, 8); pctx.lineTo(14, 8);
      pctx.stroke();
      return pc;
    }

    // 图案5:波浪
    function createWavePattern() {
      const pc = document.createElement('canvas');
      pc.width = 30; pc.height = 15;
      const pctx = pc.getContext('2d');
      pctx.fillStyle = '#0f172a';
      pctx.fillRect(0, 0, 30, 15);
      pctx.strokeStyle = '#d2a8ff60';
      pctx.lineWidth = 1;
      pctx.beginPath();
      pctx.moveTo(0, 10);
      pctx.quadraticCurveTo(7.5, 0, 15, 10);
      pctx.quadraticCurveTo(22.5, 20, 30, 10);
      pctx.stroke();
      return pc;
    }

    // 图案6:菱形
    function createDiamondPattern() {
      const pc = document.createElement('canvas');
      pc.width = 20; pc.height = 20;
      const pctx = pc.getContext('2d');
      pctx.fillStyle = '#1a1a2e';
      pctx.fillRect(0, 0, 20, 20);
      pctx.fillStyle = '#f8b50030';
      pctx.beginPath();
      pctx.moveTo(10, 0);
      pctx.lineTo(20, 10);
      pctx.lineTo(10, 20);
      pctx.lineTo(0, 10);
      pctx.closePath();
      pctx.fill();
      return pc;
    }

    // === 演示四种重复模式 ===
    const patterns = [
      { canvas: createCheckerPattern(), name: '棋盘格' },
      { canvas: createDotPattern(), name: '圆点' },
      { canvas: createDiagonalPattern(), name: '斜线' },
      { canvas: createCrossPattern(), name: '十字' },
      { canvas: createWavePattern(), name: '波浪' },
      { canvas: createDiamondPattern(), name: '菱形' }
    ];

    const repeatModes = ['repeat', 'repeat-x', 'repeat-y', 'no-repeat'];

    ctx.fillStyle = '#c9d1d9';
    ctx.font = 'bold 14px sans-serif';
    ctx.textAlign = 'center';

    // 绘制重复模式演示
    repeatModes.forEach((mode, col) => {
      const x = 30 + col * 180;
      ctx.fillText(mode, x + 75, 25);

      patterns.slice(0, 4).forEach((pat, row) => {
        const y = 40 + row * 100;
        const pattern = ctx.createPattern(pat.canvas, mode);
        ctx.fillStyle = pattern;
        ctx.fillRect(x, y, 150, 80);

        ctx.strokeStyle = '#30363d';
        ctx.lineWidth = 1;
        ctx.strokeRect(x, y, 150, 80);

        ctx.fillStyle = '#8b949e';
        ctx.font = '10px sans-serif';
        ctx.fillText(pat.name, x + 75, y + 95);
        ctx.font = 'bold 14px sans-serif';
      });
    });

    // === 图案作为描边 ===
    ctx.fillStyle = '#c9d1d9';
    ctx.font = 'bold 14px sans-serif';
    ctx.fillText('图案描边与填充', 375, 460);

    // 填充
    const fillPattern = ctx.createPattern(patterns[1].canvas, 'repeat');
    ctx.fillStyle = fillPattern;
    ctx.beginPath();
    ctx.arc(120, 490, 40, 0, Math.PI * 2);
    ctx.fill();
    ctx.strokeStyle = '#58a6ff';
    ctx.lineWidth = 2;
    ctx.stroke();

    // 描边
    const strokePattern = ctx.createPattern(patterns[2].canvas, 'repeat');
    ctx.strokeStyle = strokePattern;
    ctx.lineWidth = 8;
    ctx.beginPath();
    ctx.arc(280, 490, 40, 0, Math.PI * 2);
    ctx.stroke();

    // 填充+描边
    ctx.fillStyle = fillPattern;
    ctx.beginPath();
    ctx.arc(440, 490, 40, 0, Math.PI * 2);
    ctx.fill();
    ctx.strokeStyle = strokePattern;
    ctx.lineWidth = 6;
    ctx.stroke();

    // 文字填充图案
    const textPattern = ctx.createPattern(patterns[5].canvas, 'repeat');
    ctx.fillStyle = textPattern;
    ctx.font = 'bold 36px sans-serif';
    ctx.fillText('Pattern', 620, 498);
  </script>
</body>
</html>

五、浏览器兼容性

特性 Chrome Firefox Safari Edge IE
createPattern 1+ 1.5+ 2+ 12+ 9+
Canvas 作为图案源 4+ 3.5+ 3+ 12+ 9+
Video 作为图案源 1+ 3.5+ 3.1+ 12+ 不支持

六、注意事项与最佳实践

1. 图片必须加载完成

代码示例

const img = new Image();
img.src = 'pattern.png';
img.onload = function() {
  const pattern = ctx.createPattern(img, 'repeat');
  ctx.fillStyle = pattern;
  ctx.fillRect(0, 0, 300, 200);
};

2. 使用离屏 Canvas 创建程序化图案

代码示例

function createPatternCanvas(size, drawFn) {
  const pc = document.createElement('canvas');
  pc.width = size;
  pc.height = size;
  const pctx = pc.getContext('2d');
  drawFn(pctx, size);
  return pc;
}

const patternCanvas = createPatternCanvas(20, (ctx, size) => {
  ctx.fillStyle = '#1a1a2e';
  ctx.fillRect(0, 0, size, size);
  ctx.fillStyle = '#58a6ff';
  ctx.beginPath();
  ctx.arc(size/2, size/2, 3, 0, Math.PI * 2);
  ctx.fill();
});

3. 图案与变换

图案受当前变换矩阵影响:

代码示例

const pattern = ctx.createPattern(img, 'repeat');
ctx.fillStyle = pattern;

// 缩放图案
ctx.save();
ctx.scale(2, 2);
ctx.fillRect(0, 0, 200, 100);
ctx.restore();

4. 图案偏移

通过 setTransform 控制图案的偏移:

代码示例

const pattern = ctx.createPattern(img, 'repeat');
// 现代浏览器支持 pattern.setTransform
if (pattern.setTransform) {
  const matrix = new DOMMatrix();
  matrix.translateSelf(10, 10);
  pattern.setTransform(matrix);
}
ctx.fillStyle = pattern;
ctx.fillRect(0, 0, 300, 200);

七、代码规范示例

代码示例

// 推荐:封装图案创建
function createPatternFromCanvas(ctx, drawFn, size, repetition) {
  const pc = document.createElement('canvas');
  pc.width = size;
  pc.height = size;
  const pctx = pc.getContext('2d');
  drawFn(pctx, size);
  return ctx.createPattern(pc, repetition || 'repeat');
}

// 推荐:图案预设
const PATTERN_DRAW = {
  dots: (ctx, size) => {
    ctx.fillStyle = '#1a1a2e';
    ctx.fillRect(0, 0, size, size);
    ctx.fillStyle = '#58a6ff';
    ctx.beginPath();
    ctx.arc(size/2, size/2, size*0.15, 0, Math.PI * 2);
    ctx.fill();
  },
  grid: (ctx, size) => {
    ctx.fillStyle = '#1a1a2e';
    ctx.fillRect(0, 0, size, size);
    ctx.strokeStyle = '#30363d';
    ctx.lineWidth = 0.5;
    ctx.strokeRect(0, 0, size, size);
  },
  diagonal: (ctx, size) => {
    ctx.strokeStyle = '#3fb95080';
    ctx.lineWidth = 1;
    ctx.beginPath();
    ctx.moveTo(0, size);
    ctx.lineTo(size, 0);
    ctx.stroke();
  }
};

// 使用示例
const dotPattern = createPatternFromCanvas(ctx, PATTERN_DRAW.dots, 16, 'repeat');
ctx.fillStyle = dotPattern;
ctx.fillRect(0, 0, 300, 200);

八、常见问题与解决方案

常见问题

图案不显示?

原因:图片未加载完成就创建了图案。解决方案:确保在onload回调中创建图案。

如何创建动态图案?

使用离屏Canvas并在每帧更新图案内容,通过requestAnimationFrame实现动画效果。

图案太大或太小?

使用离屏Canvas缩放图案源,通过调整离屏Canvas尺寸控制图案大小。


九、总结

图案是 Canvas 填充和描边的重要样式类型,关键要点:

  • createPattern:从图像源创建图案,支持 img、canvas、video

  • 重复模式repeatrepeat-xrepeat-yno-repeat

  • 离屏 Canvas:使用离屏 Canvas 创建程序化图案,无需外部图片

  • 加载时机:确保图片加载完成后再创建图案

  • 变换影响:图案受当前变换矩阵影响

  • 描边与填充:图案可同时用于 fillStyle 和 strokeStyle

下一教程将介绍 Canvas 阴影效果。

标签: Canvas图案 createPattern 图案重复 离屏Canvas 程序化图案

本文涉及AI创作

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

list快速访问

上一篇: 多媒体:渐变 - 完整教程与代码示例 下一篇: 多媒体:Canvas阴影 - 完整教程与代码示例

poll相关推荐