5月28日 02:57

如何获取 Canvas 的 2D 上下文并使用基本绘制方法?

获取 Canvas 2D 上下文

通过 canvas.getContext('2d') 获取 2D 渲染上下文,返回 CanvasRenderingContext2D 对象:

javascript
const canvas = document.getElementById('myCanvas'); const ctx = canvas.getContext('2d');

实际开发中建议做兼容性检查:

javascript
const canvas = document.querySelector('canvas'); if (!canvas?.getContext) { throw new Error('当前浏览器不支持 Canvas'); } const ctx = canvas.getContext('2d');

注意:同一个 Canvas 元素多次调用 getContext('2d') 返回的是同一个上下文对象,不会重复创建。

基本绘制方法分类

Canvas 2D 的绘制方法可以按用途分为以下几类:

矩形绘制

矩形是 Canvas 中唯一可以直接绘制的图形,不需要路径:

方法说明
fillRect(x, y, w, h)绘制填充矩形
strokeRect(x, y, w, h)绘制矩形边框
clearRect(x, y, w, h)清除矩形区域(变为透明)

路径绘制

所有非矩形图形都需要通过路径来绘制:

javascript
ctx.beginPath(); // 开始新路径 ctx.moveTo(50, 50); // 移动画笔到起点 ctx.lineTo(200, 50); // 画直线到 (200, 50) ctx.arc(150, 100, 40, 0, Math.PI * 2); // 画圆弧 ctx.closePath(); // 闭合路径 ctx.fill(); // 填充 ctx.stroke(); // 描边

核心路径方法:

  • beginPath() — 开始新路径(不会清除已有路径)
  • moveTo(x, y) / lineTo(x, y) — 移动/画直线
  • arc(x, y, r, startAngle, endAngle) — 画圆弧或圆
  • closePath() — 从当前点回到路径起点
  • fill() / stroke() — 填充或描边当前路径

样式设置

绘制前设置样式,影响后续所有绘制操作:

javascript
ctx.fillStyle = '#ff6600'; // 填充颜色 ctx.strokeStyle = 'rgba(0,0,255,0.8)'; // 描边颜色 ctx.lineWidth = 3; // 线宽 ctx.lineCap = 'round'; // 线帽样式:butt | round | square ctx.lineJoin = 'miter'; // 连接样式:miter | round | bevel

文本绘制

javascript
ctx.font = '24px sans-serif'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText('Hello Canvas', 100, 100); // 填充文本 ctx.strokeText('Hello Canvas', 100, 100); // 描边文本

配合 measureText() 可以精确计算文本宽度:

javascript
const metrics = ctx.measureText('Hello'); console.log(metrics.width); // 文本像素宽度

图像绘制

drawImage() 支持三种调用方式:

javascript
// 基础:原尺寸绘制 ctx.drawImage(img, dx, dy); // 缩放:指定目标尺寸 ctx.drawImage(img, dx, dy, dWidth, dHeight); // 裁剪:从源图裁剪区域绘制到目标区域 ctx.drawImage(img, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);

状态保存与恢复

这是面试高频考点。Canvas 通过栈结构管理绘制状态:

javascript
ctx.save(); // 将当前状态(样式、变换等)压入栈 // ... 修改样式、变换 ... ctx.restore(); // 从栈中弹出并恢复最近一次 save 的状态

典型场景:绘制多个不同样式的图形时,用 save/restore 避免样式互相污染。

一个完整示例

把上面的方法组合起来,绘制一个带标题的彩色柱状图:

javascript
const canvas = document.getElementById('chart'); const ctx = canvas.getContext('2d'); const data = [ { label: 'A', value: 120, color: '#ff6600' }, { label: 'B', value: 80, color: '#0066ff' }, { label: 'C', value: 150, color: '#00cc66' }, ]; const barWidth = 60; const gap = 30; const baseY = 250; data.forEach((item, i) => { const x = 40 + i * (barWidth + gap); const height = item.value; // 绘制柱子 ctx.fillStyle = item.color; ctx.fillRect(x, baseY - height, barWidth, height); // 绘制标签 ctx.save(); ctx.fillStyle = '#333'; ctx.font = '14px sans-serif'; ctx.textAlign = 'center'; ctx.fillText(item.label, x + barWidth / 2, baseY + 20); ctx.fillText(String(item.value), x + barWidth / 2, baseY - height - 8); ctx.restore(); });

常见追问

Q:Canvas 和 SVG 的区别是什么?

Canvas 是像素级绘制,适合高频重绘场景(游戏、图表动画);SVG 是矢量图形,通过 DOM 操作,适合交互式静态图形。Canvas 绘制后无法单独操作某个图形元素,SVG 可以。

Q:如何实现 Canvas 动画?

核心思路是清空画布 + 重绘。用 clearRect 清除上一帧,再绘制新帧,配合 requestAnimationFrame 控制帧率。需要避免在每帧中创建对象,减少 GC 压力。

Q:Canvas 绘制模糊怎么解决?

这是高 DPI 屏幕的常见问题。需要将 Canvas 的实际像素尺寸设为 CSS 尺寸的 devicePixelRatio 倍,再用 ctx.scale(dpr, dpr) 缩放上下文。

标签:Canvas