Canvas学习笔记(一)

什么是 Canvas

Canvas 是 HTML5 中新增的一种标签,表示一个画布,只是图形容器,绘制功能必须使用js来实现。

js 复制代码
<!doctype html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>基础的HTML5页面</title> 
</head>
<body>
	<canvas id="canvas">
            这里是canvas标签,当你的浏览器不支持canvas时,会显示这行文字
	</canvas>
</body> 

</html>

打开后会是一个完全空白的画面,因为canvas本意就是一块画布,画布在html5中是透明的,不可见的。


绘制前的准备

获取 Canvas 对象:
js 复制代码
const canvas = document.getElementById('canvas');
获取画笔
js 复制代码
const context = canvas.getContext(contextType, contextAttributes?);
const context = canvas.getContext('2d');
const ctx = canvas.getContext('2d', {
  alpha: true,          // 启用透明通道(默认就是true)
});

getContext方法用于获取 Canvas 元素的绘图上下文,来对 Canvas 元素进行绘制操作,通常是 2D 类型,用于二维绘图。第一个参数是必须传的,第二个参数代表配置上下文的行为,不同的上下文的配置属性不同。

  • 2d
属性 说明 默认值
alpha 是否包含alpha通道(透明度) true
colorSpace 指定渲染上下文的色彩空间(srgbdisplay-p3 srgb
desynchronized 是否将画布绘制周期与事件循环解耦以减少延迟 false
willReadFrequently 是否频繁读取像素(用于优化getImageData()性能) false
  • webgl
属性 作用 说明
alpha 是否包含alpha通道 和2D一样
antialias 是否开启抗锯齿 让图形边缘更平滑
depth 是否包含深度缓冲区 用于3D场景的深度检测
failIfMajorPerformanceCaveat 性能低时是否创建上下文 true:性能差时失败
powerPreference GPU电源偏好 default/high-performance/low-power
premultipliedAlpha 是否预混合alpha 用于图像合成
preserveDrawingBuffer 是否保存缓冲区 true:可以多次读取
stencil 是否包含模版缓冲区 用于复杂遮罩效果

小结一下:准备工作就分为三步:

  1. 布置画布:通过添加 <canvas>标签,添加canvas元素
  2. 获取画布:通过 <canvas>标签的id,获得canvas对象
  3. 获得画笔:通过canvas对象的 getContext("2d") 方法,获得2D环境

绘制线段:

在Canvas中,是基于状态的绘制,所以前面几步都是在确定状态,直到最后一步才会具体绘制。

绘画步骤和现实中画画差不多,可以分为四步:

1. 首先移动画笔至绘画的起始位置
js 复制代码
context.moveTo(x, y)
// 将笔画移至 x, y 这个位置,canvas中是以画布的左上角为坐标原点,x轴的正方向向右,y轴的正方向向下
2. 确定第一笔的停止点
js 复制代码
context.lineTo(x, y)
// 从上一个笔的停止点,移动至x,y这里
3. 规划好路线后,选择画笔(粗细,颜色,线条等)

因为 Canvas 是基于状态的,所以我们在选择画笔粗细和颜色的同时,其实也是选择了线条的粗细和颜色。

属性 说明 默认值 示例
context.lineWidth 线条粗细(宽度) ,单位是像素 1.0 ctx.lineWidth = 5;
context.strokeStyle 描边颜色/样式(可为颜色、渐变、图案) #000000(黑色) ctx.strokeStyle = "#AA394C";``ctx.strokeStyle = "red";``ctx.strokeStyle = gradient;
context.lineCap 线段末端样式 "butt" "butt"(平头) "round"(圆头) "square"(方头)
context.lineJoin 两条线相交处的连接样式 "miter" "miter"(尖角) "round"(圆角) "bevel"(斜角)
context.miterLimit 尖角(miter)的最大长度限制(防止过长尖角) 10 ctx.miterLimit = 5;
4. 进行绘制

确定绘制有两种方法:

js 复制代码
context.fill() // 填充
context.stroke() // 描边
5. 画一个线条!
js 复制代码
<body>
    <canvas id="myCanvas" style="border: 1px solid black;"></canvas>
    <script>
        const canvas = document.getElementById('myCanvas');
        const ctx = canvas.getContext('2d');
        
        ctx.moveTo(0, 0);
        ctx.lineTo(100, 100);

        ctx.lineWidth = 10;
        ctx.strokeStyle = 'red';

        ctx.stroke();
    </script>
</body>

一条红色的线条就画好了。但是我们现在只给 Canvas 设置了边框,那它的宽高是从哪来的呢?

这是浏览器默认给 Canvas 分配的尺寸 300x150 像素的画布。如果我们要自己设置 Canvas 宽高的话有两种方法

  1. 通过标签内部设置
js 复制代码
 <canvas id="myCanvas" style="border: 1px solid black;" width = "500" height = "500"></canvas>
  1. 通过 JS 设置
js 复制代码
const canvas = document.getElementById('myCanvas');

canvas.width = 500;
canvas.height = 500;

这两种方式设置的宽高是等效的

这里有一个特别需要注意的点:我们设置的是画布的物理宽高,也就是 Canvas 元素的真实宽高,并不是通过 Css 设置的样式宽高,如果我们通过 Css 设置了 Canvas 的宽高,效果其实是在物理宽高的基础上进行了等比的缩小或者拉伸

js 复制代码
<canvas id="myCanvas" 
    style="border: 1px solid black; width: 100px; height: 100px;" width="500" height="500">
</canvas>

线条组成图形

绘制折线

当我们学会绘制线条后,就可以用线条来组成图形了,方法其实很简单,就是复用上文用过的lineTo() 方法即可:

js 复制代码
    ctx.moveTo(0, 0);
    ctx.lineTo(50, 100);
    ctx.lineTo(100, 0);

    ctx.lineWidth = 10;
    ctx.strokeStyle = 'red';

    ctx.stroke();
绘制多条折线

如果需要绘制多条不连接的线条,只需在绘制完一次后,再重新移动画笔,重新绘制一次即可

js 复制代码
        ctx.moveTo(0, 0);
        ctx.lineTo(50, 100);
        ctx.lineTo(100, 0);
        ctx.lineWidth = 10;
        ctx.strokeStyle = 'red';
        ctx.stroke();

        ctx.moveTo(100, 0);
        ctx.lineTo(150, 100);
        ctx.lineTo(200, 0);
        ctx.lineWidth = 10;
        ctx.strokeStyle = 'blue';
        ctx.stroke(); 

诶?这是不是很奇怪,明明是先红色再蓝色,为什么就全变为蓝色了呢?是因为上文说过的 Canvas 是基于状态绘制的。我们每次使用stroke() 时,它都会把之前设置的状态再次绘制一遍,第一次stroke时会绘制一条红色折线,第二次stroke时,会再次重新绘制之前那条红色的折线,但是画笔已经变为蓝色的了,所以画出的折线全是蓝色的

为了解决这个问题,我们需要在每次重新绘制时加上beginPath(),这个 API 代表下次绘制的起始处为beginPath()之后的代码。

js 复制代码
        ctx.moveTo(0, 0);
        ctx.lineTo(50, 100);
        ctx.lineTo(100, 0);
        ctx.lineWidth = 10;
        ctx.strokeStyle = 'red';
        ctx.stroke();
        
        ctx.beginPath(); // 重新定义起始位置
        ctx.moveTo(100, 0);
        ctx.lineTo(150, 100);
        ctx.lineTo(200, 0);
        ctx.lineWidth = 10;
        ctx.strokeStyle = 'blue';
        ctx.stroke(); 

绘制矩形

我们先使用绘制线条的方式绘制一个矩形

js 复制代码
        // 绘制一个矩形
        ctx.beginPath();
        ctx.moveTo(50,50);
        ctx.lineTo(100,50);
        ctx.lineTo(100,100);
        ctx.lineTo(50,100);
        ctx.lineTo(50,50);

        ctx.lineWidth = 5;
        ctx.strokeStyle = "black";

        ctx.stroke();   

会发现此时最后一笔画时有一个小缺口,这种情况是因为我们设置了lineWidth导致的,如果是默认笔触为1的话是不会有问题的,但是如果笔触越大,线条越宽,这个小缺口就会越明显。此时需要使用closePath()闭合图形。

js 复制代码
        // 绘制一个矩形
        ctx.beginPath();
        ctx.moveTo(50,50);
        ctx.lineTo(100,50);
        ctx.lineTo(100,100);
        ctx.lineTo(50,100);
        // ctx.lineTo(50,50); // 最后一笔可以不画
        ctx.closePath();

所以我们在绘制图形时需要使用beginPath()closePath()包裹起来。

给矩形上色

上文中有提过绘制的两种方法分别是stroke()fill(),我们需要使用fill()方法给矩形上色。和使用stroke前相同,我们需要先给它设置好属性。

js 复制代码
        ctx.beginPath();
        ctx.moveTo(50,50);
        ctx.lineTo(100,50);
        ctx.lineTo(100,100);
        ctx.lineTo(50,100);
        ctx.closePath();

        ctx.lineWidth = 5;
        ctx.strokeStyle = "black";

        ctx.fillStyle = "red";

        ctx.fill();
        ctx.stroke();   
使用rect()方法绘制矩形

由于矩形是常用的图形,所以 Canvas API 封装好了一个定义矩形位置信息的方法,这个方法接受四个参数,分别表示矩形的起点坐标和宽高。

js 复制代码
        ctx.rect(x,y,width,height);

        ctx.beginPath();
        ctx.rect(50,50,100,100);
        
        ctx.lineWidth = 5;
        ctx.strokeStyle = "black";
        ctx.fillStyle = "red";

        ctx.fill();
        ctx.stroke();

今天 Canvas 的学习就到这啦

相关推荐
崔庆才丨静觅19 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby606120 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了20 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅20 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅21 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅21 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment21 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅21 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊21 小时前
jwt介绍
前端
爱敲代码的小鱼1 天前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax