杰瑞科技汇

HTML5 Canvas怎么学?入门到精通难不难?

HTML5 Canvas 完整教程

目录

  1. 什么是 Canvas?
  2. 入门:创建你的第一个 Canvas
  3. 核心概念:绘图上下文
  4. 绘制基本图形
  5. 样式与颜色
  6. 变换
  7. 动画基础
  8. 高级主题
  9. 实战案例:粒子系统
  10. 总结与资源

什么是 Canvas?

<canvas> 是 HTML5 引入的一个强大的元素,它提供了一个可以通过 JavaScript 进行绘制的位图画布,你可以把它想象成一块在浏览器中的“画布”,你拥有全套的“画笔”和“颜料”(即 JavaScript API),可以在上面绘制任何你想要的东西,从简单的图形到复杂的游戏、数据可视化和图像处理。

HTML5 Canvas怎么学?入门到精通难不难?-图1
(图片来源网络,侵删)

核心特点:

  • 基于像素:Canvas 是基于像素的,这意味着当你放大图形时,它会变得模糊(位图特性)。
  • 即时模式:Canvas 没有持久的对象,你绘制一个矩形,它就变成了像素,如果你想移动它,你必须清除画布,然后在新的位置重新绘制整个场景。
  • 性能卓越:非常适合绘制大量图形、动画和游戏,因为 GPU 可以对它进行硬件加速。

入门:创建你的第一个 Canvas

使用 Canvas 非常简单,只需要在 HTML 中放置一个 <canvas>

HTML 结构

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">Canvas 教程</title>
    <style>
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
            background-color: #f0f0f0;
        }
        canvas {
            border: 1px solid black;
        }
    </style>
</head>
<body>
    <canvas id="myCanvas" width="500" height="400"></canvas>
    <script src="main.js"></script>
</body>
</html>
  • <canvas> 元素有两个重要的属性:widthheight,它们定义了画布的分辨率(以像素为单位)。注意:不要用 CSS 来设置画布的宽高,CSS 只会拉伸画布,导致内容模糊。

JavaScript 绘制 创建一个 main.js 文件,开始绘制。

// 1. 获取 canvas 元素
const canvas = document.getElementById('myCanvas');
// 2. 获取 2D 绘图上下文
const ctx = canvas.getContext('2d');
// 3. 在画布上绘制一个矩形
ctx.fillStyle = 'green'; // 设置填充颜色
ctx.fillRect(10, 10, 150, 100); // 绘制一个矩形 (x, y, width, height)
// 4. 绘制一个描边矩形
ctx.strokeStyle = 'blue';
ctx.lineWidth = 5;
ctx.strokeRect(200, 10, 150, 100);
// 5. 绘制一条线
ctx.beginPath();
ctx.moveTo(10, 150); // 移动到起点
ctx.lineTo(400, 150); // 画一条线到终点
ctx.strokeStyle = 'red';
ctx.lineWidth = 2;
ctx.stroke();

核心概念:绘图上下文

getContext('2d') 是 Canvas 的核心,它返回一个 CanvasRenderingContext2D 对象,这个对象包含了所有用于在画布上绘制的 API 和属性,你所有的绘图操作都是通过这个 ctx 对象来完成的。

HTML5 Canvas怎么学?入门到精通难不难?-图2
(图片来源网络,侵删)

绘制基本图形

矩形

Canvas 提供了三种直接绘制矩形的方法:

  • ctx.fillRect(x, y, width, height): 绘制一个填充的矩形。
  • ctx.strokeRect(x, y, width, height): 绘制一个描边的矩形。
  • ctx.clearRect(x, y, width, height): 清除指定矩形区域内的像素,使其变为透明。

路径 - 绘制复杂图形的关键

路径是绘制自定义形状的基础,它像一个“绘图计划”,告诉 Canvas 你想画什么,然后你决定是描边它还是填充它。

