javascript的canvas是什么?如何用它绘制图形?

来源:草根站长作者:松松建站头衔:草根站长
导读:本期聚焦于松松建站创作的《javascript的canvas是什么?如何用它绘制图形?》,敬请观看详情。刚接触前端开发,经常听到Canvas这个词,它到底是什么?与SVG有何区别?又该如何用JavaScript在页面上画出想要的图形?本文从Canvas的核心概念讲起,深入解释画布坐标系与渲染上下文的工作方式,然后通过多个实际可运行的代码示例,逐一展示矩形、圆形、直线、曲线、文字和图像的绘制方法。同时也会涉及画布尺寸设置的常见误区、绘图状态的保存与恢复、性能优化等实用技巧。读完这篇文章,你会对Canvas有完整的认识,能够独立绘制出所需的图形,为后续制作动画、游戏或数据可视化打下扎实基础。

Canvas是HTML5中一个极为重要的图形绘制元素,它允许开发者通过JavaScript在网页上动态生成像素级图形。无论是绘制简单的矩形、圆形,还是实现复杂的动画效果,Canvas都能胜任。理解Canvas的工作原理,是掌握前端图形开发、数据可视化和网页游戏制作的基础。

javascript的canvas是什么?如何用它绘制图形?

Canvas是什么?它和SVG有什么不同?

Canvas由HTML5新增的<canvas>元素提供,它就像一块固定在页面上的透明画布。但画布本身并没有绘图能力,真正负责绘制的是基于JavaScript的Canvas API。通过调用getContext()方法,开发者可以获得一个绘图上下文对象,随后利用该对象提供的各种方法,在画布上逐像素地绘制图形、文字、图像等。

要理解Canvas的价值,可以对比SVG。SVG是一种基于XML的矢量图形描述语言,每个图形都是独立的DOM节点,可以被浏览器单独渲染、绑定事件和修改样式。而Canvas绘制的图形一旦呈现,就会变成画布上的像素,不再保留独立的节点结构。这意味着Canvas很难对绘制后的单个图形做事件监听,但换来的是极高的绘制性能。对于需要频繁重绘的动画、游戏画面,Canvas是更合适的选择;对于需要交互的图标、流程图,SVG则更灵活。

举一个直观的例子:要绘制一万个圆点,SVG会生成一万个DOM节点,页面操作和渲染都会变得迟缓;而Canvas只通过循环调用arc()fill(),在内存中完成绘制,性能高下立判。这也是Canvas在数据可视化、图像处理等场景中得到广泛应用的根本原因。

绘图基础:获取上下文与理解坐标系

在Canvas上绘图前,必须获取绘图上下文。使用document.getElementById()拿到<canvas>元素,然后调用getContext()方法。最常用的参数是'2d',表示得到一个二维绘图上下文。下面是最基础的一段代码:

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

// 设置画布实际尺寸(绘图缓冲区像素大小)
canvas.width = 600;
canvas.height = 400;

注意,<canvas>元素自带widthheight属性,它们决定了画布的实际像素尺寸。如果不设置,默认值是300×150。很多人会误用CSS去设置<canvas>的大小,但CSS属性只改变元素在页面上显示的尺寸,并不会改变画布内部的绘图分辨率。如果CSS尺寸与内部属性不一致,图形会被拉伸或压缩,导致显示模糊。因此,正确的方式是通过JavaScript显式设置widthheight

Canvas的坐标系与数学中的直角坐标系有区别。它以画布左上角为原点,x轴向右为正方向,y轴向下为正方向。相同的参数,放在Canvas中往往会产生上下颠倒的效果。例如,想让一个圆从左上角移动到右下角,y坐标需要逐渐增大,而不是减小。明确这个规则后,后续绘制图形时就不会犯方向性错误。下面这段代码展示了如何通过坐标控制图形位置:

ctx.fillStyle = '#e74c3c';
ctx.fillRect(10, 10, 100, 50);   // 左上角区域

ctx.fillStyle = '#2ecc71';
ctx.fillRect(200, 300, 80, 80);  // 右下角区域

绘制基本图形:矩形、圆形、线条

Canvas中最容易上手的是矩形绘制。它提供了fillRect()strokeRect()clearRect()三个方法,分别用于填充矩形、描边矩形和清除矩形区域。它们都接收四个参数:x坐标、y坐标、宽度、高度。下面是一个完整的示例,展示了三种方法的使用:

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

// 绘制半透明红色填充矩形
ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';
ctx.fillRect(20, 20, 150, 100);

// 绘制蓝色描边矩形
ctx.strokeStyle = '#3498db';
ctx.lineWidth = 5;
ctx.strokeRect(200, 20, 150, 100);

// 清除一块区域,形成透明空洞
ctx.clearRect(50, 40, 60, 30);

绘制圆形则要使用路径。路径是Canvas中描述图形轮廓的机制,它不像矩形那样直接绘制,而是先定义轮廓,再通过fill()stroke()实际显示。绘制圆形的方法是arc(),它接收圆心坐标、半径、起始角度、结束角度和逆时针标志。角度使用弧度制,一周等于2π。参考以下代码:

