Canvas 竟能这么玩?从画张图到做动画,入门到上瘾只需这篇!

你有没有想过,网页上那些炫酷的游戏、动态数据图表、甚至在线涂鸦板,是怎么实现的?其实它们背后都藏着一个 "神级工具"------HTML5 的<canvas>标签。这个看似简单的画布,能让你用代码画出任何东西,从静态图片到流畅动画,甚至交互式游戏,全凭想象力。

今天我们就从最基础的 "画张图" 开始,一步步解锁 Canvas 的神奇功能。看完这篇,你不仅能看懂示例代码,还能亲手写出会动的效果,感受用代码 "作画" 的乐趣!

认识 Canvas:网页里的 "电子画板"

<canvas>就像一块网页上的 "电子画板",你可以用 JavaScript 在上面绘制图形、文字、图片,甚至做动画。它的核心优势是直接操作像素,比 CSS 绘图更灵活,能实现复杂的视觉效果。

最基础的用法:创建画布

先看一个最简单的示例(对应你提供的第一个代码):在 Canvas 上画一张图片。

html 复制代码
<!-- 1. 创建画布标签 -->
<canvas id="demo"></canvas>

<script>
  // 2. 获取画布元素
  let canvas = document.getElementById('demo');
  // 3. 获取"画笔"(2D渲染上下文,所有绘图操作都靠它)
  let context = canvas.getContext('2d');

  // 4. 加载图片并绘制到画布
  const img = new Image();
  img.src = '图片地址';
  // 注意:图片加载是异步的,必须等加载完成再绘制
  img.onload = function() {
    // 1. 设置 Canvas 尺寸为图片实际尺寸
    canvas.width = img.naturalWidth;
    canvas.height = img.naturalHeight;
    // 绘制图片:参数分别是"图片对象、起点x、起点y"
    context.drawImage(img, 0, 0);
  };
</script>

关键知识点

  • <canvas>默认尺寸是 300x150 像素,如需调整大小,用canvas.widthcanvas.height(不要用 CSS,会拉伸变形);
  • getContext('2d')是核心:返回一个 "2D 绘图上下文" 对象(相当于画笔),所有绘图方法(画矩形、文字、图片等)都定义在这个对象上。

进阶:用代码 "画" 出各种形状

Canvas 的 "画笔"(context)提供了丰富的绘图方法,能画矩形、圆形、文字等。我们结合示例,看看如何画矩形和动态文字。

类别 方法 描述 参数示例
矩形 fillRect(x, y, width, height) 绘制填充矩形 (10, 10, 100, 50)
strokeRect(x, y, width, height) 绘制矩形边框 (10, 70, 100, 50)
clearRect(x, y, width, height) 清除矩形区域(透明) (20, 20, 80, 30)
路径 beginPath() 开始新路径 -
closePath() 闭合路径(起点终点连线) -
moveTo(x, y) 移动画笔到点 (50, 50)
lineTo(x, y) 添加直线到点 (150, 50)
arc(x, y, r, sAngle, eAngle, anticlockwise) 绘制圆弧/圆 x,y:圆心; r:半径; s/eAngle:起止弧度; anticlockwise:逆时针 (100, 75, 50, 0, Math.PI*2)
arcTo(x1, y1, x2, y2, r) 通过控制点绘制圆弧 (150, 20, 150, 70, 50)
quadraticCurveTo(cpx, cpy, x, y) 二次贝塞尔曲线 cpx,cpy:控制点; x,y:终点 (75, 25, 100, 50)
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) 三次贝塞尔曲线 cp1*, cp2*: 控制点 (70, 20, 130, 20, 100, 50)
rect(x, y, width, height) 添加矩形路径(需fill()stroke()渲染) (10, 10, 100, 50)
fill() / stroke() 填充/描边路径 -
clip() 将路径设为裁剪区域 -
文本 fillText(text, x, y [, maxWidth]) 填充文本 ("Hello", 50, 50, 200)
strokeText(text, x, y [, maxWidth]) 描边文本 ("World", 50, 80)
图像 drawImage(image, dx, dy [, dWidth, dHeight]) 绘制图像 dx,dy: 目标位置; dWidth,dHeight: 缩放尺寸 (img, 10, 10, 100, 100)
drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight) 切片绘制图像 sx,sy: 源图像切片位置; sWidth,sHeight: 切片尺寸 (img, 0,0,50,50, 10,10,100,100)
像素操作 getImageData(sx, sy, sw, sh) 获取像素数据对象 (0, 0, canvas.width, canvas.height)
putImageData(data, dx, dy) 写入像素数据 (imgData, 0, 0)

(1)画矩形:3 个核心方法

javascript 复制代码
// 获取画笔
let ctx = canvas.getContext('2d');

// 1. 填充矩形:fillRect(x起点, y起点, 宽度, 高度)
ctx.fillStyle = 'red'; // 设置填充颜色
ctx.fillRect(0, 0, 300, 150); // 画一个红色矩形(铺满画布)

// 2. 清空矩形(相当于"橡皮擦"):clearRect(x起点, y起点, 宽度, 高度)
ctx.clearRect(20, 20, 100, 50); // 擦除一块矩形区域,露出画布背景

效果:红色背景上出现一个 "透明方块",就像在红纸上挖了个洞。

(2)画文字:动态更新的文本

要实现 "动态数字" 效果,核心是用fillText方法画文字,并通过循环更新内容:

javascript 复制代码
// 初始化一个计数器
let dis = 0;

// 定义动画函数
function animation() {
  // 用requestAnimationFrame实现流畅动画(浏览器会自动优化帧率,通常60帧/秒)
  requestAnimationFrame(function() {
    // 每次动画前先清空画布(避免文字叠加)
    ctx.clearRect(0, 0, 300, 150);

    // 1. 动态设置文字颜色(用rgba实现渐变色)
    ctx.fillStyle = `rgba(${dis}, 0, 0)`; // 红色分量随dis变化

    // 2. 设置字体样式
    ctx.font = '50px Verdana';

    // 3. 画文字:fillText(内容, x起点, y起点)
    ctx.fillText(dis, 110, 90); // 显示当前计数器值

    // 4. 更新计数器(超过225重置,避免颜色过亮)
    dis++;
    if (dis >= 225) dis = 0;

    // 循环调用,实现持续动画
    animation();
  });
}

// 启动动画
animation();

动画原理

  1. requestAnimationFrame:告诉浏览器 "下一次重绘前执行回调",比setInterval更流畅(不会掉帧);
  2. 每次动画先clearRect清空画布,再重绘文字,就像 "每帧换一张画",视觉上形成动态效果。

Canvas 动画的核心逻辑:"帧" 的概念

你可能会好奇:为什么这些代码能产生 "动" 的效果?其实动画的本质是 "快速切换静态画面"。

比如电影每秒播放 24 帧(24 张静态图片),人眼就会觉得画面是连续的。Canvas 动画也是如此:

  • requestAnimationFrame每秒执行 60 次回调(60 帧 / 秒);
  • 每次回调都修改绘图参数(位置、颜色、大小等),然后重新绘制;
  • 人眼无法分辨快速切换的画面,就会产生 "动画" 的错觉。

Canvas 能做什么?这些场景超惊艳

掌握了基础绘图和动画后,你可以用 Canvas 实现更酷的功能:

(1)数据可视化:动态图表

比如用 Canvas 画折线图、饼图,支持实时更新数据(比静态图表更灵活)。

(2)网页游戏:交互场景

很多轻量级游戏(如贪吃蛇、俄罗斯方块)都是用 Canvas 开发的,通过监听鼠标 / 键盘事件,实时更新画面。

(3)图片处理:滤镜效果

结合像素操作 API,给图片加滤镜(灰度、模糊、反转色等),比如:

javascript 复制代码
// 获取图片像素数据
let imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
let data = imageData.data;

// 遍历像素,转为灰度图(每个像素的RGB值取平均值)
for (let i = 0; i < data.length; i += 4) {
  let avg = (data[i] + data[i+1] + data[i+2]) / 3;
  data[i] = avg; // R
  data[i+1] = avg; // G
  data[i+2] = avg; // B
}

// 把处理后的像素画回画布
ctx.putImageData(imageData, 0, 0);

常见坑:这些错误别再犯

  1. 用 CSS 设置 Canvas 尺寸 :会导致画面拉伸变形,正确做法是用canvas.width = 600; canvas.height = 400;
  2. 没等图片加载完成就绘制 :图片是异步加载的,必须在onload回调里调用drawImage
  3. 忘记清空画布 :动画会出现 "拖影",每次重绘前用clearRect清空;
  4. 忽略坐标系:Canvas 的原点(0,0)在左上角,y 轴向下为正(和数学坐标系相反)。
相关推荐
puffysang33几秒前
Android paging3实现本地缓存加载数据
前端
拉罐7 分钟前
React Query:彻底解决 React 数据获取难题的强大利器
前端
一涯37 分钟前
用python写一个抓取股市关键词的程序
前端·python
情绪的稳定剂_精神的锚43 分钟前
git提交前修改文件校验
前端
Moonbit1 小时前
MoonBit 作者寄语 2025 级清华深圳新生
前端·后端·程序员
前端的阶梯1 小时前
开发一个支持支付功能的微信小程序的注意事项,含泪送上
前端·后端·全栈
Juchecar1 小时前
Node.js package.json 配置详解 + TypeScript + ES Module 集成指南
javascript
李明卫杭州1 小时前
深入理解CSS变量(Custom Properties)
前端·javascript
CoderLiu1 小时前
AI提示词工程优化指南:8个技巧,释放大语言模型的全部潜力
前端·人工智能·ai编程
咕噜分发企业签名APP加固彭于晏1 小时前
腾讯元器的优点是什么
前端·后端