1. Canvas简介

1.1 什么是Canvas

HTML5 Canvas是一个HTML元素,提供了一个通过JavaScript进行2D绘图的画布。它是一个基于像素的绘图API,允许开发者创建动态图形、动画、游戏和数据可视化应用。

<canvas id="myCanvas" width="800" height="600"></canvas>

1.2 Canvas的特点

  • 基于像素的绘图:直接操作像素数据
  • 即时模式:绘制后无法直接修改已绘制的内容
  • 高性能:硬件加速支持
  • 跨平台:所有现代浏览器都支持
  • 灵活性:可以绘制任意形状和效果

1.3 Canvas vs SVG

特性 Canvas SVG
绘图方式 基于像素(位图) 基于矢量
DOM集成 单个元素 每个图形都是DOM元素
交互性 需要手动实现 内置事件支持
性能 适合复杂动画 适合静态图形
可缩放性 像素化 无损缩放

2. 环境搭建

2.1 基础HTML结构

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Canvas教程</title>
    <style>
        canvas {
            border: 1px solid #ccc;
            display: block;
            margin: 20px auto;
        }
        body {
            font-family: Arial, sans-serif;
            background-color: #f5f5f5;
        }
    </style>
</head>
<body>
    <h1>Canvas绘图示例</h1>
    <canvas id="canvas" width="800" height="600"></canvas>
    <script src="script.js"></script>
</body>
</html>

2.2 获取Canvas上下文

// 获取canvas元素
const canvas = document.getElementById('canvas');

// 获取2D渲染上下文
const ctx = canvas.getContext('2d');

// 检查浏览器支持
if (!ctx) {
    console.error('浏览器不支持Canvas');
}

2.3 Canvas坐标系统

Canvas使用左上角为原点(0,0)的坐标系统: - X轴:从左到右递增 - Y轴:从上到下递增

// 坐标系统示例
ctx.fillStyle = 'red';
ctx.fillRect(0, 0, 50, 50);     // 左上角
ctx.fillRect(750, 0, 50, 50);   // 右上角
ctx.fillRect(0, 550, 50, 50);   // 左下角
ctx.fillRect(750, 550, 50, 50); // 右下角

3. 开发工具与调试

3.1 推荐的开发工具

  1. 代码编辑器

    • Visual Studio Code
    • WebStorm
    • Sublime Text
  2. 浏览器开发者工具

    • Chrome DevTools
    • Firefox Developer Tools
    • Safari Web Inspector
  3. 在线工具

    • CodePen
    • JSFiddle
    • JSBin

3.2 调试技巧

// 1. 使用console.log调试
function drawCircle(x, y, radius) {
    console.log(`绘制圆形: x=${x}, y=${y}, radius=${radius}`);
    ctx.beginPath();
    ctx.arc(x, y, radius, 0, Math.PI * 2);
    ctx.fill();
}

// 2. 绘制辅助线
function drawGrid(step = 50) {
    ctx.strokeStyle = '#e0e0e0';
    ctx.lineWidth = 1;
    
    // 垂直线
    for (let x = 0; x <= canvas.width; x += step) {
        ctx.beginPath();
        ctx.moveTo(x, 0);
        ctx.lineTo(x, canvas.height);
        ctx.stroke();
    }
    
    // 水平线
    for (let y = 0; y <= canvas.height; y += step) {
        ctx.beginPath();
        ctx.moveTo(0, y);
        ctx.lineTo(canvas.width, y);
        ctx.stroke();
    }
}

// 3. 显示坐标信息
canvas.addEventListener('mousemove', (e) => {
    const rect = canvas.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const y = e.clientY - rect.top;
    console.log(`鼠标坐标: (${x}, ${y})`);
});

4. 第一个Canvas程序

4.1 Hello Canvas

// 获取canvas和上下文
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

// 设置背景色
ctx.fillStyle = '#f0f0f0';
ctx.fillRect(0, 0, canvas.width, canvas.height);

// 绘制文本
ctx.fillStyle = '#333';
ctx.font = '48px Arial';
ctx.textAlign = 'center';
ctx.fillText('Hello Canvas!', canvas.width / 2, canvas.height / 2);

// 绘制装饰性图形
ctx.strokeStyle = '#007acc';
ctx.lineWidth = 3;
ctx.strokeRect(50, 50, canvas.width - 100, canvas.height - 100);

4.2 基础图形绘制

// 清除画布
function clearCanvas() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
}