基本步骤:

  1. ctx.beginPath(): 开始一条新路径。非常重要!这会重置当前的路径。
  2. ctx.moveTo(x, y): 将画笔移动到一个指定的点,但不画线。
  3. ctx.lineTo(x, y): 从当前点画一条直线到指定的新点。
  4. ctx.closePath(): 自动从当前点画一条线回到路径的起点。
  5. ctx.stroke(): 描边(绘制)当前路径。
  6. ctx.fill(): 填充当前路径。

示例:绘制一个三角形

HTML5 Canvas怎么学?入门到精通难不难?-图3
(图片来源网络,侵删)
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(50, 50);   // 移动到点 A
ctx.lineTo(150, 50);  // 画线到点 B
ctx.lineTo(100, 150); // 画线到点 C
ctx.closePath();       // 闭合路径 (从 C 回到 A)
ctx.fillStyle = 'purple';
ctx.fill();

圆形和弧线

使用 arc() 方法来绘制弧线或圆形。 ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise)

  • x, y: 圆心坐标。
  • radius: 半径。
  • startAngle, endAngle: 起始和结束角度(弧度制,不是角度!)。0 弧度是 3点钟方向,Math.PI * 2 是一个完整的圆。
  • anticlockwise: true 表示逆时针,false 表示顺时针(默认)。

示例:绘制一个圆

const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
ctx.beginPath();
// 圆心(250, 200), 半径50, 从0到Math.PI*2(一个完整的圆)
ctx.arc(250, 200, 50, 0, Math.PI * 2); 
ctx.fillStyle = 'orange';
ctx.fill();

文本

Canvas 也可以绘制文本。

  • ctx.fillText(text, x, y, [maxWidth]): 绘制填充文本。
  • ctx.strokeText(text, x, y, [maxWidth]): 绘制描边文本。

文本样式属性:

  • ctx.font: 设置字体,格式与 CSS font 相同 (e.g., "20px Arial")。
  • ctx.fillStyle / ctx.strokeStyle: 设置文本颜色。
  • ctx.textAlign: 文本对齐方式 (left, center, right)。
  • ctx.textBaseline: 文本基线 (top, middle, bottom, alphabetic)。

示例:

const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
ctx.font = '30px Arial';
ctx.fillStyle = 'black';
ctx.textAlign = 'center';
ctx.fillText('Hello Canvas!', canvas.width / 2, canvas.height / 2);

图像

你可以将图像(如 <img> 标签或图片 URL)绘制到画布上。 ctx.drawImage(image, x, y, [width, height])

示例:

const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
const img = new Image();
img.src = 'path/to/your/image.png';
// 等待图片加载完成
img.onload = function() {
    ctx.drawImage(img, 50, 50, 200, 150); // 绘制图片,并指定宽高
};

样式与颜色

填充与描边

几乎所有形状都有两个版本:填充和描边。

  • ctx.fill(): 使用 ctx.fillStyle 设置的颜色填充路径。
  • ctx.stroke(): 使用 ctx.strokeStyle 设置的颜色和 ctx.lineWidth 设置的宽度来描边路径。

颜色、透明度和渐变

  • 颜色:
    • ctx.fillStyle = 'red'; // 颜色名
    • ctx.fillStyle = '#FF0000'; // 十六进制
    • ctx.fillStyle = 'rgb(255, 0, 0)'; // RGB
    • ctx.fillStyle = 'rgba(255, 0, 0, 0.5)'; // RGBA (最后一个值是透明度 0-1)
  • 渐变:
    • createLinearGradient(x0, y0, x1, y1): 创建线性渐变。
    • createRadialGradient(x0, y0, r0, x1, y1, r1): 创建径向渐变。
    • gradient.addColorStop(position, color): 添加颜色断点。position 在 0 到 1 之间。

示例:线性渐变

const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
const gradient = ctx.createLinearGradient(0, 0, canvas.width, 0);
gradient.addColorStop(0, 'blue');
gradient.addColorStop(1, 'green');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, canvas.width, canvas.height);

阴影

  • ctx.shadowColor = 'rgba(0, 0, 0, 0.5)'; // 阴影颜色
  • ctx.shadowBlur = 10; // 阴影模糊程度
  • ctx.shadowOffsetX = 5; // 阴影 X 轴偏移
  • ctx.shadowOffsetY = 5; // 阴影 Y 轴偏移

线条样式

  • ctx.lineWidth = 5; // 线条宽度
  • ctx.lineCap = 'round'; // 线条末端样式 (butt, round, square)
  • ctx.lineJoin = 'miter'; // 线条连接处样式 (miter, round, bevel)
  • ctx.setLineDash([5, 15]); // 设置虚线,数组 [实线长度, 空白长度]

变换

变换允许你移动、旋转和缩放整个画布坐标系。重要提示:变换会影响之后的所有绘制操作。

平移

ctx.translate(x, y): 将画布的原点 (0, 0) 移动到 (x, y)

旋转

ctx.rotate(angle): 围绕当前原点旋转画布。angle 是弧度。

缩放

ctx.scale(x, y): 缩放画布。xy 是缩放因子。

使用变换的最佳实践:保存和恢复状态 变换会累积,这通常不是你想要的,为了避免混乱,可以使用 save()restore()

  • ctx.save(): 保存当前画布的状态(包括所有样式、变换等)到一个栈中。
  • ctx.restore(): 从栈中恢复最近保存的状态。

示例:绘制一个旋转的矩形

const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
// 绘制一个原始矩形
ctx.fillStyle = 'blue';
ctx.fillRect(50, 50, 100, 100);
// 保存当前状态
ctx.save();
// 应用变换
ctx.translate(150, 150); // 将原点移动到矩形中心
ctx.rotate(Math.PI / 4); // 旋转45度 (Math.PI / 4 弧度)
// 绘制一个变换后的矩形
// 因为坐标系已经移动和旋转,所以坐标是相对于新原点的
ctx.fillStyle = 'red';
ctx.fillRect(-50, -50, 100, 100); // 矩形中心在(0,0)
// 恢复之前保存的状态
ctx.restore();

动画基础

Canvas 动画的原理是:清除 -> 更新 -> 绘制 -> 重复

使用 requestAnimationFrame

requestAnimationFrame 是现代浏览器提供的用于制作动画的 API,它比 setIntervalsetTimeout 更高效,因为它会浏览器的重绘周期同步,从而节省资源并使动画更流畅。

语法: requestAnimationFrame(callback) callback 是一个函数,浏览器在下一次重绘之前会调用它。

动画循环示例

目标: 让一个球从左边弹跳到右边。

const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
// 1. 定义对象状态
let x = 0;
let y = canvas.height / 2;
let dx = 2; // x轴速度
let radius = 20;
function drawBall() {
    ctx.beginPath();
    ctx.arc(x, y, radius, 0, Math.PI * 2);
    ctx.fillStyle = '#0095DD';
    ctx.fill();
    ctx.closePath();
}
function update() {
    // 2. 更新状态
    x += dx;
    // 边界检测
    if (x + radius > canvas.width || x - radius < 0) {
        dx = -dx; // 反转方向
    }
}
function animate() {
    // 3. 清除画布
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    // 4. 更新和绘制
    update();
    drawBall();
    // 5. 请求下一帧
    requestAnimationFrame(animate);
}
// 启动动画
animate();

高级主题

像素操作

你可以直接获取和修改画布上的像素数据。

  • ctx.getImageData(x, y, width, height): 获取一个矩形区域的像素数据,返回一个 ImageData 对象。
  • ctx.putImageData(imageData, x, y): 将 ImageData 对象放回画布。
  • ImageData.data: 一个一维数组,包含 [R, G, B, A, R, G, B, A, ...] 值。

示例:灰度滤镜

// ... (获取 canvas 和 ctx)
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
    // 获取 RGB 值
    const r = data[i];
    const g = data[i + 1];
    const b = data[i + 2];
    // 计算灰度值 (加权平均)
    const avg = 0.299 * r + 0.587 * g + 0.114 * b;
    // 将 RGB 都设置为灰度值
    data[i] = avg;     // R
    data[i + 1] = avg; // G
    data[i + 2] = avg; // B
}
// 将处理后的数据放回画布
ctx.putImageData(imageData, 0, 0);