ctx.beginPath();
ctx.arc(150, 100, 50, 0, Math.PI * 2);
ctx.fillStyle = '#f39c12';
ctx.fill();

这里需要注意,绘制每个独立路径之前都要调用beginPath(),否则新路径会与上一次路径粘连到一起。如果希望给圆加边框,可以把fill()换成stroke(),甚至两者同时调用,得到既有填充又有描边的效果。

绘制直线同样依赖路径。最基本的操作是moveTo()移动画笔到起点,lineTo()画线到下一个点,最后调用stroke()将线条渲染出来。示例:

ctx.beginPath();
ctx.moveTo(40, 40);
ctx.lineTo(300, 80);
ctx.lineTo(200, 200);
ctx.strokeStyle = '#2c3e50';
ctx.lineWidth = 3;
ctx.stroke();

多段lineTo()可以组成折线或多边形。如果想让路径闭合,可以调用closePath(),它会从当前点画一条直线回到路径起点。闭合并填充后,就能得到一个实心的多边形。

曲线绘制:贝塞尔曲线与文字

贝塞尔曲线是Canvas绘制不规则图形的利器。二次贝塞尔曲线使用quadraticCurveTo(),三次贝塞尔曲线使用bezierCurveTo()。它们通过控制点弯曲路径,让曲线变得平滑自然。这是一个二次贝塞尔曲线的例子:

ctx.beginPath();
ctx.moveTo(30, 150);
ctx.quadraticCurveTo(100, 20, 250, 150);
ctx.stroke();

在这个例子中,起点是(30,150),终点是(250,150),控制点是(100,20)。曲线会从起点出发,受到控制点的吸引力而向上弯曲,再落回终点。如果想绘制更复杂的波浪形状,可以连续使用多段三次贝塞尔曲线bezierCurveTo(),通过调整两个控制点的位置形成丰富的曲线变化。

除了图形,Canvas还可以直接绘制文字。使用fillText()填充文字,strokeText()描边文字。绘制前需要设置font属性,字面语法与CSS的font属性一致,可以指定大小、字体、粗细等。示例:

ctx.font = 'bold 28px Arial';
ctx.fillStyle = '#34495e';
ctx.fillText('Hello Canvas', 30, 120);

ctx.strokeStyle = '#e74c3c';
ctx.lineWidth = 1;
ctx.strokeText('Hello Canvas', 30, 200);

文字的位置由textAligntextBaseline控制,它们分别指定水平对齐和垂直对齐方式。例如设置textAlign = 'center'后,fillText的x参数表示文字中心点的x坐标。灵活使用这些属性,可以精确控制文字在画面中的位置。

状态管理与性能优化

Canvas的绘图状态包括当前填充色、描边色、线宽、字体、变换矩阵等。如果在一个复杂绘图中反复修改这些属性,很容易导致状态混乱。为此,Canvas提供了save()restore()方法。它们将当前状态压入栈中,或从栈中弹出,实现状态的临时切换和恢复。看下面的例子:

ctx.fillStyle = '#000';
ctx.save();               // 保存当前状态(fillStyle为#000)

ctx.fillStyle = '#f00';
ctx.fillRect(0, 0, 50, 50);

ctx.restore();            // 恢复之前保存的状态
ctx.fillRect(70, 0, 50, 50);  // 此时填充色又变回#000

在动画开发中,性能优化是核心问题。一个常见误区是每一帧都使用setTimeout驱动,导致帧率不稳定。正确做法是使用requestAnimationFrame,它能让浏览器在合适的时间刷新动画,节省CPU资源并且帧率更平滑。下面是一个简单的动画示例:

var x = 0;
function draw() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.beginPath();
    ctx.arc(x, 150, 30, 0, Math.PI * 2);
    ctx.fillStyle = '#3498db';
    ctx.fill();
    x += 2;
    if (x > canvas.width + 30) x = -30;
    requestAnimationFrame(draw);
}
requestAnimationFrame(draw);

这段代码中,每一帧都先清除整个画布,再重新绘制圆,让圆从左向右移动。注意clearRect()的参数必须覆盖整个画布尺寸,否则会残留上一帧的痕迹。

针对更大规模的绘制场景,可以使用离屏Canvas技术。先创建一个不显示在页面上的<canvas>,把复杂背景预先绘制好,然后在每一帧动画中只绘制这个背景图像。这样可以大幅减少每帧需要执行的绘图指令,提升渲染效率。无论是制作游戏还是图表动态交互,这个技巧都非常实用。

总结

Canvas是Web前端中不可多得的绘图利器。从本质上讲,它就是一个由JavaScript控制像素的矩形区域。通过getContext('2d')获得上下文后,开发者可以自由绘制矩形、圆形、直线、曲线、文字等基础内容。深入理解坐标系、路径和状态管理,是掌握Canvas的三大关键。同时,在性能敏感的场景下,要合理使用requestAnimationFramesave()restore()以及离屏Canvas来优化动画。不断练习这些基础API,你会慢慢发现Canvas能做的事情远超想象,从动态图表到小游戏,它都能为你提供稳定的底层支持。

CanvasJavaScript绘制图形修改时间:2026-08-30 16:09:55

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。