// 绘制矩形
function drawRectangles() {
    // 填充矩形
    ctx.fillStyle = 'red';
    ctx.fillRect(50, 50, 100, 80);
    
    // 描边矩形
    ctx.strokeStyle = 'blue';
    ctx.lineWidth = 2;
    ctx.strokeRect(200, 50, 100, 80);
    
    // 清除矩形区域
    ctx.clearRect(75, 75, 50, 30);
}

// 绘制圆形
function drawCircles() {
    // 填充圆
    ctx.fillStyle = 'green';
    ctx.beginPath();
    ctx.arc(400, 90, 40, 0, Math.PI * 2);
    ctx.fill();
    
    // 描边圆
    ctx.strokeStyle = 'purple';
    ctx.lineWidth = 3;
    ctx.beginPath();
    ctx.arc(550, 90, 40, 0, Math.PI * 2);
    ctx.stroke();
}

// 绘制线条
function drawLines() {
    ctx.strokeStyle = 'orange';
    ctx.lineWidth = 4;
    ctx.beginPath();
    ctx.moveTo(50, 200);
    ctx.lineTo(200, 250);
    ctx.lineTo(350, 200);
    ctx.stroke();
}

// 执行绘制
clearCanvas();
drawRectangles();
drawCircles();
drawLines();

5. Canvas属性与方法概览

5.1 Canvas元素属性

// 画布尺寸
console.log('宽度:', canvas.width);
console.log('高度:', canvas.height);

// 设置画布尺寸
canvas.width = 1200;
canvas.height = 800;

// 获取画布数据URL
const dataURL = canvas.toDataURL('image/png');
console.log('画布数据:', dataURL);

5.2 上下文基础方法

// 状态保存与恢复
ctx.save();    // 保存当前状态
ctx.restore(); // 恢复之前保存的状态

// 变换方法
ctx.translate(x, y);           // 平移
ctx.rotate(angle);             // 旋转
ctx.scale(scaleX, scaleY);     // 缩放
ctx.transform(a, b, c, d, e, f); // 变换矩阵

// 路径方法
ctx.beginPath();  // 开始新路径
ctx.closePath();  // 闭合路径
ctx.moveTo(x, y); // 移动到指定点
ctx.lineTo(x, y); // 画线到指定点

// 绘制方法
ctx.fill();   // 填充
ctx.stroke(); // 描边
ctx.clip();   // 裁剪

6. 常见问题与解决方案

6.1 模糊问题

// 问题:Canvas在高DPI屏幕上显示模糊
// 解决方案:设备像素比适配
function setupHighDPI(canvas) {
    const ctx = canvas.getContext('2d');
    const devicePixelRatio = window.devicePixelRatio || 1;
    
    // 设置实际尺寸
    const rect = canvas.getBoundingClientRect();
    canvas.width = rect.width * devicePixelRatio;
    canvas.height = rect.height * devicePixelRatio;
    
    // 缩放上下文
    ctx.scale(devicePixelRatio, devicePixelRatio);
    
    // 设置CSS尺寸
    canvas.style.width = rect.width + 'px';
    canvas.style.height = rect.height + 'px';
}

6.2 性能优化基础

// 1. 避免频繁的状态改变
function efficientDrawing() {
    // 批量设置相同样式的图形
    ctx.fillStyle = 'red';
    for (let i = 0; i < 100; i++) {
        ctx.fillRect(i * 10, 100, 8, 8);
    }
}

// 2. 使用离屏Canvas
function createOffscreenCanvas() {
    const offscreen = document.createElement('canvas');
    offscreen.width = 200;
    offscreen.height = 200;
    const offCtx = offscreen.getContext('2d');
    
    // 在离屏canvas上绘制复杂图形
    offCtx.fillStyle = 'blue';
    offCtx.fillRect(0, 0, 200, 200);
    
    // 将离屏canvas绘制到主canvas
    ctx.drawImage(offscreen, 100, 100);
}

7. 小结

本章介绍了Canvas的基础概念和环境搭建:

  1. Canvas基础:了解了Canvas的特点和应用场景
  2. 环境搭建:学会了如何创建Canvas元素和获取绘图上下文
  3. 坐标系统:掌握了Canvas的坐标系统
  4. 开发工具:了解了常用的开发和调试工具
  5. 第一个程序:创建了简单的Canvas绘图示例
  6. 常见问题:学习了模糊问题和性能优化的基础知识

下一章我们将深入学习Canvas的基本绘图API,包括矩形、圆形、线条等基础图形的绘制方法。

8. 练习题

  1. 创建一个800x600的Canvas,绘制一个居中的”Hello World”文本
  2. 绘制一个简单的房子图形(矩形+三角形屋顶)
  3. 实现一个鼠标跟随的小圆点效果
  4. 创建一个网格背景的Canvas画布
  5. 实现Canvas的高DPI适配