合成与剪辑

  • 合成:控制新绘制的图形如何与画布上已有的内容混合,通过 globalCompositeOperation 属性设置,source-over (默认), multiply, screen 等。
  • 剪辑:定义一个“剪切区域”,之后所有的绘制操作都只在这个区域内可见,通过 clip() 方法实现,它需要一个路径作为剪切区域。

实战案例:粒子系统

粒子系统是 Canvas 动画中的一个经典应用,我们将创建一个简单的粒子爆炸效果。

HTML: (与之前相同) JavaScript (particles.js):

const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
// 1. 粒子类
class Particle {
    constructor(x, y) {
        this.x = x;
        this.y = y;
        this.size = Math.random() * 5 + 1;
        this.speedX = Math.random() * 3 - 1.5; // -1.5 到 1.5
        this.speedY = Math.random() * 3 - 1.5;
        this.color = `hsl(${Math.random() * 360}, 50%, 50%)`;
    }
    update() {
        this.x += this.speedX;
        this.y += this.speedY;
        // 粒子逐渐变小
        if (this.size > 0.2) this.size -= 0.05;
    }
    draw() {
        ctx.fillStyle = this.color;
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
        ctx.fill();
    }
}
// 2. 粒子数组
let particlesArray = [];
// 3. 鼠标移动事件监听
let mouseX = 0;
let mouseY = 0;
canvas.addEventListener('mousemove', (event) => {
    const rect = canvas.getBoundingClientRect();
    mouseX = event.clientX - rect.left;
    mouseY = event.clientY - rect.top;
    // 在鼠标位置创建新粒子
    for (let i = 0; i < 5; i++) {
        particlesArray.push(new Particle(mouseX, mouseY));
    }
});
// 4. 动画循环
function animate() {
    // 使用半透明的黑色填充画布,实现拖尾效果
    ctx.fillStyle = 'rgba(0, 0, 0, 0.05)';
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    // 更新和绘制所有粒子
    for (let i = 0; i < particlesArray.length; i++) {
        particlesArray[i].update();
        particlesArray[i].draw();
        // 移除太小的粒子
        if (particlesArray[i].size <= 0.2) {
            particlesArray.splice(i, 1);
            i--;
        }
    }
    requestAnimationFrame(animate);
}
// 启动动画
animate();

效果说明:

  • 移动鼠标,会在鼠标位置产生彩色粒子。
  • 粒子会向随机方向散开。
  • 粒子会逐渐变小并消失。
  • 由于每次清除画布时使用了 rgba(0, 0, 0, 0.05),而不是完全不透明的黑色,所以会产生粒子运动的拖尾效果。

总结与资源

HTML5 Canvas 是一个极其强大和灵活的工具,掌握它的关键在于:

  1. 理解上下文:所有操作都通过 ctx 对象。
  2. 掌握路径:这是绘制自定义形状的基础。
  3. 熟悉变换:学会使用 save()restore() 来管理状态。
  4. 拥抱动画循环requestAnimationFrame 是你的好朋友。
  5. 多加练习:从简单的图形开始,逐步挑战更复杂的动画和交互。

推荐资源:

  • MDN Web Docs - Canvas: 最权威、最全面的文档,几乎涵盖了所有 API 和细节。
  • Canvas API Tutorial by MDN: 一个结构良好的交互式教程。
  • The Nature of Code: Daniel Shiffman 的经典书籍,教你如何使用代码(包括 Canvas)来模拟自然现象,有免费在线版本。
  • Creative, Coding, Design: 许多艺术家和开发者分享的 Canvas 项目和教程,能给你带来很多灵感。

希望这份教程能帮助你顺利入门并精通 HTML5 Canvas!祝你编码愉快!

分享:
扫描分享到社交APP
上一篇
下一篇