尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

Canvas 完全指南:从基础绘图到高性能动画

Canvas 完全指南:从基础绘图到高性能动画
📅 发布时间:2026/7/6 8:53:52

在网页上绘制图形、创建动画、实现图像处理——这些需求在传统的 Web 开发中一直存在,但直到 HTML5 带来了<canvas>元素,才真正让浏览器拥有了“画布”能力。Canvas 是一个位图绘图 API,通过 JavaScript 在网页上绘制 2D 图形、图像和动画,是游戏开发、数据可视化、图像编辑、动态图表等场景的核心技术。

本文将从零开始,系统讲解 Canvas 的核心 API、绘图原理、动画机制以及性能优化技巧,带你从入门到精通。


一、Canvas 是什么?

1.1 定义与定位

Canvas 是 HTML5 引入的一个用于动态绘制图形的元素,它本身只是一个“容器”,真正的绘图工作通过 JavaScript 调用其上下文(Context)API 来完成。与 SVG 不同,Canvas 是位图(像素)级别的绘图,适合频繁更新和复杂渲染的场景。

1.2 Canvas vs SVG

对比维度

Canvas

SVG

图形类型

位图(像素级)

矢量图(保留对象)

性能

大量图形时性能好

大量图形时 DOM 节点多,性能下降

交互性

需手动计算点击位置

原生支持事件绑定

放大

会模糊

不失真

适用场景

游戏、动画、图像处理

图表、图标、静态图形

一句话选择:需要频繁重绘和大规模图形用 Canvas;需要交互和缩放用 SVG。


二、快速上手:第一个 Canvas 程序

2.1 基本结构

