
从0到1:先把Canvas的“地基”打牢
想画好Canvas,第一步不是学怎么画圆,而是先把“画布”和“画笔”搞明白——这俩是所有操作的基础,我之前跳过这步直接画,结果折腾了俩小时没出结果,后来才发现是漏了最关键的“拿画笔”步骤。
你得在HTML里“搭个画布”:用标签,比如
。注意!width和height一定要写在标签里,别用CSS设——我之前犯过傻,用CSS把画布设成400×300,结果画的圆变成椭圆,查了MDN文档(https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/canvasnofollow)才知道:CSS会拉伸画布的“像素格子”,而标签里的width/height是原始尺寸,就像你在A4纸上画画,别把纸揉皱了再画。
要“拿画笔”——用JavaScript获取“2D上下文”(也就是2D的绘图环境)。代码很简单:const ctx = document.getElementById('myCanvas').getContext('2d');
。这里的ctx
就是你的“画笔”,之后所有的画直线、画圆都是用它来操作。我第一次帮朋友做动画时,漏了这行代码,结果ctx.fillRect()
写了半天没反应,还以为是浏览器坏了,现在想起来都觉得好笑。
再强调个小细节:每次画新图形前,最好用beginPath()
——这就像你画完一幅画,换张新纸再画,不然之前的路径会和新路径混在一起,比如你先画了个红圆,没写beginPath()
就画蓝方,结果蓝方会带着红边,我之前就犯过这错,把客户要的“清新图标”画成了“花脸”。
从简单到复杂:一步步画出能“拿得出手”的图形
等你把地基打牢,就能开始画“像样”的图形了——我把这个过程分成三步,跟着走保证不迷路。
第一步:先画最基础的形状,搞定“基本功”
新手先从直线、矩形、圆开始,这些是所有复杂图形的“积木”。
moveTo(x1,y1)
(笔移到起点)和lineTo(x2,y2)
(笔拉到终点),最后用stroke()
(描边)或者fill()
(填充)。比如画一条从(50,50)到(350,50)的横线,代码是:ctx.beginPath(); ctx.moveTo(50,50); ctx.lineTo(350,50); ctx.strokeStyle = 'blue'; ctx.stroke();
。我之前画直线总忘加stroke()
,结果“笔”动了但没痕迹,后来才明白:moveTo
和lineTo
是“规划路线”,stroke
是“实际下笔”。 fillRect(x,y,width,height)
(填充矩形)和strokeRect(x,y,width,height)
(描边矩形)。比如画一个红色填充的100×100矩形,代码是:ctx.fillStyle = 'red'; ctx.fillRect(150,100,100,100);
。注意fillStyle
要写在fillRect
前面,不然颜色不会生效——我之前总把顺序搞反,画了个“默认黑色”的矩形,还以为颜色代码错了。 arc(x,y,r,startAngle,endAngle,anticlockwise)
。参数里的“角”是弧度制,比如画一个完整的圆,startAngle
是0,endAngle
是2Math.PI
(也就是360度)。我之前总记不住弧度和角度的换算,后来用“偷懒法”:直接用Math.PI
代替180度,比如画半圆就用Math.PI
当结束角,再也没算错过。 给你个“偷懒表格”,我把常用方法整理成了“傻瓜版”,直接抄就能用:
方法名 | 作用 | 基础参数 | 我的“偷懒”技巧 |
---|---|---|---|
fillRect() | 画填充矩形 | x,y,宽,高 | 先设fillStyle,再画 |
arc() | 画圆/圆弧 | x,y,半径,起始角,结束角,是否逆时针 | 用2Math.PI画整圆,不用算弧度 |
lineTo() | 画直线 | 终点x,y | 先moveTo起点,再lineTo |
第二步:进阶!用路径画复杂图形(比如五角星)
等你会画基础形状,就能用“路径(Path)”画复杂图形了——比如五角星、爱心,这些都是用moveTo
和lineTo
连出来的。我第一次画五角星时,查了坐标公式:五角星的顶点坐标是(rMath.cos(angle), rMath.sin(angle)),其中angle是每个顶点的角度(比如第一个顶点在0度,第二个在72度,因为360/5=72)。
给你个“能直接复制”的五角星代码:
ctx.beginPath();
const r = 100; // 五角星半径
const x0 = 200; // 中心x坐标
const y0 = 150; // 中心y坐标
for (let i = 0; i < 5; i++) {
const angle = (i 2 Math.PI) / 5
Math.PI / 2; // 调整到12点方向开始
const x = x0 + r Math.cos(angle);
const y = y0 + r Math.sin(angle);
if (i === 0) {
ctx.moveTo(x, y); // 第一个点用moveTo
} else {
ctx.lineTo(x, y); // 后面的点用lineTo
}
}
ctx.closePath(); // 闭合路径
ctx.fillStyle = 'orange';
ctx.fill(); // 填充颜色
我第一次写这段代码时,把angle
的起始值写错了,结果五角星“倒着”,后来把
加上,才让顶点对准12点方向——你要是画的时候方向不对,调这个数值就行。
第三步:加特效!让图形“活”起来
光画对形状还不够,加渐变和阴影能让图形更生动——我帮电商客户做产品图时,就用这俩技巧把“普通的产品图标”变成了“有质感的卖点图”。
javascript
const gradient = ctx.createLinearGradient(0, 0, 400, 0); // 从左到右渐变
gradient.addColorStop(0, ‘blue’); // 起点颜色
gradient.addColorStop(1, ‘pink’); // 终点颜色
ctx.fillStyle = gradient;
ctx.fillRect(50, 50, 300, 100);
我之前调渐变方向时,总搞混createLinearGradient的参数,后来记“前两个是起点坐标,后两个是终点坐标”,比如从下到上渐变就是(200, 300, 200, 0),这样就不会错了。
(阴影颜色)、
shadowBlur(模糊程度)、
shadowOffsetX/Y(阴影偏移量)。比如给圆加个“软阴影”:
javascript
ctx.shadowColor = ‘rgba(0,0,0,0.3)’;
ctx.shadowBlur = 10;
ctx.shadowOffsetX = 5;
ctx.shadowOffsetY = 5;
ctx.beginPath();
ctx.arc(200, 150, 80, 0, 2*Math.PI);
ctx.fillStyle = ‘yellow’;
ctx.fill();
注意!阴影会增加渲染负担,别给太多图形加——我之前给一个有10个图形的动画加阴影,结果页面卡成“幻灯片”,后来只给主图形加,才变流畅。
现在你按这些步骤走,应该能画出第一个“拿得出手”的Canvas图形了——我当初学的时候,用了3天画出一个旋转的五角星,朋友看到都说“你居然会写代码画这个?”。其实真没那么难,关键是“多练+踩坑”——你要是画的时候遇到问题,比如图形不显示、颜色不对,先检查这几点:有没有getContext?有没有stroke/fill?是不是漏了beginPath?
对了,如果你按这些方法画了第一个图形,欢迎在评论区发张截图——我帮你看看有没有可以优化的小细节,比如渐变方向能不能调得更自然,或者阴影的模糊度是不是刚好~
为什么用CSS设置Canvas尺寸后,画的图形会变形?
因为Canvas标签里的width/height是它的“原始像素尺寸”,就像你在A4纸上画画,纸本身的大小是固定的;但用CSS设置尺寸,相当于把这张纸拉伸或压缩,比如你把400×300的Canvas用CSS设成800×600,像素格子会被“拉大”,画的圆就会变成椭圆。我之前就犯过这错,查了MDN文档才搞明白,现在都直接在标签里写width和height。
为什么我写了画图形的代码,却看不到任何效果?
先检查两个关键点:第一,有没有用JavaScript获取“2D上下文”?就是那句const ctx = document.getElementById(‘myCanvas’).getContext(‘2d’);,这步是“拿画笔”,没拿画笔自然画不了;第二,有没有加stroke()或fill()?比如你用了fillRect但没写fill(),或者lineTo后没写stroke(),相当于“规划了路线但没下笔”,我第一次帮朋友做动画时就漏了这两步,折腾半天没反应。
画多个图形时,为什么之前的颜色会蹭到新图形上?
因为你没写beginPath()!这就像你画完一幅画,没换纸就接着画下一幅,之前的“路径”会和新路径混在一起。比如你先画了个红圆,没写beginPath()就画蓝方,蓝方的边会带着红颜色——我之前给客户画图标时就犯过这错,把“清新图标”画成了“花脸”,后来每次画新图形前都加beginPath(),就再也没乱过。
怎么调整线性渐变的方向?比如想做从下到上的渐变?
线性渐变的方向是由createLinearGradient的四个参数决定的,前两个是“渐变起点”的坐标,后两个是“渐变终点”的坐标。比如你想从下到上渐变,就把起点设成画布下方(比如x=200,y=300),终点设成画布上方(x=200,y=0),代码就是createLinearGradient(200, 300, 200, 0);如果想从左到右,就用(0,0,400,0)——我之前总搞混参数,后来记“起点到终点的连线就是渐变方向”,就再也没调错过。
给图形加阴影后页面变卡,有什么解决办法吗?
阴影会增加浏览器的渲染负担,就像你画水彩画时,每加一层阴影都要等干,加太多肯定慢。我之前给一个有10个图形的动画加了阴影,结果页面卡成“幻灯片”,后来改成只给主图形(比如核心图标)加阴影,次要图形不加,页面就流畅了。 你优先给最显眼的图形加阴影,别贪多。