pin_drop当前位置:知识文库 ❯ 图文
多媒体:图案 - 完整教程与代码示例
一、教程简介
Canvas 图案(Pattern)允许使用图像、Canvas 或视频作为重复填充或描边的素材。通过 createPattern 方法,可以将一张小图片平铺为背景图案,类似于 CSS 中的 background-repeat。本教程将详细讲解图案的创建、重复模式和使用方法。
二、核心概念
图案来源
createPattern 支持以下来源:
-
HTMLImageElement:
<img>标签加载的图片 -
HTMLCanvasElement:另一个 Canvas 元素
-
HTMLVideoElement:
<video>标签的视频帧 -
ImageBitmap:位图对象
重复模式
三、语法与用法
createPattern
代码示例
const pattern = ctx.createPattern(image, repetition);使用图案
代码示例
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>五、浏览器兼容性
六、注意事项与最佳实践
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
-
重复模式:
repeat、repeat-x、repeat-y、no-repeat -
离屏 Canvas:使用离屏 Canvas 创建程序化图案,无需外部图片
-
加载时机:确保图片加载完成后再创建图案
-
变换影响:图案受当前变换矩阵影响
-
描边与填充:图案可同时用于 fillStyle 和 strokeStyle
下一教程将介绍 Canvas 阴影效果。
本文涉及AI创作
内容由AI创作,请仔细甄别