<!DOCTYPE html> <html> <head> <style> /* 可选:给画布加边框以便看清区域 */ canvas { border: 1px solid #ccc; } </style> </head> <body> <!-- 1. 在 HTML 中放置 canvas 元素 --> <canvas id="myCanvas" width="600" height="400"></canvas> <script> // 2. 获取画布元素 const canvas = document.getElementById('myCanvas'); // 3. 获取绘图上下文(2D) const ctx = canvas.getContext('2d'); // 4. 开始绘图 ctx.fillStyle = 'skyblue'; ctx.fillRect(50, 50, 200, 100); ctx.fillStyle = 'orange'; ctx.fillRect(300, 50, 150, 150); </script> </body> </html>

2.2 核心三要素

  1. <canvas>元素:HTML 中的画布容器,需设置width和height(注意:CSS 尺寸会缩放画布,而width/height属性定义的是绘图分辨率)。
  2. getContext('2d'):获取 2D 绘图上下文,所有绘图操作都通过它完成。
  3. 绘图 API:如fillRect、strokeRect、fillStyle等。

⚠️关键提示:<canvas>的width和height属性与 CSS 尺寸是两回事。CSS 拉伸画布会导致图像模糊,建议始终用属性设置尺寸,CSS 只控制布局。


三、坐标系与基础形状

Canvas 的坐标系原点(0, 0)位于左上角,x轴向右为正,y轴向下为正。

3.1 矩形

// 填充矩形 ctx.fillStyle = '#ff0000'; ctx.fillRect(10, 10, 100, 50); // (x, y, width, height) // 描边矩形 ctx.strokeStyle = '#00ff00'; ctx.lineWidth = 3; ctx.strokeRect(130, 10, 100, 50); // 清除矩形区域(恢复为透明) ctx.clearRect(20, 20, 80, 30);

3.2 路径绘制

Canvas 中大多数复杂图形都通过路径(Path)绘制:

javascript

ctx.beginPath(); // 开始路径 ctx.moveTo(50, 50); // 移动笔触到起点 ctx.lineTo(150, 50); // 画线到 (150, 50) ctx.lineTo(100, 120); // 画线到 (100, 120) ctx.closePath(); // 闭合路径(回到起点) ctx.fillStyle = 'purple'; ctx.fill(); // 填充 ctx.strokeStyle = 'black'; ctx.lineWidth = 2; ctx.stroke(); // 描边

3.3 圆形与弧线

ctx.beginPath(); // arc(x, y, radius, startAngle, endAngle, counterclockwise) ctx.arc(200, 150, 80, 0, Math.PI * 2); // 整圆 ctx.fillStyle = 'gold'; ctx.fill(); ctx.stroke(); // 半圆弧 ctx.beginPath(); ctx.arc(400, 150, 80, 0, Math.PI); ctx.stroke();

四、样式与状态管理

4.1 常用样式属性

属性

说明

示例

fillStyle

填充颜色/渐变/图案

'#ff0000'

,'rgba(255,0,0,0.5)'

strokeStyle

描边颜色

同上

lineWidth

线条宽度(px)

3

lineCap

线条端点样式

'round'

,'square'

lineJoin

线条拐角样式

'round'

,'bevel'

globalAlpha

全局透明度(0~1)

0.5

shadowColor

阴影颜色

'rgba(0,0,0,0.3)'

shadowBlur

阴影模糊程度

10

4.2 状态栈:save() 与 restore()

ctx.fillStyle = 'red'; ctx.save(); // 保存当前状态(红色) ctx.fillStyle = 'blue'; // 修改为蓝色 ctx.fillRect(10, 10, 50, 50); ctx.restore(); // 恢复到红色 ctx.fillRect(70, 10, 50, 50); // 红色矩形

使用场景:在绘制复杂图形时,频繁使用save()和restore()避免样式污染。

4.3 渐变与图案

// 线性渐变 const gradient = ctx.createLinearGradient(0, 0, 200, 0); gradient.addColorStop(0, 'red'); gradient.addColorStop(0.5, 'yellow'); gradient.addColorStop(1, 'blue'); ctx.fillStyle = gradient; ctx.fillRect(10, 10, 200, 100); // 径向渐变 const radial = ctx.createRadialGradient(300, 60, 10, 300, 60, 80); radial.addColorStop(0, 'white'); radial.addColorStop(1, 'darkblue'); ctx.fillStyle = radial; ctx.beginPath(); ctx.arc(300, 60, 80, 0, Math.PI * 2); ctx.fill(); // 图案填充 const img = new Image(); img.src = 'pattern.png'; img.onload = function() { const pattern = ctx.createPattern(img, 'repeat'); ctx.fillStyle = pattern; ctx.fillRect(0, 150, 600, 100); };

五、文本绘制

ctx.font = 'bold 30px Arial'; ctx.fillStyle = '#333'; ctx.textAlign = 'center'; // 'left', 'center', 'right' ctx.textBaseline = 'middle'; // 'top', 'middle', 'bottom' ctx.fillText('Hello Canvas', 300, 200); ctx.strokeStyle = '#ff0000'; ctx.lineWidth = 1; ctx.strokeText('描边文字', 300, 250); // 测量文字宽度 const metrics = ctx.measureText('Hello Canvas'); console.log(metrics.width);

六、图像处理

6.1 绘制图像

const img = new Image(); img.src = 'photo.jpg'; img.onload = function() { // 绘制原图 ctx.drawImage(img, 0, 0); // 缩放绘制 ctx.drawImage(img, 200, 0, 100, 100); // 裁剪绘制 (sx, sy, sw, sh, dx, dy, dw, dh) ctx.drawImage(img, 50, 50, 100, 100, 300, 0, 100, 100); };

6.2 像素操作

// 获取像素数据 const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); const data = imageData.data; // Uint8ClampedArray [R,G,B,A, R,G,B,A, ...] // 转换为灰度图 for (let i = 0; i < data.length; i += 4) { const gray = data[i] * 0.3 + data[i+1] * 0.59 + data[i+2] * 0.11; data[i] = gray; data[i+1] = gray; data[i+2] = gray; } ctx.putImageData(imageData, 0, 0);

七、变换与坐标系操作

7.1 平移、旋转、缩放

ctx.save(); ctx.translate(300, 200); // 将原点移到 (300, 200) ctx.rotate(Math.PI / 4); // 旋转 45 度 ctx.scale(1.5, 1.5); // 放大 1.5 倍 ctx.fillStyle = 'red'; ctx.fillRect(-50, -50, 100, 100); ctx.restore();

注意:变换操作是累加的,建议在变换前save(),操作完成后restore()。

7.2 矩阵变换

ctx.setTransform(a, b, c, d, e, f); // 对应矩阵:[[a, c, e], [b, d, f], [0, 0, 1]]

八、动画基础

Canvas 动画的核心是循环重绘,通过requestAnimationFrame实现平滑动画。

8.1 基本动画循环

let x = 0; let direction = 1; function animate() { // 清除画布 ctx.clearRect(0, 0, canvas.width, canvas.height); // 更新状态 x += 2 * direction; if (x > canvas.width - 50 || x < 0) { direction *= -1; } // 绘制 ctx.fillStyle = 'blue'; ctx.fillRect(x, 150, 50, 50); // 请求下一帧 requestAnimationFrame(animate); } animate();

8.2 帧率控制与 deltaTime

let lastTime = 0; const speed = 100; // 像素/秒 function animate(timestamp) { const deltaTime = (timestamp - lastTime) / 1000; // 转为秒 lastTime = timestamp; x += speed * deltaTime; // ... 绘制 requestAnimationFrame(animate); } requestAnimationFrame(animate);

使用deltaTime确保动画在不同刷新率的设备上速度一致。


九、交互与事件

Canvas 本身不提供“点击某个圆形”的事件,需要手动计算。

9.1 鼠标点击检测

const circles = [ { x: 100, y: 150, r: 40, color: 'red' }, { x: 300, y: 150, r: 40, color: 'blue' }, ]; function drawCircles() { circles.forEach(c => { ctx.beginPath(); ctx.arc(c.x, c.y, c.r, 0, Math.PI * 2); ctx.fillStyle = c.color; ctx.fill(); }); } canvas.addEventListener('click', function(e) { const rect = canvas.getBoundingClientRect(); const mouseX = e.clientX - rect.left; const mouseY = e.clientY - rect.top; // 从后往前遍历(上层优先) for (let i = circles.length - 1; i >= 0; i--) { const c = circles[i]; const dx = mouseX - c.x; const dy = mouseY - c.y; if (dx * dx + dy * dy < c.r * c.r) { alert('点击了 ' + c.color + ' 圆'); break; } } });

提示:getBoundingClientRect()用于将鼠标坐标转换为 canvas 坐标系,需考虑 canvas 的 CSS 缩放。


十、性能优化

优化策略

说明

离屏渲染

在内存中创建不可见 Canvas 绘制复杂内容,再一次性绘制到主画布

减少绘制调用

合并在同一路径中的绘制,避免频繁beginPath()

/stroke()

使用requestAnimationFrame

取代setInterval

/setTimeout

避免getImageData

频繁调用

除非必要,减少像素级操作

控制重绘区域

使用drawImage

裁剪或clearRect

局部清除

合理使用will-change

提示浏览器优化(canvas.style.willChange = 'transform'

)


十一、总结速查表

知识点

关键 API

获取上下文

canvas.getContext('2d')

矩形

fillRect(x,y,w,h)

,strokeRect()

,clearRect()

路径

beginPath()

,moveTo()

,lineTo()

,closePath()

,fill()

,stroke()

圆弧

arc(x,y,r,startAngle,endAngle)

样式

fillStyle

,strokeStyle

,lineWidth

,globalAlpha

,shadow*

状态

save()

,restore()

文本

fillText()

,strokeText()

,measureText()

图像

drawImage()

,getImageData()

,putImageData()

变换

translate()

,rotate()

,scale()

,setTransform()

动画

requestAnimationFrame(callback)


一句话记忆:Canvas 是浏览器的像素级画布——通过 JavaScript 获取 2D 上下文,用路径、样式和变换绘制图形,用requestAnimationFrame驱动动画,用手动坐标计算实现交互,用离屏渲染和减少绘制调用优化性能。

Canvas 是现代 Web 前端开发的核心技能之一。从本章的示例出发,尝试实现一个“画板”应用(支持鼠标绘制、颜色切换、清空),再挑战一个简单的“弹球”游戏,你会逐步感受到 Canvas 的强大。动画和游戏开发才是它真正的用武之地,祝你创作愉快。

相关新闻

  • 构建企业级AI Agent:从概念到实践,打通数据孤岛实现智能自动化
  • 百度网盘解析工具终极指南:三步实现全速下载的免费方案
  • uos-network-exporter社区贡献指南:如何参与开源项目开发与维护

最新新闻

  • Python Docstring 三种主流风格实战指南
  • 工业缺陷检测实战包:1800张VOC格式图+可训练Faster R-CNN模型
  • Docker容器启动原理与实战:从镜像到活服务的完整链路
  • Web安全实战:XSS与CSRF攻击原理、防御策略与靶场演练
  • Python地方技术社区实战指南:从参会到贡献的跃迁路径
  • JMeter接口自动化测试实战:从核心概念到性能压测

日新闻

  • AI智能体安全防护框架AgentGuard:从原理到实战部署指南
  • KMX63与PIC18F26K40硬件组合及低功耗设计实践
  • 基于YOLO13改进的门体检测模型:C3k2模块与PoolingFormer技术解析

周新闻

  • 基于YOLOv12的番茄成熟度智能检测系统开发
  • 终极RimWorld模组管理指南:用RimSort告别模组冲突烦恼
  • AI Agent框架开发:从理论到实践的完整指南

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号